[AI-1283] Deterministic update notice + version/preference headers - #507
[AI-1283] Deterministic update notice + version/preference headers#507realtonyyoung wants to merge 9 commits into
Conversation
…le-backoff reads Cache schema (UpdateCacheRecord) adds attempted_at/failed alongside the existing latest_version/checked_at, reading legacy two-field files as plain success records. CheckForUpdateAsync's decision ladder is now: fresh success record -> cached; failed record within a 1h backoff and not forceCheck -> retained last-known version; otherwise fetch. The fetch honors a passed CancellationToken so a future caller can bound the passive path without stalling every CLI invocation; the cache write itself never uses that token so a cancelled/failed fetch can still persist its backoff record. Part of AI-1283.
Replaces the fire-and-forget update-check Task.Run in Program.cs (only reliably awaited inside a Claude hook, where nobody reads stderr) with UpdateNotice.FlushAsync, run from a finally wrapping the whole command dispatch — including the --help and no-server-configured early exits — so the notice fires deterministically for every human-facing invocation. UpdateNotice.IsHumanFacing is the suppression predicate (hooks/generators, mcp, watch, daemon run, update/uninstall, --no-update-check); a shared lazily-started check task plus a MarkReported flag let a future exit-time surface reuse the same result without a second network call or a double print. Adds --no-update-check to every kcap-hook invocation in hooks.json belt-and-braces.
… drop dead updateCheckTask param
Adds a Version line to `kcap status` (kcap {current}), reusing
UpdateNotice's shared lazy update-check (GetSharedCheckAsync) so no
second network round-trip happens. When a newer version is available
it annotates inline (`kcap 0.11.12 (update available: 0.11.14)`) and
calls UpdateNotice.MarkReported() so Program.cs's exit-time footer
does not also print. Respects --no-update-check and a disabled
profile.UpdateCheck by skipping the check entirely rather than
suppressing an already-performed one.
Every client from HttpClientExtensions.CreateClientCoreAsync (the sole choke point for authenticated CLI requests) and WhoamiCommand's raw probe client now carry X-Kcap-Cli-Version. X-Kcap-Update-Check: off is added only when the active profile has update_check disabled; its absence on a version-carrying request is read by the server as "on".
…oadened opt-out update_check=false now silences kcap's update nudging everywhere, not just the local stderr hint: ClaudeHookCommand skips emitting the VersionNudgeEmitter fragment into a Claude Code session's additionalContext when the active profile has opted out, even if the server still sends a newer `version`. help-update.txt, the config-set help text, and the README are updated to describe the broadened meaning (stderr hint, transmitted version/preference headers, in-agent nudge).
…-shot flag in README
PR Summary by QodoDeterministic update notice + CLI version/opt-out headers on every request
AI Description
Diagram
High-Level Assessment
Files changed (20)
|
Code Review by Qodo
1.
|
…ateNotice/StatusCommand comments
|
All three qodo findings addressed in a60c100 (docs/comments only, no logic change):
|
Part of AI-1283 — the kcap-cli half of "your kcap CLI is out of date" notifications. The kcap-server half (npm poller, per-user version registry, web banner, notification-centre kind, hook
versionfield) already merged in kcap-server#1384. This PR makes the local update notice deterministic and starts transmitting the observation headers that server side consumes. Immediately useful on its own; the headers are inert until a server that reads them is deployed (and the server already ships that).What changed
try/finallyaround the whole dispatch (covering--helpand the no-server early exits) and prints after every human-facing command. Suppressed for agent-spawned/protocol/long-running commands (hook,generate-whats-done,set-title,copilot-finalize,mcp *,watch, the wholedaemonfamily) and forupdate/uninstall/--no-update-check/update_check=false.UpdateCacheRecordadds failure/backoff fields (backward-compatible with the legacy two-field cache): a failed poll is retained with a 1h backoff so repeated quick commands don't re-hit the network, and the passive path runs under a bounded budget (300ms warm cache / 3s network with a 500ms cleanup grace) so a slow registry can't delay exit or livelock.kcap update/--checkkeep the 5s bound and bypass the backoff.kcap statusnow prints the installed CLI version, with an inline(update available: X)when behind — sharing one check with the exit notice (no double print, at most one network call).CreateClientCoreAsyncchoke point, plus thewhoamiraw probe) carriesX-Kcap-Cli-Version;X-Kcap-Update-Check: offis added only when the user has opted out. These let the server surface the banner / notification and honor the opt-out.kcap config set update_check falseis now the full, persisted opt-out: it silences the local notice, thekcap statusannotation, the transmitted headers (so the server-side banner/notification honor it), and the in-agent nudge.--no-update-checkstays a one-shot local suppression.help-update.txt+confighelp updated.Notes
.csfile (repo lint).🤖 Generated with Claude Code