Skip to content

Commit 0d26338

Browse files
ralyodioclaude
andauthored
fix(plugin): bump both plugins to 0.2.0 so installs actually update (#333)
Claude Code only pulls a new copy of a plugin when the plugin's own version moves: "If set, users only receive updates when you bump this field." https://code.claude.com/docs/en/plugins-reference#version-management Both plugins have sat at 0.1.0 since they were created, through every change since — including v0.29.2, which rewrote every command file to carry the namespaced names. An existing install has been serving the old copy the whole time, so the surface people were told to use is the surface they did not get. Shipping a moshcode release does not carry plugin edits; only this number does. Both go to 0.2.0. The content they describe changed; the version now says so. To stop it happening again, `version` joins the catalog next to `commands` — the thing an editor is already touching when they change a plugin — with the mechanism spelled out above it, and a test pinning the catalog to the manifest that actually ships. Verified the guard fails when the two disagree rather than merely passing today. The README now documents `claude plugin update <plugin>@moshcode`, which is the step users need and the one nothing mentioned: `moshcode upgrade` updates the CLI and leaves installed plugins exactly where they were. Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
1 parent e7a2fc0 commit 0d26338

5 files changed

Lines changed: 33 additions & 2 deletions

File tree

README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -388,6 +388,14 @@ score that must not be ranked against an equity's.
388388
Restart the engine after installing either; a newly installed plugin is not live
389389
in a session that is already running.
390390

391+
Updating an installed plugin is its own step, and upgrading moshcode does not do
392+
it: an engine only pulls a new copy when the *plugin's* own version moves.
393+
394+
```sh
395+
claude plugin update stocks@moshcode
396+
claude plugin update crypto@moshcode
397+
```
398+
391399
Plugin commands are namespaced `/<plugin>:<command>` — always, not only when two
392400
plugins collide — so it is `/stocks:signals AAPL`, and a bare `/signals` answers
393401
`Unknown command`. Typing `/` and picking from the menu inserts the right form.

plugins/crypto/.claude-plugin/plugin.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"$schema": "https://anthropic.com/claude-code/plugin.schema.json",
33
"name": "crypto",
44
"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.",
5-
"version": "0.1.0",
5+
"version": "0.2.0",
66
"author": {
77
"name": "moshcoder",
88
"url": "https://moshcode.sh"

plugins/stocks/.claude-plugin/plugin.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"$schema": "https://anthropic.com/claude-code/plugin.schema.json",
33
"name": "stocks",
44
"description": "Equity research slash commands backed by advis0r.com: scored reports, extracted signals, transcript search, company-name lookup, and ranked watchlists.",
5-
"version": "0.1.0",
5+
"version": "0.2.0",
66
"author": {
77
"name": "moshcoder",
88
"url": "https://moshcode.sh"

src/plugins.mjs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,16 +39,28 @@ export function marketplaceSource(env = process.env) {
3939
* `example` exists because the invitation printed after an install has to be
4040
* runnable. It used to append a hardcoded "NVDA" to whatever came first in
4141
* `commands`, which told anyone installing the crypto plugin to try a stock.
42+
*
43+
* `version` mirrors each plugin's own plugin.json, and it is not decoration:
44+
* "If set, users only receive updates when you bump this field."
45+
* https://code.claude.com/docs/en/plugins-reference#version-management
46+
*
47+
* So editing a plugin's commands and shipping a moshcode release is *not*
48+
* enough — an existing install keeps serving the old copy until this number
49+
* moves. Both plugins sat at 0.1.0 through v0.29.2, which rewrote every command
50+
* file. Change a plugin's contents, bump its version, in the same commit.
51+
* A test fails when this list and the manifests disagree.
4252
*/
4353
export const PLUGINS = [
4454
{
4555
name: "stocks",
56+
version: "0.2.0",
4657
description: "equity research slash commands backed by advis0r.com",
4758
commands: ["/stocks:stocks", "/stocks:signals", "/stocks:research", "/stocks:lookup", "/stocks:reports", "/stocks:discover"],
4859
example: "/stocks:stocks NVDA",
4960
},
5061
{
5162
name: "crypto",
63+
version: "0.2.0",
5264
description: "crypto market data slash commands backed by advis0r.com",
5365
commands: ["/crypto:crypto", "/crypto:quote", "/crypto:book", "/crypto:bars", "/crypto:spark", "/crypto:pairs", "/crypto:coin"],
5466
example: "/crypto:crypto BTC",

test/plugins.test.mjs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,17 @@ test("every plugin the marketplace lists exists, with a manifest and its command
143143
const plugin = JSON.parse(fs.readFileSync(new URL(".claude-plugin/plugin.json", dir), "utf8"));
144144
assert.equal(plugin.name, entry.name, `${entry.name}'s manifest disagrees with the marketplace`);
145145

146+
// An engine only pulls a new copy of a plugin when its own version moves —
147+
// a moshcode release does not carry plugin edits to existing installs on its
148+
// own. Both plugins sat at 0.1.0 through v0.29.2, which rewrote every
149+
// command file, so this pins the catalog to the manifest that ships.
150+
assert.match(plugin.version ?? "", /^\d+\.\d+\.\d+$/, `${entry.name} has no usable plugin.json version`);
151+
assert.equal(
152+
PLUGINS.find((p) => p.name === entry.name)?.version,
153+
plugin.version,
154+
`${entry.name}: the catalog and plugin.json disagree on the version`,
155+
);
156+
146157
const catalog = PLUGINS.find((p) => p.name === entry.name);
147158
const files = fs.readdirSync(new URL("commands/", dir)).filter((f) => f.endsWith(".md"));
148159
// Namespaced, because that is how Claude Code invokes them. Comparing bare

0 commit comments

Comments
 (0)