[AI-866] feat: make kcap update perform the upgrade and refresh hooks/skills#159
Conversation
…ks/skills Previously `kcap update` only checked the registry and printed a hint to run `npm install -g`. The skills/hooks refresh lived only in the npm postinstall hook, which modern package managers gate behind an "allowed scripts" allowlist — so an upgrade could ship stale skills/hooks. `kcap update` now performs a one-step, user-initiated upgrade and refresh. Because the user invokes it explicitly, the refresh runs regardless of the postinstall gate. The upgrade is driven from the Node launcher (kcap.js), never the native binary: the OS locks an executable image for the whole process lifetime but a script only during load, so with the native binary not running, npm can overwrite it even on Windows — no temp-file/rename/detached-helper dance. - npm/kcap/bin/refresh.js: extract the per-agent `plugin install --if-installed` loop, shared by postinstall and update. - npm/kcap/bin/postinstall.js: slim to call refresh.runRefreshes(). - npm/kcap/bin/kcap.js: intercept `update` — detect npm-global install, probe the native `update --check`, pre-check write access to the global root, run `npm install -g @kurrent/kcap@latest`, then refresh. Route npm through a shell on Windows. `--check`/`--help` fall through to the binary. - UpdateCommand.cs: add `--check` JSON probe; retarget messages to `kcap update`. - VersionNudgeEmitter.cs / Program.cs: retarget nudge, pass args. - .gitignore: track npm/kcap/bin/ (blanket `bin/` rule would drop refresh.js). - Docs + tests updated. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Code Review by Qodo
Context used✅ Tickets:
AI-866 1.
|
PR Summary by QodoMake WalkthroughsDescription• Make kcap update run the npm global upgrade and then refresh opted-in plugins. • Add a --check JSON probe for launcher-driven update gating. • Retarget docs, help text, and nudge messaging from npm install -g to kcap update. Diagramgraph TD
U["User runs kcap update"] --> L["Node launcher (kcap.js)"] --> D{"Global npm install?"}
D -->|"no"| G["Print install guidance"]
D -->|"yes"| C["Native binary: update --check"] --> N["npm install -g @kurrent/kcap@latest"] --> R["refresh.js: runRefreshes"] --> P["plugin install --if-installed (agents)"]
High-Level AssessmentThe following are alternative approaches to this PR: 1. Implement self-update inside the native binary
2. Keep `kcap update` as “check-only” and rely on postinstall refresh
3. Add a dedicated `kcap refresh` command and keep upgrade separate
Recommendation: Keep the PR’s approach: driving the upgrade from the Node launcher is the most robust way to avoid native binary file-lock issues while still providing a one-step UX. The added File ChangesEnhancement (4)
Refactor (2)
Tests (2)
Documentation (3)
|
…inate `update --check` emitted `newer:false` whenever it couldn't compare versions — including when the native binary reports its version as "unknown" (current => null). The launcher treated that as "already up to date" and exited without upgrading, stranding the user on a stale CLI (and printing "Already up to date: null"). Make `newer` tri-state: true (upgrade), false (confidently up to date), null (can't tell — current unknown or registry check failed). The launcher now only takes the up-to-date fast-path on `newer:false` with a known current version; null falls through to the idempotent `npm install -g @latest`. Reported by qodo on #159. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
What
kcap updatenow performs a one-step upgrade and refreshes agent hooks/skills, instead of only printingnpm install -g ….Closes AI-866.
Why
The skills/hooks refresh lived only in the npm
postinstallhook, which modern package managers gate behind an "allowed scripts" allowlist. When that gate blocks the postinstall, an upgraded CLI ships stale skills/hooks. A user-initiatedkcap updateruns the refresh regardless of that gate — the same pattern Claude Code / Codex use.How
The upgrade is driven from the Node launcher (
kcap.js), never the native binary. The OS locks an executable image for the whole process lifetime, but a script only during load — so with the native binary not running, npm can overwrite it even on Windows, with no temp-file/rename/detached-helper dance.kcap update:npm root -g); otherwise prints install-method guidance (e.g. Homebrew) and exits.update --check(short-lived → binary unlocked before npm runs) to skip when already latest.npm install -g @kurrent/kcap@latest, then refreshes opted-in agent plugins via the new launcher. npm is routed through a shell on Windows (.cmd-spawn fix).update --check/update --helpfall through to the native binary.Changes
npm/kcap/bin/refresh.js(new): shared per-agentplugin install --if-installedloop.postinstall.js: slimmed to callrefresh.runRefreshes().kcap.js:updateintercept (above).UpdateCommand.cs:--checkJSON probe ({current, latest, newer}); messages retargeted tokcap update.VersionNudgeEmitter.cs/Program.cs: in-agent nudge retargeted; pass args..gitignore: tracknpm/kcap/bin/(the blanketbin/rule would silently droprefresh.js; platform binary dirs stay ignored).help-update.txt, npm README) + 3 test assertions updated.Verification
node --check.Notes
--check:CheckForUpdateAsyncis network/cache-coupled (needs injection to test cleanly); thenewergating reuses already-testedSemverCompare.🤖 Generated with Claude Code