[AI-1863] Cap the passive update notice + kcap status at the connected server's version - #545
Conversation
…-1863] The server half (kcap-server #1404) caps CLI-update recommendations at min(npm latest, server version) and emits X-Kcap-Server-Version. This is the client half: the CLI now consumes that header so its own passive "update available" stderr notice and the kcap status version line never steer a user to a CLI newer than the server they talk to (manual tenant rollouts can trail npm by days). - ServerVersionStore: a durable, per-normalized-server-URL cache of the server version (one flat file per server in the config dir; best-effort, in-process write-dedup so the hot path touches disk once per distinct value). - ServerVersionCaptureHandler: outermost DelegatingHandler on every authenticated client (the CreateClientCoreImplAsync choke point) that reads X-Kcap-Server-Version from each response into the store. No extra requests. - UpdateAdvisoryResolver: caps the npm-latest target at min(npm, cached server version), ONLY on the stable `latest` channel with a cached, stable server version (beta rides ahead; absent cache => today's behaviour). Recomputes "newer" against the target so a user already at/ahead of their server isn't nagged. - UpdateNotice (passive stderr notice) and kcap status render the capped advisory: when capped, a pinned `npm install -g @kurrent/kcap@<target>` command and a "(server version)" marker (plain `kcap update` follows the dist-tag and would overshoot). `kcap update` / `--check` stay UNCAPPED — explicit actions, not recommendations. Surface D (the in-agent VersionNudgeEmitter) needs no change: the server omits the hook `version` field when capped, so the emitter only ever receives an uncapped target. Tests: ServerVersionStore round-trip/normalize, capture handler, the cap truth table, and the status version-line formatting (29 green). 🤖 Generated with [Claude Code](https://claude.com/claude-code)
PR Summary by QodoCap passive CLI update hints to the connected server version
AI Description
Diagram
High-Level Assessment
Files changed (11)
|
Code Review by Qodo
1.
|
…etadata Two correctness fixes on the passive server-version cap: - ServerVersionStore.Normalize now reuses the repo's own ServerIdentity. Canonicalize (scheme+host lower-cased, default ports converged, path preserved case-sensitively) instead of a divergent lowercase-everything key, with a conservative non-lowercasing fallback for inadmissible URLs. The old key flattened case-sensitive path-routed deployments (one tenant capped against another's server) and split https://host vs :443. - UpdateAdvisoryResolver strips +buildmetadata from the capped target via CapacitorVersion.Display, so a MinVer commit-SHA server version never leaks into the "(server version)" copy or the pinned npm install -g @kurrent/kcap@<target> command (which would not resolve). Adds tests: default-port convergence, path-case significance, and build-metadata stripping on a capped target.
|
Both qodo findings addressed in 6373435:
Added tests: default-port convergence, path-case significance, and build-metadata stripping on a capped target. |
|
/agentic_review |
|
Code review by qodo was updated up to the latest commit 6373435 |
…ity note Compress the doc comment to the load-bearing facts (canonicalization helper, case-sensitive path rationale, conservative fallback) to satisfy the repo's concise-comment convention. No behavior change.
|
/agentic_review |
|
Code review by qodo was updated up to the latest commit dd5d441 |
Context
The server half (kcap-server #1404, AI-1863) caps CLI-update recommendations at
min(npm latest, server version)and emits anX-Kcap-Server-Versionresponse header. This is the client half: the CLI now consumes that header so its own passive "update available" stderr notice and thekcap statusversion line never steer a user to a CLI newer than the server they talk to — manual tenant rollouts can trail npm by days, and a newer CLI risks protocol mismatch against the older server.What changed
ServerVersionStore— a durable, per-normalized-server-URL cache of the server version (one flat file per server in the config dir; best-effort, with an in-process write-dedup so the per-response hot path touches disk at most once per distinct value).ServerVersionCaptureHandler— the outermostDelegatingHandleron every authenticated client (theCreateClientCoreImplAsyncchoke point, the same one that attaches the request-side observation headers), readingX-Kcap-Server-Versionfrom each response into the store. No extra requests; best-effort, never alters the response.UpdateAdvisoryResolver— caps the npm-latest target atmin(npm, cached server version), only on the stablelatestchannel with a cached, stable server version present (beta deliberately rides ahead; an absent cache keeps today's behaviour — the cold-start doctrine). Recomputes "newer" against the capped target, so a user already at/ahead of their server is never nagged.UpdateNotice(passive exit-time stderr notice) andkcap statusrender the capped advisory: when capped, a pinnednpm install -g @kurrent/kcap@<target>command and a(server version)marker (plainkcap updatefollows the dist-tag and would overshoot the cap).kcap updateand--checkstay UNCAPPED — they're explicit actions, not recommendations.Surface D (the in-agent
VersionNudgeEmitter) needs no change: the server omits the hookversionfield when the target is capped, so the emitter only ever receives an uncapped target (where plainkcap updateis correct).Tests
29 unit tests, all green locally:
ServerVersionStoreTests(round-trip, normalization, per-server independence, overwrite, no-op guards);ServerVersionCaptureHandlerTests(header present → captured; absent → nothing);UpdateAdvisoryResolverTests(the cap truth table — passthrough when uncapped/beta/prerelease/absent, cap at min, user-ahead-not-nagged, plus the stable-release gate);StatusVersionLineFormattingTests(bare / uncapped / capped-with-marker rendering).README +
help-update.txtupdated in the same PR (house rule).Completes the client half of AI-1863.
🤖 Generated with Claude Code