Skip to content

feat(update-check): show extension update notice on exit#1236

Merged
jackwener merged 2 commits intomainfrom
feat/extension-update-notice
May 1, 2026
Merged

feat(update-check): show extension update notice on exit#1236
jackwener merged 2 commits intomainfrom
feat/extension-update-notice

Conversation

@jackwener
Copy link
Copy Markdown
Owner

Summary

  • Daemon stashes the live extensionVersion + lastSeenAt into the shared ~/.opencli/update-check.json cache on each hello handshake.
  • CLI exit hook now prints an extra Extension update available line when a newer release is in cache and lastSeenAt is within the last 7 days.
  • writeCache is now a read-merge-write so the daemon's currentExtensionVersion and the CLI's npm latestVersion writes don't clobber each other.

Why

Today only opencli doctor surfaces extension drift. Users running normal browser commands have no signal that the Chrome extension is out of date. The shared cache already contains latestExtensionVersion (refreshed every 24h via the existing GitHub fetch); we just needed the current installed extension version to compare against, and the daemon already knows it from the hello handshake.

Cost

  • CLI hot path: zero new I/O, zero new daemon contact, zero new network. Module-load cache read is unchanged; exit hook does one extra string compare.
  • Daemon: one extra fs.writeFileSync (small JSON) per extension reconnect — a rare event.

Staleness guard

If the user hasn't run a browser command in a week, extensionLastSeenAt becomes stale and we suppress the notice rather than risk reporting an outdated currentExtensionVersion. The window is EXTENSION_STALE_MS = 7 days.

Test plan

  • npm run typecheck
  • OPENCLI_DAEMON_PORT=29125 npx vitest run src/update-check.test.ts src/daemon.test.ts src/commands/daemon.test.ts src/doctor.test.ts src/browser/daemon-client.test.ts src/browser.test.ts — 67/67 passing
  • New unit tests for buildUpdateNotices: empty cache, CLI-only notice, ext-only notice, stale-window suppression, equal-version suppression, both-out-of-date.

jackwener added 2 commits May 2, 2026 00:56
The CLI exit hook already prints "Update available" when a newer @jackwener/opencli is on npm. Extension updates were only surfaced inside `opencli doctor`, so users running normal browser commands had no signal that the Chrome extension was out of date.

Solution piggybacks on the existing 24h background fetch:
- Daemon writes the live extensionVersion + lastSeenAt into the shared cache on every hello handshake (rare event, one fs.writeFileSync).
- CLI exit hook reads the cache it already loads and prints an extra extension notice when a newer release is available and the cache is fresh (<7d).
- writeCache becomes a read-merge-write so the daemon's currentExtensionVersion and the CLI's npm latestVersion don't clobber each other.

Net cost on the CLI hot path: zero new I/O, zero new daemon contact. The notice formatter is split into a pure helper (buildUpdateNotices) so the staleness window, equality, and combined-notice cases are unit-tested without touching disk or stderr.
Self-review caught a TypeError path: if the daemon's hello handler runs `recordExtensionVersion` before the CLI's npm fetch ever populated the cache, the resulting cache file has only `currentExtensionVersion` + `extensionLastSeenAt` and no `latestVersion`. The next CLI run then fed `undefined` into `isNewer`, which calls `.replace(...)` on it.

- Mark `lastCheck` and `latestVersion` optional in the cache schema (the merge pattern means either side may write first).
- Guard the CLI notice on `cache.latestVersion` being defined before comparing.
- Guard `checkForUpdateBackground`'s 24h short-circuit on `lastCheck` being defined.
- Add a test for the daemon-only cache case.
@jackwener jackwener merged commit b41ee2b into main May 1, 2026
13 checks passed
@jackwener jackwener deleted the feat/extension-update-notice branch May 1, 2026 17:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant