@cmodjs/core 0.2.0 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/docs/commands.md CHANGED
@@ -97,7 +97,7 @@ Releases the mod at `path` (default: the current folder) at the version in its `
97
97
  3. Checks the release with `claude plugin validate --strict`, and stops with the validator's message when it fails.
98
98
  4. Commits the release as the `release` branch, and builds the release archive from that commit.
99
99
  5. Builds the program `cli/` declares, and writes `SHA256SUMS` for every file of the release.
100
- 6. Writes `.claude-plugin/marketplace.json`, listing the archive and the cmod plugin.
100
+ 6. Writes `.claude-plugin/marketplace.json`, listing the archive and the cmod plugin. The cmod entry points at the `release` branch of `heyJordanParker/cmod`, so the mod's `"cmod"` dependency resolves in this marketplace and follows each cmod release with no new publish of the mod.
101
101
  7. Commits that file, tags `v<version>`, pushes the tag and the `release` branch, and creates the GitHub release. Its notes open with `## Breaking changes`, listing each `BREAKING CHANGE:` footer of a commit since the last `v` tag and the subject of each commit typed with `!`, such as `feat!: mod.claude replaces job.claude`, so the people who use the mod know what to change before they update. `--dry-run` prints that list.
102
102
  8. Prints the link to paste as the Repository when you submit the mod at [claude.ai/directory/manage](https://claude.ai/directory/manage), such as `https://github.com/owner/greeter/tree/release`. The portal reads the branch from the link, so the directory follows `release`.
103
103
 
@@ -113,7 +113,6 @@ It needs, and refuses to start without:
113
113
  - a `package.json` with no dependency on a `file:` or `link:` path, which no user has
114
114
  - a `"files"` list, when `package.json` has one, whose every path matches a committed file
115
115
  - a `"program"` in the `cmod` key of `package.json` that names the program `cli/` declares, when `cli/` declares one
116
- - the network, to hash the cmod plugin release it lists, unless the mod is cmod itself
117
116
  - for a real publish, a working tree with no uncommitted changes, a `v<version>` tag that does not exist yet, a `git push` to `origin` that succeeds, and the `gh` command, which creates the GitHub release
118
117
 
119
118
  `--dry-run` builds everything into a temporary folder, and pushes nothing. It writes `marketplace.json` there too, so the working tree stays as it was. It allows uncommitted changes and an existing tag, and builds from the last commit. It prints the folder that holds the release, so you can read what the directory will read.
@@ -184,7 +183,7 @@ cmod runs these itself. A person runs them to see a step's whole log, to finish
184
183
  cmod setup <plugin-root> [--events] [--consent <sha256>] [--yes]
185
184
  ```
186
185
 
187
- Downloads the program the mod's `package.json` `cmod.program` names into `~/.local/bin`, runs the mod's install step, saves its uninstall step, grants the permissions its `cmod.permissions` lists, and records the mod as set up. The consent covers the scripts, the program, the keys, and the permissions together, and an update asks again only for what changed. An unchanged mod runs nothing. `--events` prints one event per line for a program to read, and the mod's progress line in Claude Code reads them.
186
+ Downloads the program the mod's `package.json` `cmod.program` names into `~/.local/bin`, runs the mod's install step, saves its uninstall step, grants the permissions its `cmod.permissions` lists, and records the mod as set up. A mod installed from a marketplace whose automatic updates the person has not turned on or off gets them turned on, through `"autoUpdate": true` on the marketplace's `extraKnownMarketplaces` entry in Claude Code's `settings.json`, and the consent question says so. The consent covers the scripts, the program, the keys, and the permissions together, and an update asks again only for what changed. An unchanged mod runs nothing. `--events` prints one event per line for a program to read, and the mod's progress line in Claude Code reads them.
188
187
 
189
188
  ### cmod teardown
190
189
 
@@ -52,6 +52,14 @@ A mod that calls tracer lists it in its own `.claude-plugin/plugin.json`, and Cl
52
52
  "dependencies": ["cmod", "tracer"]
53
53
  ```
54
54
 
55
+ A provider that changes or removes a method breaks every mod that calls it, and with automatic updates the provider can update first. Name the versions you tested with a range, and Claude Code turns your mod off with a clear error instead of letting its calls fail one by one:
56
+
57
+ ```json
58
+ "dependencies": ["cmod", { "name": "tracer", "version": "^1.0" }]
59
+ ```
60
+
61
+ Claude Code checks the range against the `version` in the provider's `plugin.json` when it loads your mod ([Claude Code's plugin dependencies](https://code.claude.com/docs/en/plugins/dependencies)).
62
+
55
63
  Claude Code then lays tracer's types file beside the mod's own types, so the call is typed:
56
64
 
57
65
  ```ts
@@ -43,6 +43,12 @@ Before a step runs for the first time, cmod shows the person the commands, the k
43
43
 
44
44
  The mod starts only once its install step has run ([mod.md](mod.md)).
45
45
 
46
+ ## Automatic updates
47
+
48
+ Claude Code updates a plugin by itself only when its marketplace has automatic updates on, and they are off for every marketplace that is not Anthropic's. So the setup of a mod installed from a marketplace turns them on, through `"autoUpdate": true` on that marketplace's `extraKnownMarketplaces` entry in `settings.json`. The consent lists it as `Update <mod> automatically from the <marketplace> marketplace`, and a mod with nothing to consent to logs it. The setup never changes a choice the person made, in `settings.json` or with the toggle under `/plugin` Marketplaces, and leaves a linked mod alone.
49
+
50
+ Claude Code downloads an update in the background and loads it at the next launch or `/reload-plugins`. An update whose scripts, keys, or permissions changed waits for consent again, so an update never runs a new install step unasked.
51
+
46
52
  In Claude Code, the mod sets itself up through the `cmod` that PATH finds, and only through one that knows every step it has. A mod with `keys` waits for cmod 0.1.12 or later, because an older cmod skips the keys, and a mod with `permissions` waits for cmod 0.2.0 or later, because an older cmod grants none of them. While PATH finds an older one, the line above the prompt says `PATH finds cmod <version>, and <mod> needs cmod 0.1.12 or later. Run npm i -g @cmodjs/cli, or put ~/.local/bin ahead of the old cmod on PATH.` The mod sets up as soon as a new enough cmod answers, such as the one the cmod plugin installs into `~/.local/bin` at its first start.
47
53
 
48
54
  ## Steps in Claude Code
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cmodjs/core",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "description": "Build Claude Code mods: hooks, panes, permissions, checks, and an install that just works.",
5
5
  "license": "MIT",
6
6
  "type": "module",
package/records.d.ts CHANGED
@@ -64,6 +64,8 @@ export declare const settingsPagesMethod = "cmod:settingsPages";
64
64
  export declare const openPageMethod = "cmod:openPage";
65
65
  export declare const pendingStepsMethod = "cmod:pendingSteps";
66
66
  export declare const finishStepsMethod = "cmod:finishSteps";
67
+ export declare function marketplaceOf(root: string, name: string): string | undefined;
68
+ export declare function updatesToTurnOn(marketplace: string | undefined, settings: unknown, known: unknown): string | undefined;
67
69
  export declare function consentPath(store: string): string;
68
70
  export declare function parseConsent(value: unknown, path: string): Record<string, string[]>;
69
71
  export declare function oldestCmodFor(steps: Steps): string;
package/records.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"records.d.ts","sourceRoot":"","sources":["src/records.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"records.d.ts","sourceRoot":"","sources":["src/records.ts"],"names":[],"mappings":"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"}
package/records.js CHANGED
@@ -174,6 +174,19 @@ export const settingsPagesMethod = 'cmod:settingsPages';
174
174
  export const openPageMethod = 'cmod:openPage';
175
175
  export const pendingStepsMethod = 'cmod:pendingSteps';
176
176
  export const finishStepsMethod = 'cmod:finishSteps';
177
+ export function marketplaceOf(root, name) {
178
+ const installed = /\/cache\/([^/]+)\/([^/]+)\/[^/]+\/?$/.exec(root);
179
+ return installed?.[2] === name ? installed[1] : undefined;
180
+ }
181
+ export function updatesToTurnOn(marketplace, settings, known) {
182
+ if (marketplace === undefined)
183
+ return undefined;
184
+ const declared = isObject(settings) && isObject(settings['extraKnownMarketplaces']) ? settings['extraKnownMarketplaces'][marketplace] : undefined;
185
+ const fetched = isObject(known) ? known[marketplace] : undefined;
186
+ const isDecided = [declared, fetched].some((entry) => isObject(entry) && typeof entry['autoUpdate'] === 'boolean');
187
+ const hasSource = [declared, fetched].some((entry) => isObject(entry) && isObject(entry['source']));
188
+ return isDecided || !hasSource ? undefined : marketplace;
189
+ }
177
190
  export function consentPath(store) {
178
191
  return `${store}/consent.json`;
179
192
  }
@@ -9,6 +9,7 @@ export type Consent = {
9
9
  readonly uninstall: string;
10
10
  readonly keys: string;
11
11
  readonly permissions: readonly string[];
12
+ readonly updates?: string | undefined;
12
13
  };
13
14
  export type Installer = {
14
15
  draws(e: Frozen<Args<'ui.render'>>): boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"installer.d.ts","sourceRoot":"","sources":["../src/runtime/installer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,aAAa,EAAiB,MAAM,aAAa,CAAA;AAC7E,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAA;AAC3C,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,WAAW,CAAA;AACpC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAA;AAI3C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAEzC,eAAO,MAAM,eAAe,mBAAmB,CAAA;AAE/C,MAAM,MAAM,OAAO,GAAG;IACpB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,WAAW,EAAE,SAAS,MAAM,EAAE,CAAA;CACxC,CAAA;AAOD,MAAM,MAAM,SAAS,GAAG;IACtB,KAAK,CAAC,CAAC,EAAE,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,GAAG,OAAO,CAAA;IAC5C,IAAI,CAAC,CAAC,EAAE,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,GAAG,aAAa,CAAA;IACjD,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,OAAO,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;IAC3C,OAAO,CAAC,OAAO,EAAE,SAAS,CAAC,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;IAC7I,IAAI,CAAC,KAAK,SAAS,MAAM,EAAE,GAAG,EAAE,GAAG,CAAC,KAAK,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;IAC9G,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;CACvB,CAAA;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,MAAM,GAAG,SAAS,CAiI7E"}
1
+ {"version":3,"file":"installer.d.ts","sourceRoot":"","sources":["../src/runtime/installer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,aAAa,EAAiB,MAAM,aAAa,CAAA;AAC7E,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAA;AAC3C,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,WAAW,CAAA;AACpC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAA;AAI3C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAEzC,eAAO,MAAM,eAAe,mBAAmB,CAAA;AAE/C,MAAM,MAAM,OAAO,GAAG;IACpB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,WAAW,EAAE,SAAS,MAAM,EAAE,CAAA;IACvC,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CACtC,CAAA;AAOD,MAAM,MAAM,SAAS,GAAG;IACtB,KAAK,CAAC,CAAC,EAAE,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,GAAG,OAAO,CAAA;IAC5C,IAAI,CAAC,CAAC,EAAE,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,GAAG,aAAa,CAAA;IACjD,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,OAAO,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;IAC3C,OAAO,CAAC,OAAO,EAAE,SAAS,CAAC,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;IAC7I,IAAI,CAAC,KAAK,SAAS,MAAM,EAAE,GAAG,EAAE,GAAG,CAAC,KAAK,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;IAC9G,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;CACvB,CAAA;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,MAAM,GAAG,SAAS,CAsI7E"}
@@ -36,8 +36,13 @@ export function createInstaller(name, claude) {
36
36
  isOpen = false;
37
37
  page?.cancel();
38
38
  },
39
- consent({ install, uninstall, keys, permissions }) {
40
- const changes = [...(install === '' ? [] : [`Run ${install} now${uninstall === '' ? '' : `, and ${uninstall} when you remove it`}`]), ...(install === '' && uninstall !== '' ? [`Run ${uninstall} when you remove it`] : []), ...(keys === '' ? [] : [`Bind ${keys}`])];
39
+ consent({ install, uninstall, keys, permissions, updates }) {
40
+ const changes = [
41
+ ...(install === '' ? [] : [`Run ${install} now${uninstall === '' ? '' : `, and ${uninstall} when you remove it`}`]),
42
+ ...(install === '' && uninstall !== '' ? [`Run ${uninstall} when you remove it`] : []),
43
+ ...(keys === '' ? [] : [`Bind ${keys}`]),
44
+ ...(updates === undefined ? [] : [`Update ${name} automatically from the ${updates} marketplace`]),
45
+ ];
41
46
  return show((answer) => ({
42
47
  draw: () => frame(`${name} wants to:`, [
43
48
  ...(permissions.length === 0 ? [] : [Box({ flexDirection: 'column', children: permissions.map((item) => bullet(permissionWords(item))) })]),
@@ -1 +1 @@
1
- {"version":3,"file":"lifecycle.d.ts","sourceRoot":"","sources":["../src/runtime/lifecycle.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,EAA0B,aAAa,EAAyC,MAAM,aAAa,CAAA;AAC1I,OAAO,KAAK,EAAa,GAAG,EAAE,aAAa,EAAiC,MAAM,WAAW,CAAA;AAC7F,OAAO,KAAK,EAAE,OAAO,EAAgB,MAAM,eAAe,CAAA;AAC1D,OAAO,EAAgQ,KAAK,KAAK,EAAE,MAAM,eAAe,CAAA;AAGxS,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAGzC,OAAO,EAAsG,KAAK,WAAW,EAAE,MAAM,YAAY,CAAA;AAMjJ,OAAO,EAA6B,KAAK,UAAU,EAAE,MAAM,aAAa,CAAA;AAKxE,MAAM,MAAM,MAAM,GAAG;IACnB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,CAAA;IACpC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAA;IAC7B,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAA;IAC9B,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAA;IACrB,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAA;CACpC,CAAA;AAED,MAAM,MAAM,KAAK,GAAG,UAAU,GAAG,YAAY,GAAG,SAAS,GAAG,UAAU,GAAG,QAAQ,GAAG,OAAO,GAAG,QAAQ,CAAA;AAEtG,MAAM,MAAM,SAAS,CAAC,KAAK,SAAS,MAAM,IAAI;IAC5C,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAA;IACrB,QAAQ,CAAC,GAAG,EAAE,GAAG,CAAC,KAAK,CAAC,GAAG,SAAS,CAAA;IACpC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;IACzB,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAC/E,KAAK,CAAC,CAAC,SAAS,WAAW,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,UAAU,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAA;CACzG,CAAA;AAqCD,wBAAsB,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CA2BhE;AAkCD,wBAAgB,eAAe,CAAC,KAAK,SAAS,MAAM,EAAE,QAAQ,SAAS,OAAO,GAAG,OAAO,EACtF,UAAU,EAAE,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,CAAC,EAClD,iBAAiB,GAAE,MAAM,OAAoB,EAC7C,OAAO,GAAE,aAAkB,EAC3B,UAAU,UAAO,GAChB,SAAS,CAAC,KAAK,CAAC,CAmVlB"}
1
+ {"version":3,"file":"lifecycle.d.ts","sourceRoot":"","sources":["../src/runtime/lifecycle.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,EAA0B,aAAa,EAAyC,MAAM,aAAa,CAAA;AAC1I,OAAO,KAAK,EAAa,GAAG,EAAE,aAAa,EAAiC,MAAM,WAAW,CAAA;AAC7F,OAAO,KAAK,EAAE,OAAO,EAAgB,MAAM,eAAe,CAAA;AAC1D,OAAO,EAAgS,KAAK,KAAK,EAAE,MAAM,eAAe,CAAA;AAGxU,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAGzC,OAAO,EAAsG,KAAK,WAAW,EAAE,MAAM,YAAY,CAAA;AAMjJ,OAAO,EAA6B,KAAK,UAAU,EAAE,MAAM,aAAa,CAAA;AAKxE,MAAM,MAAM,MAAM,GAAG;IACnB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,CAAA;IACpC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAA;IAC7B,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAA;IAC9B,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAA;IACrB,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAA;CACpC,CAAA;AAED,MAAM,MAAM,KAAK,GAAG,UAAU,GAAG,YAAY,GAAG,SAAS,GAAG,UAAU,GAAG,QAAQ,GAAG,OAAO,GAAG,QAAQ,CAAA;AAEtG,MAAM,MAAM,SAAS,CAAC,KAAK,SAAS,MAAM,IAAI;IAC5C,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAA;IACrB,QAAQ,CAAC,GAAG,EAAE,GAAG,CAAC,KAAK,CAAC,GAAG,SAAS,CAAA;IACpC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;IACzB,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAC/E,KAAK,CAAC,CAAC,SAAS,WAAW,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,UAAU,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAA;CACzG,CAAA;AAqCD,wBAAsB,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CA2BhE;AAkCD,wBAAgB,eAAe,CAAC,KAAK,SAAS,MAAM,EAAE,QAAQ,SAAS,OAAO,GAAG,OAAO,EACtF,UAAU,EAAE,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,CAAC,EAClD,iBAAiB,GAAE,MAAM,OAAoB,EAC7C,OAAO,GAAE,aAAkB,EAC3B,UAAU,UAAO,GAChB,SAAS,CAAC,KAAK,CAAC,CA0VlB"}
@@ -1,4 +1,4 @@
1
- import { consentPath, dataFolder, finishStepsMethod, isAtLeast, oldestCmodFor, openPageMethod, parseConsent, pendingStepsMethod, parseEvent, permissionWords, readRecord, readSteps, scriptsSha256, settingsPagesMethod, storeFolder } from '../records.js';
1
+ import { consentPath, dataFolder, finishStepsMethod, isAtLeast, marketplaceOf, oldestCmodFor, openPageMethod, parseConsent, pendingStepsMethod, parseEvent, permissionWords, readRecord, readSteps, scriptsSha256, settingsPagesMethod, storeFolder, updatesToTurnOn } from '../records.js';
2
2
  import { relativePath } from '../utils/paths.js';
3
3
  import { formatExit, listed, messageOf } from '../utils/text.js';
4
4
  import { beforeDeadline } from './deadline.js';
@@ -224,6 +224,12 @@ export function createLifecycle(definition, checksPermissions = () => true, opti
224
224
  if (added.length > 0)
225
225
  runtime.claude.ui.log(`${definition.name} added ${listed(added)}.`);
226
226
  };
227
+ const updatesToShow = async () => {
228
+ const [home, configHome] = await Promise.all([claude().env.home(), claude().env.configHome()]);
229
+ const configRoot = configHome ?? `${home ?? ''}/.claude`;
230
+ const known = await claude().fs.read(`${configRoot}/plugins/known_marketplaces.json`).then((text) => JSON.parse(text), () => undefined);
231
+ return updatesToTurnOn(marketplaceOf(claude().plugin.root, claude().plugin.name), await claude().settings.read({ source: 'user' }), known);
232
+ };
227
233
  const askConsent = async (event) => {
228
234
  const name = definition.name;
229
235
  if ((await claude().session.surfaces()).length === 0) {
@@ -232,7 +238,7 @@ export function createLifecycle(definition, checksPermissions = () => true, opti
232
238
  return;
233
239
  }
234
240
  showLine().wait('Waiting for your answer');
235
- if (await installer.consent(event))
241
+ if (await installer.consent({ ...event, updates: await updatesToShow().catch(() => undefined) }))
236
242
  return install(event.sha256);
237
243
  await installer.close();
238
244
  phase = 'declined';
package/src/records.ts CHANGED
@@ -202,6 +202,20 @@ export const pendingStepsMethod = 'cmod:pendingSteps'
202
202
 
203
203
  export const finishStepsMethod = 'cmod:finishSteps'
204
204
 
205
+ export function marketplaceOf(root: string, name: string): string | undefined {
206
+ const installed = /\/cache\/([^/]+)\/([^/]+)\/[^/]+\/?$/.exec(root)
207
+ return installed?.[2] === name ? installed[1] : undefined
208
+ }
209
+
210
+ export function updatesToTurnOn(marketplace: string | undefined, settings: unknown, known: unknown): string | undefined {
211
+ if (marketplace === undefined) return undefined
212
+ const declared = isObject(settings) && isObject(settings['extraKnownMarketplaces']) ? settings['extraKnownMarketplaces'][marketplace] : undefined
213
+ const fetched = isObject(known) ? known[marketplace] : undefined
214
+ const isDecided = [declared, fetched].some((entry) => isObject(entry) && typeof entry['autoUpdate'] === 'boolean')
215
+ const hasSource = [declared, fetched].some((entry) => isObject(entry) && isObject(entry['source']))
216
+ return isDecided || !hasSource ? undefined : marketplace
217
+ }
218
+
205
219
  export function consentPath(store: string): string {
206
220
  return `${store}/consent.json`
207
221
  }
@@ -14,6 +14,7 @@ export type Consent = {
14
14
  readonly uninstall: string
15
15
  readonly keys: string
16
16
  readonly permissions: readonly string[]
17
+ readonly updates?: string | undefined
17
18
  }
18
19
 
19
20
  type Page = {
@@ -68,8 +69,13 @@ export function createInstaller(name: string, claude: () => Claude): Installer {
68
69
  isOpen = false
69
70
  page?.cancel()
70
71
  },
71
- consent({ install, uninstall, keys, permissions }) {
72
- const changes = [...(install === '' ? [] : [`Run ${install} now${uninstall === '' ? '' : `, and ${uninstall} when you remove it`}`]), ...(install === '' && uninstall !== '' ? [`Run ${uninstall} when you remove it`] : []), ...(keys === '' ? [] : [`Bind ${keys}`])]
72
+ consent({ install, uninstall, keys, permissions, updates }) {
73
+ const changes = [
74
+ ...(install === '' ? [] : [`Run ${install} now${uninstall === '' ? '' : `, and ${uninstall} when you remove it`}`]),
75
+ ...(install === '' && uninstall !== '' ? [`Run ${uninstall} when you remove it`] : []),
76
+ ...(keys === '' ? [] : [`Bind ${keys}`]),
77
+ ...(updates === undefined ? [] : [`Update ${name} automatically from the ${updates} marketplace`]),
78
+ ]
73
79
  return show<boolean>(
74
80
  (answer) => ({
75
81
  draw: () =>
@@ -1,7 +1,7 @@
1
1
  import type { Args, EventResult, Frozen, HookBudget, HookStream, PluginOptions, ProcessSpawnChunk, ProcessSpawnResult } from 'claude-code'
2
2
  import type { HookInput, Mod, ModDefinition, ModEvent, ModHook, PaneHandle } from '../mod.js'
3
3
  import type { Options, OptionValues } from '../options.js'
4
- import { consentPath, dataFolder, finishStepsMethod, isAtLeast, oldestCmodFor, openPageMethod, parseConsent, pendingStepsMethod, parseEvent, permissionWords, readRecord, readSteps, scriptsSha256, settingsPagesMethod, storeFolder, type ReadFile, type RunnerEvent, type Steps } from '../records.js'
4
+ import { consentPath, dataFolder, finishStepsMethod, isAtLeast, marketplaceOf, oldestCmodFor, openPageMethod, parseConsent, pendingStepsMethod, parseEvent, permissionWords, readRecord, readSteps, scriptsSha256, settingsPagesMethod, storeFolder, updatesToTurnOn, type ReadFile, type RunnerEvent, type Steps } from '../records.js'
5
5
  import { relativePath } from '../utils/paths.js'
6
6
  import { formatExit, listed, messageOf } from '../utils/text.js'
7
7
  import type { Claude } from './claude.js'
@@ -275,6 +275,13 @@ export function createLifecycle<State extends object, Declared extends Options =
275
275
  if (added.length > 0) runtime.claude.ui.log(`${definition.name} added ${listed(added)}.`)
276
276
  }
277
277
 
278
+ const updatesToShow = async () => {
279
+ const [home, configHome] = await Promise.all([claude().env.home(), claude().env.configHome()])
280
+ const configRoot = configHome ?? `${home ?? ''}/.claude`
281
+ const known = await claude().fs.read(`${configRoot}/plugins/known_marketplaces.json`).then((text): unknown => JSON.parse(text), () => undefined)
282
+ return updatesToTurnOn(marketplaceOf(claude().plugin.root, claude().plugin.name), await claude().settings.read({ source: 'user' }), known)
283
+ }
284
+
278
285
  const askConsent = async (event: Extract<RunnerEvent, { kind: 'needs-consent' }>) => {
279
286
  const name = definition.name
280
287
  if ((await claude().session.surfaces()).length === 0) {
@@ -283,7 +290,7 @@ export function createLifecycle<State extends object, Declared extends Options =
283
290
  return
284
291
  }
285
292
  showLine().wait('Waiting for your answer')
286
- if (await installer.consent(event)) return install(event.sha256)
293
+ if (await installer.consent({ ...event, updates: await updatesToShow().catch(() => undefined) })) return install(event.sha256)
287
294
  await installer.close()
288
295
  phase = 'declined'
289
296
  endLine()