Skip to content

feat(cua-driver-rs): announce new versions at startup (#1535) - #1536

Merged
f-trycua merged 4 commits into
mainfrom
feat/cua-driver-rs-update-banner-1535
May 17, 2026
Merged

feat(cua-driver-rs): announce new versions at startup (#1535)#1536
f-trycua merged 4 commits into
mainfrom
feat/cua-driver-rs-update-banner-1535

Conversation

@f-trycua

@f-trycua f-trycua commented May 16, 2026

Copy link
Copy Markdown
Collaborator

Closes #1535.

Summary

Adds a non-blocking "new version available" banner to the long-running interactive entry points of cua-driver-rs (mcp, serve, doctor). The check runs on a background task at startup, hits the GitHub releases API once per ~20 hours (cached on disk), and prints a small two-line banner to stderr if a newer cua-driver-rs-v* release exists and the user hasn't dismissed it.

Banner format:

✨ cua-driver v0.1.4 is available (you have v0.1.3).
   Update with: cua-driver update
   Release notes: https://github.com/trycua/cua/releases/tag/cua-driver-rs-v0.1.4

What's in this PR

  • crates/cua-driver/src/version_check.rs — new module:
    • pub fn maybe_announce_update() — sync, returns instantly; spawns the network check on tokio::task::spawn_blocking (or a short-lived OS thread for sync entry points)
    • pub(crate) fn fetch_latest_version()ureq-based GitHub releases call, filtered to the cua-driver-rs-v* tag prefix, drafts + pre-releases excluded
    • read_cache / write_cache against ~/.cua-driver-rs/version_check.json with a 20-hour refresh threshold
    • pub fn is_newer(latest, current) -> bool — strict semver compare; pre-release sorts below release
    • pub fn dismiss_version(version: &str) — appends to dismissed_versions for the future interactive "skip until next version" path
  • crates/cua-driver/src/main.rs — wires maybe_announce_update() into the Mcp, Serve, and Doctor arms on both the macOS and non-macOS main() paths
  • crates/cua-driver/src/cli.rsrun_update_cmd now delegates to the shared version_check::fetch_latest_version() / version_check::is_newer() instead of shelling out to curl with its own JSON-walking code path
  • crates/cua-driver/Cargo.toml — adds semver = "1" and tempfile (dev-dep)
  • libs/cua-driver-rs/PARITY.md — new "Startup flow: update-available banner" section covering behavior, cache shape, opt-out layers, HTTP client, and shared release-fetch with cua-driver update
  • docs/content/docs/cua-driver/guide/getting-started/installation.mdx + docs/content/docs/cua-driver/reference/cli-reference.mdx — user-facing docs for the banner, the cache, the scripted-context skip list, and the env / config opt-out paths

Opt-out (three layers, any one disables the check)

  1. Env var CUA_DRIVER_RS_UPDATE_CHECK=false (also 0, no, off; case-insensitive) — single invocation
  2. Config flag update_check_enabled = false in ~/.cua-driver/config.json — permanent (set via cua-driver config set update_check_enabled false)
  3. CARGO_PKG_VERSION with a pre-release suffix (-dev, -rc.1, -beta, …) — auto-skips for source / dev builds

Skipped entry points

--version, list-tools, describe, call, dump-docs, mcp-config, update, stop, status, recording, config, diagnose, telemetry install-event — these are routinely piped from scripts and a banner would corrupt their parseable output.

Tests

22 new unit tests in version_check::tests, all passing:

  • is_newer semver edge cases (0.2.0 > 0.1.99, 0.1.3 > 0.1.3-dev, equal / older returns false, unparseable returns false)
  • pre-release detection (-dev, -rc.1, -beta, garbage input)
  • cache round-trip through tempfile::tempdir()
  • dismissed_versions persistence (append, idempotent re-dismissal)
  • 20h refresh threshold (stale cache → fetch; fresh cache → no fetch, uses cached value)
  • dismissed-latest suppresses the banner
  • env-var opt-out short-circuits is_enabled
  • persisted update_check_enabled = false config flag disables; true / missing leaves on
  • banner format contains all required lines + the correct release-tag URL
  • pick_latest_release filters out Swift-port tags, drafts, and pre-releases
  • ISO-8601 timestamp round-trips against a known unix epoch

Test plan

  • cargo build --release -p cua-driver — clean build (1 pre-existing unrelated warning)
  • cargo test -p cua-driver version_check:: — 22 passed, 0 failed
  • cua-driver --version — no banner pollution, prints cua-driver 0.1.3
  • CUA_DRIVER_RS_UPDATE_CHECK=false cua-driver list-tools — clean machine-readable output, no banner
  • Manual: run cua-driver mcp from an outdated install (e.g. CARGO_PKG_VERSION patched to 0.1.0) and verify the banner lands on stderr within ~5s
  • Manual: re-run cua-driver mcp within 20h and verify the cache file is reused (~/.cua-driver-rs/version_check.json mtime unchanged, no HTTP request in tracing::debug! output with CUA_LOG=debug)
  • Manual: write ~/.cua-driver/config.json with {"update_check_enabled": false} and verify the check is skipped (no banner, no debug-log fetch line)

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added automatic update notifications for interactive commands (mcp, serve, doctor). Displays a banner on stderr when a newer release is available, with options to disable via environment variable or configuration.
  • Documentation

    • Added documentation describing the startup banner feature, including configuration options and behavior details.

Review Change Stack

f-trycua and others added 3 commits May 17, 2026 00:39
Introduces crates/cua-driver/src/version_check.rs with the building
blocks for the startup "new version available" banner:

- fetch_latest_version(): ureq-based GitHub releases call, filtered
  to the cua-driver-rs-v* tag prefix; shared with the update
  subcommand which now delegates to it instead of shelling out to
  curl with its own JSON-walking code path
- VersionCache + read_cache / write_cache against
  ~/.cua-driver-rs/version_check.json (last_checked_at, latest
  version, dismissed_versions)
- is_newer() strict semver compare; pre-release detection so source
  builds never get nagged
- dismiss_version() append + idempotent persist
- 22 unit tests covering semver edge cases (0.2.0 > 0.1.99,
  release > pre-release of same triple), cache round-trip in a
  tempdir, dismissal persistence, 20-hour refresh threshold,
  env-var + config opt-out, JSON release-list filtering

No callers yet — maybe_announce_update is wired into the mcp / serve
/ doctor entry points in the next commit. semver = "1" and tempfile
(dev-dep) added to Cargo.toml.

Refs: #1535

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Wires version_check::maybe_announce_update() into the three
long-running interactive entry points on both the macOS and
non-macOS main() paths:

- mcp (in-process MCP server, also runs before the daemon-proxy
  decision so users on either dispatch path see the banner)
- serve (Unix-socket daemon, fires before the permissions gate)
- doctor (interactive diagnostic command)

Deliberately NOT called from --version, list-tools, describe, call,
or dump-docs — those produce machine-readable stdout that gets piped
through jq from scripts, and a banner would corrupt their output.

The call is sync, returns immediately, and spawns the network round
trip on either tokio::task::spawn_blocking (when a runtime is live)
or a short-lived OS thread otherwise. Network failures stay silent
(tracing::debug! only); the next launch retries.

dismiss_version() is the one piece of the public API with no
in-binary caller today — kept #[allow(dead_code)] for the future
interactive prompt path (TUI / GUI helper) so the persistence layer
stays in one place.

Refs: #1535

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- PARITY.md: new "Startup flow: update-available banner" section
  covering the cache file shape, 20-hour refresh, opt-out layers,
  HTTP client, shared release-fetch with `cua-driver update`, and
  dismissal API
- cua-driver/guide/getting-started/installation.mdx: Callout
  explaining the stderr banner, the cache location, the
  scripted-context skip list, and the env / config opt-out paths
- cua-driver/reference/cli-reference.mdx: "Startup banner"
  subsection under `cua-driver update` linking the manual
  subcommand to the proactive surfacing path

Refs: #1535

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@vercel

vercel Bot commented May 16, 2026

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
docs Ready Ready Preview, Comment May 17, 2026 8:12am

Request Review

@coderabbitai

coderabbitai Bot commented May 16, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto incremental reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: ef23bc3c-7d16-4fde-8027-90023749de08

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

This PR adds a non-blocking background version-check banner to cua-driver that notifies users of available updates on long-running interactive commands. The banner runs asynchronously at startup, caches results for ~20 hours, supports persistent dismissal and disable controls, and shares version-fetching logic with the existing update subcommand.

Changes

Update available banner for interactive entry points

Layer / File(s) Summary
Dependencies for version checking
libs/cua-driver-rs/crates/cua-driver/Cargo.toml
semver = "1" enables strict semver comparison for version ordering; tempfile = "3" isolates test cache directories.
Version check module constants and data model
libs/cua-driver-rs/crates/cua-driver/src/version_check.rs
Module constants define cache location (~/.cua-driver-rs/version_check.json), env/config keys, ~20-hour refresh threshold, and GitHub Releases API details; VersionCache struct holds last-checked timestamp, latest version, and dismissed versions list.
Core version check implementation
libs/cua-driver-rs/crates/cua-driver/src/version_check.rs
GitHub Releases HTTP fetching with tag prefix filtering and draft/prerelease exclusion; cache read/write with fallback on network failure; enable/disable decision logic based on env var (CUA_DRIVER_RS_UPDATE_CHECK), config flag (update_check_enabled), and automatic skip for prerelease builds; internal time helpers for cache-age and ISO-8601 formatting.
Check and announce routine with dismissal
libs/cua-driver-rs/crates/cua-driver/src/version_check.rs
check_and_announce() fetches latest version (with cache fallback), compares for strictly newer, checks dismissed versions, and conditionally prints two-line stderr banner; maybe_announce_update() spawns background task immediately and returns; dismiss_version() records versions to suppress.
Unit tests for version check logic
libs/cua-driver-rs/crates/cua-driver/src/version_check.rs
Tests cover semver comparison with prerelease handling and parse failures, cache persistence and dismissal, refresh-threshold triggering vs. skipping network calls, enable/disable paths driven by env/config, banner formatting, GitHub release filtering, and timestamp round-tripping with isolated temporary directories.
Integrate version check into main entry points
libs/cua-driver-rs/crates/cua-driver/src/main.rs
Add mod version_check declaration and call version_check::maybe_announce_update() at startup of serve, doctor, and mcp commands (macOS and non-macOS variants).
Refactor update command to use shared version check
libs/cua-driver-rs/crates/cua-driver/src/cli.rs
run_update_cmd() delegates to shared crate::version_check::fetch_latest_version() and crate::version_check::is_newer() instead of local helpers; error handling matches shared-module behavior; remove deprecated local helper functions.
Document update banner in user-facing guides
docs/content/docs/cua-driver/guide/getting-started/installation.mdx, docs/content/docs/cua-driver/reference/cli-reference.mdx, libs/cua-driver-rs/PARITY.md
Installation guide callout and CLI reference section describe banner behavior, caching, disable controls (CUA_DRIVER_RS_UPDATE_CHECK env var and update_check_enabled config flag), excluded scripted commands, and prerelease auto-skip; PARITY.md audit documents implementation details and public APIs.

Sequence Diagram

sequenceDiagram
  participant User as User
  participant MainEntry as main.rs<br/>(serve/doctor/mcp)
  participant MaybeAnnounce as maybe_announce_update()
  participant Background as Background thread
  participant CheckAndAnnounce as check_and_announce()
  participant GitHub as GitHub Releases API
  participant Cache as ~/.cua-driver-rs/<br/>version_check.json
  participant Stderr as stderr
  
  User->>MainEntry: cua-driver serve (or doctor/mcp)
  MainEntry->>MaybeAnnounce: call at startup
  MaybeAnnounce->>Background: spawn(check_and_announce)
  MaybeAnnounce-->>MainEntry: return immediately
  MainEntry->>MainEntry: continue serve/doctor/mcp
  Background->>CheckAndAnnounce: run in background
  CheckAndAnnounce->>Cache: read cache & check age
  alt cache < 20 hours old
    Cache-->>CheckAndAnnounce: use cached latest_version
  else cache >= 20 hours old or missing
    CheckAndAnnounce->>GitHub: HTTP GET /repos/trycua/cua/releases
    GitHub-->>CheckAndAnnounce: JSON array of releases
    CheckAndAnnounce->>CheckAndAnnounce: filter cua-driver-rs-v* tags
    CheckAndAnnounce->>Cache: write latest version & timestamp
  end
  CheckAndAnnounce->>Cache: read dismissed_versions
  alt latest is strictly newer && not dismissed
    CheckAndAnnounce->>Stderr: print banner:<br/>✨ cua-driver v... is available<br/>Update with: cua-driver update
  end
Loading

🎯 3 (Moderate) | ⏱️ ~25 minutes

A rabbit hops through GitHub releases,
Caching secrets for twenty hours fast,
"New version!" it chirps to the sleepy dev—*
Background work done, the serve command sails.
Update at leisure, or dismiss with a bound. 🐰✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat(cua-driver-rs): announce new versions at startup (#1535)' clearly and specifically summarizes the main feature addition—a startup banner announcing new versions for interactive cua-driver-rs entry points.
Linked Issues check ✅ Passed The PR comprehensively implements all major coding requirements from issue #1535: asynchronous version checking, disk caching with ~20-hour refresh, GitHub releases integration with tag filtering, dismissal persistence, multi-layer opt-outs (env var, config flag, pre-release auto-skip), silent network failure handling, scripted-context skip list, shared code reuse in update command, and extensive unit tests.
Out of Scope Changes check ✅ Passed All changes are directly aligned with the PR objectives: version_check module implementation, main.rs integration for interactive entry points, CLI delegation to shared logic, dependency additions (semver, tempfile), and comprehensive documentation updates. No extraneous changes detected.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/cua-driver-rs-update-banner-1535

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (3)
docs/content/docs/cua-driver/guide/getting-started/installation.mdx (1)

117-120: ⚡ Quick win

Incomplete list of excluded commands.

Lines 117-120 state that --version, list-tools, describe, call, and dump-docs skip the banner, but the list is incomplete. According to PARITY.md lines 1836-1843, additional commands also skip the banner: mcp-config, update, stop, status, recording, config, diagnose, and telemetry install-event. The CLI reference (line 396-397 of cli-reference.mdx) includes mcp-config but not the others.

Consider either:

  1. Listing all excluded commands consistently across all three docs, or
  2. Rephrasing to make clear this is a partial list: "One-shot and machine-readable entry points such as --version, list-tools, describe, call, dump-docs, and others are not instrumented."
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/content/docs/cua-driver/guide/getting-started/installation.mdx` around
lines 117 - 120, The documentation states that scripted/machine-readable entry
points are not instrumented but lists an incomplete set; update the text in
installation.mdx to either enumerate all commands that skip the banner (include
--version, list-tools, describe, call, dump-docs, mcp-config, update, stop,
status, recording, config, diagnose, and telemetry install-event drawn from
PARITY.md) or rephrase the sentence to indicate this is a partial list (e.g.,
"One-shot and machine-readable entry points such as --version, list-tools,
describe, call, dump-docs, and others are not instrumented") so the docs are
consistent with PARITY.md and cli-reference.mdx.
docs/content/docs/cua-driver/reference/cli-reference.mdx (1)

396-399: ⚡ Quick win

Incomplete list of excluded commands (same issue as installation.mdx).

Lines 396-399 list machine-readable subcommands that skip the banner but omit several: update, stop, status, recording, config, diagnose, and telemetry install-event are also excluded per PARITY.md lines 1836-1843.

For consistency, either list all excluded commands or rephrase to indicate this is a representative sample: "Machine-readable and one-shot subcommands (such as --version, list-tools, describe, call, dump-docs, mcp-config, and others) deliberately do NOT emit the banner..."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/content/docs/cua-driver/reference/cli-reference.mdx` around lines 396 -
399, The sentence listing machine-readable subcommands is incomplete — it omits
`update`, `stop`, `status`, `recording`, `config`, `diagnose`, and `telemetry
install-event` (per PARITY.md) — so either expand the list to include those
exact commands (alongside `--version`, `list-tools`, `describe`, `call`,
`dump-docs`, `mcp-config`) or replace the sentence with a concise representative
phrase such as: "Machine-readable and one-shot subcommands (such as `--version`,
`list-tools`, `describe`, `call`, `dump-docs`, `mcp-config`, and others)
deliberately do NOT emit the banner" so the intent is clear and stays accurate;
update the text in cli-reference.mdx accordingly.
libs/cua-driver-rs/PARITY.md (1)

1800-1804: 💤 Low value

Add language specifier to fenced code block.

The code block showing the banner format is missing a language specifier. Add one for proper syntax highlighting and to resolve the markdownlint warning.

📝 Proposed fix
-```
+```text
 ✨ cua-driver v0.1.4 is available (you have v0.1.3).
    Update with: cua-driver update
    Release notes: https://github.com/trycua/cua/releases/tag/cua-driver-rs-v0.1.4

</details>

<details>
<summary>🤖 Prompt for AI Agents</summary>

Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @libs/cua-driver-rs/PARITY.md around lines 1800 - 1804, In PARITY.md, locate
the fenced code block containing the banner text starting with "✨ cua-driver
v0.1.4 is available (you have v0.1.3)." and add a language specifier (e.g.,
text) to the opening fence so the block becomes text ... ``` to enable
proper syntax highlighting and silence the markdownlint warning.


</details>

</blockquote></details>

</blockquote></details>

<details>
<summary>🤖 Prompt for all review comments with AI agents</summary>

Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In @docs/content/docs/cua-driver/guide/getting-started/installation.mdx:

  • Around line 117-120: The documentation states that scripted/machine-readable
    entry points are not instrumented but lists an incomplete set; update the text
    in installation.mdx to either enumerate all commands that skip the banner
    (include --version, list-tools, describe, call, dump-docs, mcp-config, update,
    stop, status, recording, config, diagnose, and telemetry install-event drawn
    from PARITY.md) or rephrase the sentence to indicate this is a partial list
    (e.g., "One-shot and machine-readable entry points such as --version,
    list-tools, describe, call, dump-docs, and others are not instrumented") so the
    docs are consistent with PARITY.md and cli-reference.mdx.

In @docs/content/docs/cua-driver/reference/cli-reference.mdx:

  • Around line 396-399: The sentence listing machine-readable subcommands is
    incomplete — it omits update, stop, status, recording, config,
    diagnose, and telemetry install-event (per PARITY.md) — so either expand the
    list to include those exact commands (alongside --version, list-tools,
    describe, call, dump-docs, mcp-config) or replace the sentence with a
    concise representative phrase such as: "Machine-readable and one-shot
    subcommands (such as --version, list-tools, describe, call, dump-docs,
    mcp-config, and others) deliberately do NOT emit the banner" so the intent is
    clear and stays accurate; update the text in cli-reference.mdx accordingly.

In @libs/cua-driver-rs/PARITY.md:

  • Around line 1800-1804: In PARITY.md, locate the fenced code block containing
    the banner text starting with "✨ cua-driver v0.1.4 is available (you have
    v0.1.3)." and add a language specifier (e.g., text) to the opening fence so the block becomes text ... ``` to enable proper syntax highlighting and
    silence the markdownlint warning.

</details>

---

<details>
<summary>ℹ️ Review info</summary>

<details>
<summary>⚙️ Run configuration</summary>

**Configuration used**: Organization UI

**Review profile**: CHILL

**Plan**: Pro

**Run ID**: `4a30011d-fff7-4cc6-a414-978e9334bf4e`

</details>

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 5e27549541ef55e8d466bd18e9d82baf363bbfbf and 5f2753b212b49f5b6019cf6fb4b4d29214bb6585.

</details>

<details>
<summary>⛔ Files ignored due to path filters (1)</summary>

* `libs/cua-driver-rs/Cargo.lock` is excluded by `!**/*.lock`

</details>

<details>
<summary>📒 Files selected for processing (7)</summary>

* `docs/content/docs/cua-driver/guide/getting-started/installation.mdx`
* `docs/content/docs/cua-driver/reference/cli-reference.mdx`
* `libs/cua-driver-rs/PARITY.md`
* `libs/cua-driver-rs/crates/cua-driver/Cargo.toml`
* `libs/cua-driver-rs/crates/cua-driver/src/cli.rs`
* `libs/cua-driver-rs/crates/cua-driver/src/main.rs`
* `libs/cua-driver-rs/crates/cua-driver/src/version_check.rs`

</details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->

- installation.mdx: expand the list of subcommands that skip the banner
  (add `mcp-config`, `update`, `stop`, `status`, `recording`, `config`,
  `diagnose`, `telemetry install-event`) so the doc matches the actual
  call-site enumeration.
- cli-reference.mdx / mcp-tools.mdx: regenerate against current Swift
  source. (The previous file diverged from the generator output for the
  same reason flagged in #1522 — accumulated drift from version bumps +
  upstream docstring edits.) Side-effect: the standalone "Startup banner"
  prose the previous agent added to the auto-generated cli-reference.mdx
  is now gone; the user-facing docs for this feature live in
  installation.mdx where edits survive regen.
- PARITY.md: add `text` language specifier to the example banner code
  fence (MD038 lint fix).
@f-trycua
f-trycua merged commit 5eaaabb into main May 17, 2026
6 of 8 checks passed
@f-trycua
f-trycua deleted the feat/cua-driver-rs-update-banner-1535 branch May 17, 2026 08:10
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.

cua-driver-rs: surface 'new version available' banner with one-line update instructions

1 participant