Skip to content

feat: passive update check (cached, opt-out, install-aware)#21

Open
hakimjonas wants to merge 1 commit into
mainfrom
feat/update-ergonomics
Open

feat: passive update check (cached, opt-out, install-aware)#21
hakimjonas wants to merge 1 commit into
mainfrom
feat/update-ergonomics

Conversation

@hakimjonas

Copy link
Copy Markdown
Owner

Item 1c of the 0.14.0 cycle — the update-ergonomics feature.

What

On a normal query or REPL run, lam checks at most once a day whether a newer release exists and, if so, prints a one-line notice to stderr with the upgrade command for how it was installed:

A new lam is available: 0.13.0 -> 0.14.0. Upgrade: brew upgrade lambe

Design (the careful bits)

  • Never blocks the query. The notice shown this run is a synchronous read of a small JSON cache (sub-ms). The network refresh only updates the cache for the next run, so it's fire-and-forget (unawaited) — its result is never needed, which sidesteps the background-future-vs-exit() race entirely.
  • Testable. All IO (clock, cache store, fetcher, exe path, env) is behind injectable seams in bin/update_check.dart, so the policy is unit-tested with in-memory fakes — no real network/disk.
  • Language stays pure. Everything is in bin/ (the CLI harness); lib/ remains dart:io-free / WASM-clean. MCP server untouched.
  • No binary self-replacement. Install-method detection (brew/scoop/pub/manual) from Platform.resolvedExecutable just prints the right upgrade command.

Gating (fires only when ALL hold)

stderr is a TTY · not CI (CI env) · not --no-update-check · not LAM_NO_UPDATE_CHECK · not a suppressed mode (-n, --ndjson, --assert, --print-shape, --explain*; --version/--skill/--completions already exit earlier).

Tests

  • 25 unit tests (test/update_check_test.dart): isNewer (incl. unparseable→not-newer so a bad response can't notice), decideNotice staleness/malformed-cache, refreshCache write-only-on-success, detectChannel per platform, render per channel, the shouldCheck truth table, cache-path resolution (XDG/HOME/LOCALAPPDATA).
  • Integration (cli_integration_test.dart): no notice leaks to stderr on the non-TTY path; --no-update-check accepted.

Docs

getting-started "Updating" section; man page --update-check option + ENVIRONMENT (LAM_NO_UPDATE_CHECK, CI) + FILES (cache path); CHANGELOG.

Verification

analyze --fatal-infos, format, lint-changelog, generated-files (man page idempotent) all green; full suite 1714 + lambe_test 19 pass. Purely additive (753 insertions, 0 deletions).

On a normal query or REPL run, lam checks at most once a day whether a
newer release exists and, if so, prints a one-line notice to stderr with
the upgrade command for how it was installed. Closes the 0.14.0
update-ergonomics item.

Design (bin/update_check.dart, all IO behind injectable seams):
- The notice shown THIS run is decided synchronously from a small JSON
  cache (sub-millisecond, never blocks the query). The network refresh
  only updates the cache for the NEXT run, so it's fire-and-forget —
  unawaited, its result never needed — which sidesteps the
  background-future-vs-exit() race entirely.
- Gated: fires only for the interactive query path and the REPL. OFF for
  -n/--null-input, --ndjson, --assert, --print-shape, --explain*,
  --version/--skill/--completions, in CI (CI env var), when stderr is not
  a terminal, via --no-update-check, or LAM_NO_UPDATE_CHECK.
- Install-method detection (brew/scoop/pub/manual) from
  Platform.resolvedExecutable picks the upgrade command. No binary
  self-replacement.
- Version compare is a small hand-rolled numeric semver; unparseable
  upstream => not-newer, so a bad response can't produce a bogus notice.

The language (lib/) stays dart:io-free — this is all CLI harness, the
same category as the existing file/stdin IO. MCP server untouched.

Tests: 25 unit tests with in-memory fakes + fixed clock (no real
network/disk) covering isNewer, decideNotice staleness, refreshCache,
detectChannel, render per channel, the shouldCheck truth table, and
cache-path resolution; plus integration tests asserting no notice leaks
on the non-TTY path and --no-update-check is accepted.

Docs: getting-started "Updating" section; man page --update-check option,
ENVIRONMENT (LAM_NO_UPDATE_CHECK, CI), and FILES (cache path); CHANGELOG.

analyze --fatal-infos, format, lint-changelog, generated-files all green;
full suite 1714 + lambe_test 19 pass.
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