Skip to content

feat(updater): restart-to-update sidebar row with per-channel escalation#2381

Open
harshitsinghbhandari wants to merge 5 commits into
AgentWrapper:mainfrom
harshitsinghbhandari:ao/agent-orchestrator-26/restart-to-update-row
Open

feat(updater): restart-to-update sidebar row with per-channel escalation#2381
harshitsinghbhandari wants to merge 5 commits into
AgentWrapper:mainfrom
harshitsinghbhandari:ao/agent-orchestrator-26/restart-to-update-row

Conversation

@harshitsinghbhandari

Copy link
Copy Markdown
Collaborator

What

Implements T2 and T3 of the staged-update escalation work:

  • Extends UpdateStatus with optional stagedAt (epoch ms) and escalated fields, present on the downloaded state.
  • Adds a pure evaluateEscalation() function (frontend/src/main/escalation-evaluator.ts) with 8 unit tests.
  • Wires a 30-minute unref'd setInterval in auto-updater.ts that re-evaluates escalation after each update-downloaded and rebroadcasts the status.
  • Adds a "Restart to update" row in the sidebar footer, directly above Settings, in both expanded and collapsed (icon rail) variants. Clicking calls updates.install(); no confirmation dialog, the row itself is the prompt. Zero footprint unless an update is downloaded.

Escalation rules

Channel Escalates when
latest now - stagedAt >= 48h
nightly feed important: true on the staged release yml, OR semver.lt(runningVersion, latestStableVersion) (skipped if stable version could not be fetched)

Feed data comes from read-only fetches of the GitHub release yml files (owner/repo regex-parsed from the bundled app-update.yml, platform suffix per the feed.mjs convention, 10s abort timeout). Every failure is silent: this path never broadcasts an error state (see #2270) and dev builds skip it entirely, so escalated stays false outside the packaged app. No yaml dependency; regex on flat keys is deliberate.

UI

  • Fresh: transparent row inheriting the sidebar background, passive label plus small neutral dot, Settings-row hover treatment.
  • Escalated: orange text and dot reusing the --orange / bg-working tokens, with a subtle color-mix orange fill and border matching the existing styles.css idiom.
  • Collapsed rail: icon-only RefreshCw button with both lines in the tooltip.

Verification

  • npm run typecheck: clean.
  • Full vite builds of all three bundles (vite.main.config.ts, vite.preload.config.ts, vite.renderer.config.ts, there is no aggregate build script in frontend/package.json): all exit 0.
  • npm test: 383/383 tests pass across 41 files, including the 8 new escalation-evaluator tests (stable under/at/over 48h, nightly important, nightly behind stable 0.10.4 vs ahead of 0.10.3, missing stable info, unparseable versions).

Notes

  • The important feed key ships separately (publish side is a sibling PR); until then the key is absent from nightly release ymls and reads as false, so nightly escalation relies only on the behind-stable semver check.
  • New direct dependency: semver (plus @types/semver dev). It was previously only transitive.

Part of #2377.

🤖 Generated with Claude Code

harshitsinghbhandari and others added 5 commits July 3, 2026 20:07
Adds two optional fields to the UpdateStatus downloaded variant so the
main process can advertise how long an update has been staged and
whether per-channel rules consider it overdue. Adds semver as a direct
dependency for the upcoming escalation evaluator.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
latest channel escalates after 48h staged. nightly escalates on the
important feed flag or when the running version is behind the latest
stable release (semver). Missing stable info or unparseable versions
never escalate. 8 unit tests in the update-settings test style.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… process

On update-downloaded, records the staged version and stagedAt, then
runs the evaluator immediately and every 30 minutes (unref'd interval)
while the update sits uninstalled. Feed data (latest stable version,
nightly important flag) comes from read-only GitHub release yml fetches
regex-parsed for flat keys; every failure is silent and this path never
broadcasts an error state (issue AgentWrapper#2270). Skipped entirely in dev builds.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Renders only when an update is downloaded and staged: transparent with
passive text while fresh, orange (working tokens plus color-mix fill
and border) once the main-process evaluator flags it escalated. The
expanded row shows Restart to update over a v{version} ready sub-line;
the collapsed icon rail gets a RefreshCw button with the same copy in
its tooltip. Clicking installs immediately; the row is the prompt.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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