Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -388,6 +388,14 @@ score that must not be ranked against an equity's.
Restart the engine after installing either; a newly installed plugin is not live
in a session that is already running.

Updating an installed plugin is its own step, and upgrading moshcode does not do
it: an engine only pulls a new copy when the *plugin's* own version moves.

```sh
claude plugin update stocks@moshcode
claude plugin update crypto@moshcode
```

Plugin commands are namespaced `/<plugin>:<command>` — always, not only when two
plugins collide — so it is `/stocks:signals AAPL`, and a bare `/signals` answers
`Unknown command`. Typing `/` and picking from the menu inserts the right form.
Expand Down
2 changes: 1 addition & 1 deletion plugins/crypto/.claude-plugin/plugin.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"$schema": "https://anthropic.com/claude-code/plugin.schema.json",
"name": "crypto",
"description": "Crypto market data slash commands backed by advis0r.com: live prices, technical scores, order books, OHLCV history and sparklines across Alpaca's US crypto venue.",
"version": "0.1.0",
"version": "0.2.0",
"author": {
"name": "moshcoder",
"url": "https://moshcode.sh"
Expand Down
2 changes: 1 addition & 1 deletion plugins/stocks/.claude-plugin/plugin.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"$schema": "https://anthropic.com/claude-code/plugin.schema.json",
"name": "stocks",
"description": "Equity research slash commands backed by advis0r.com: scored reports, extracted signals, transcript search, company-name lookup, and ranked watchlists.",
"version": "0.1.0",
"version": "0.2.0",
"author": {
"name": "moshcoder",
"url": "https://moshcode.sh"
Expand Down
12 changes: 12 additions & 0 deletions src/plugins.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -39,16 +39,28 @@ export function marketplaceSource(env = process.env) {
* `example` exists because the invitation printed after an install has to be
* runnable. It used to append a hardcoded "NVDA" to whatever came first in
* `commands`, which told anyone installing the crypto plugin to try a stock.
*
* `version` mirrors each plugin's own plugin.json, and it is not decoration:
* "If set, users only receive updates when you bump this field."
* https://code.claude.com/docs/en/plugins-reference#version-management
*
* So editing a plugin's commands and shipping a moshcode release is *not*
* enough — an existing install keeps serving the old copy until this number
* moves. Both plugins sat at 0.1.0 through v0.29.2, which rewrote every command
* file. Change a plugin's contents, bump its version, in the same commit.
* A test fails when this list and the manifests disagree.
*/
export const PLUGINS = [
{
name: "stocks",
version: "0.2.0",
description: "equity research slash commands backed by advis0r.com",
commands: ["/stocks:stocks", "/stocks:signals", "/stocks:research", "/stocks:lookup", "/stocks:reports", "/stocks:discover"],
example: "/stocks:stocks NVDA",
},
{
name: "crypto",
version: "0.2.0",
description: "crypto market data slash commands backed by advis0r.com",
commands: ["/crypto:crypto", "/crypto:quote", "/crypto:book", "/crypto:bars", "/crypto:spark", "/crypto:pairs", "/crypto:coin"],
example: "/crypto:crypto BTC",
Expand Down
11 changes: 11 additions & 0 deletions test/plugins.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,17 @@ test("every plugin the marketplace lists exists, with a manifest and its command
const plugin = JSON.parse(fs.readFileSync(new URL(".claude-plugin/plugin.json", dir), "utf8"));
assert.equal(plugin.name, entry.name, `${entry.name}'s manifest disagrees with the marketplace`);

// An engine only pulls a new copy of a plugin when its own version moves —
// a moshcode release does not carry plugin edits to existing installs on its
// own. Both plugins sat at 0.1.0 through v0.29.2, which rewrote every
// command file, so this pins the catalog to the manifest that ships.
assert.match(plugin.version ?? "", /^\d+\.\d+\.\d+$/, `${entry.name} has no usable plugin.json version`);
assert.equal(
PLUGINS.find((p) => p.name === entry.name)?.version,
plugin.version,
`${entry.name}: the catalog and plugin.json disagree on the version`,
);

const catalog = PLUGINS.find((p) => p.name === entry.name);
const files = fs.readdirSync(new URL("commands/", dir)).filter((f) => f.endsWith(".md"));
// Namespaced, because that is how Claude Code invokes them. Comparing bare
Expand Down
Loading