fix(update,sync): V9 update behaviors, atomic auth, conflict window#223
fix(update,sync): V9 update behaviors, atomic auth, conflict window#223vreshch wants to merge 2 commits into
Conversation
|
🎉 PR Validation ✅ PASSED Commit: Checks:
Ready to merge! ✨ 🔗 View workflow run |
5d28e4a to
83ea944
Compare
Hardening pass (adversarial review findings, commit 2)1 (HIGH) Offline exit delay + retry storm - fixed. Background refresh now uses
2 (MED) update.lock TOCTOU - fixed. 3 (MED) crash mid-merge wedges sync - fixed. Each cycle now aborts any interrupted operation before touching the tree: 4 (LOW) restart robustness - fixed. New Verification: |
Closes five verified code-vs-spec gaps around self-update, atomic auth writes, and the sync conflict crash-window. One reviewable unit; strict-TS ESM, no new deps (R6 guard green).
Fixes
1. Update source = npm registry (doc V9).
fetchCliLatestnowGETshttps://registry.npmjs.org/@agentage/cli/latest(5s timeout,Accept: application/json, reads.version) instead of the backend/cli/latest. Same silent-null /kind:'unknown'contract on any failure; no server floor/notice so those paths simply never trigger. Callers updated (checkForUpdate(installed),status-info).update-check.test.ts(registry shape, JSON Accept header, null on non-2xx/throw/no-version);status-info.test.tsmock updated to the registry route.2. Passive check on every command + 1h TTL cache (doc V9). New
src/lib/update-cache.ts:<configDir>/update-check.json({checkedAt, latest}, 1h TTL). A commanderpostActionhook prints at most one dim hint (update available: X.Y.Z -> npm i -g @agentage/cli@latest) read purely from the cache, then fires a non-awaited refresh only when the cache is stale/absent. Never blocks: warm runs are cache-only (~0.15s), a cold run is bounded by a 3s background fetch, any failure is total silence. Hint suppressed forstatus/update(they report richer state) and under--json(no output corruption).update-cache.test.ts(TTL respected = no fetch, stale = refresh, absent = refresh, throw/null = silent + no write, end-to-end cache file write, hint only when newer).node dist/cli.js --helpexits ~0.15s; coldvault listwarms the cache then subsequent runs are cache-only;vault list --jsonemits clean JSON.3.
agentage updaterestarts the daemon + concurrency lock (V9 + M3 "restart clears the version-mismatch warning"). After a successful install, if the daemon is running (pidfile-alive check) it is stopped and re-spawned and a line is printed; a stopped daemon is left stopped. A single-writer<configDir>/update.lock(src/lib/update-lock.ts) refuses a second run while a lock younger than 10 min is held, overrides a stale one, and is released infinally.update.test.ts(restart announced only when running; lock refusal blocks install + skips release;restartDaemonIfRunningstops/starts only when running);update-lock.test.ts(acquire, refuse-fresh, override-stale, idempotent release).4. Atomic
auth.jsonwrites.saveAuthnow writes a sibling temp,chmod 0600BEFORE the rename, then renames over (mirrorsvaults.ts); dir stays 0700. No half-written or briefly-permissive token file.config.test.ts(mode still 0600 after overwrite, content round-trips, noauth.json.tmpresidue).5. Conflict files durable with the merge (M4 follow-up).
sync/cycle.tsreconcilepreviously committed themerge -X oursand only afterwards wrote + committed the.conflict.mdcopies, so a crash between the two left the remote side merged-away yet never surfaced. Nowmerge --no-commit -X ours, write the.conflict.mdcopies (remote blobs captured before merging, as before), then onegit add -A && git commit: the merge result and the conflict copies land in a SINGLE commit. Numeric-dedup naming unchanged.cycle.test.tsdivergence test asserts HEAD is a merge commit (two parents) andgit show --name-onlyof it listsnote.conflict.md(window structurally closed). Added: auto-commit message matches/^sync: \d{4}-/; a file tracked before being added toignorekeeps syncing (gitignore/.git/info/excludesemantics).Verification
npm run verifygreen (type-check + type-check:e2e + lint + format:check + 224 tests + build).test:coveragegreen (statements 86%, branches 77%, functions 77%, lines 87%; all above the 65/70/70/70 gates).daemon,m1-requirements,mcp-daemon,mcp-stdio,memory-offline,sync,vault-offline): 19/19 pass against the build - including theupdate --checktest that hits the new npm-registry source and the sync-divergence test.Notes
e2e/*.test.tschanges).update --checklands separately.