Skip to content

LOCAL: let a managed server link its update instructions - #17

Merged
kiwidream merged 1 commit into
swaplabs/mainfrom
swaplabs/server-update-help-url
Sep 28, 2026
Merged

kiwidream merged 1 commit into
swaplabs/mainfrom
swaplabs/server-update-help-url

Conversation

@kiwidream

@kiwidream kiwidream commented Sep 28, 2026 •

Copy link
Copy Markdown
Files Added Deleted Net
Test 7 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​730 0 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​730
Prod 14 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​151 $\color{#cf222e}{\Huge{\mathbf{−}}}$​8 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​143

ELI5

When a server can't update itself, Orca tells you to update it "through the service manager". On our dev VMs that advice is wrong. Ansible installs a pinned Orca build there, so an update done by hand is undone at the next run. This lets the server give a link to its real update instructions, and the desktop shows that link.

What Changed

Before: a paired Linux orca serve host with an update available shows "Update Orca on the server host… through the service manager that starts it" in the update dialog and in the Settings server row.

After: if the host was started with ORCA_SERVER_UPDATE_HELP_URL=https://…, those two places instead say "Updates for this server are managed by its deployment." and add a How to update link. The link opens in the external browser. Hosts without the variable look exactly as before.

How:

  • Host: reads the variable once at startup (src/main/updater/server-update-help-url-env.ts). It accepts only an absolute https: URL of at most 2048 characters with no control characters, and otherwise logs one warning and ignores it. It adds the URL as an optional helpUrl on RemoteServerUpdateSupport, and only when it reports manual-service-update-required. When the variable is unset, the key is left out entirely, so what the host sends is byte-identical to today.
  • Client: readRemoteServerUpdateSupport checks the value again with the same parser where the status reply is read. A malformed helpUrl is dropped without dropping the rest of the status.

Why

  • Why a configured link: the host is the only side that knows who manages its install, and the link is something an operator can point at their own instructions. The alternative was hard-coding a "managed" flag or SwapLabs text into the client, which would put deployment knowledge in the desktop app.
  • Why the old/new mix is safe: clients and hosts update separately, so this follows docs/reference/remote-wire-compatibility.md: it is a new optional field on an existing message. There is no new opcode or RPC, and no capability flag is needed. Old clients ignore the field and new clients treat a missing or invalid value as absent. Nothing on the path rejects unknown fields: the CLI passes the status through whole, and mobile's parser allows extra fields and doesn't read this one.

Linked Issue

None. This is fork-only (LOCAL:). The host-side setting that uses it is in SwapLabsInc/SwapLabs#114 (devvms), for fork hosts only.

Visual Proof

Not attached. A hidden-renderer Playwright check (Electron headless, ORCA_BACKGROUND_LAUNCH=1) of the update dialog passed in dark and light themes. It showed the managed text and link, a click reached a stubbed shell:openUrl with the URL, the window didn't navigate, and a host without helpUrl showed today's text. The Settings server row was checked only in unit tests.

Testing

  • pnpm tc passes.

  • pnpm test passes on the new, touched and existing updater, remote-server-update, i18n and CLI-transport suites: 67 files and 695 tests passed, with 1 file and 14 tests skipped. I re-ran the 7 new test files myself: 82 tests passed.

  • oxlint and check:code-quality:changed are clean, and the four verify:localization-* scripts pass.

  • What the tests cover:

    • Variable parsing: a valid https URL is accepted; http, relative, control-character and over-long values are rejected.
    • What the host sends: helpUrl is present only when updates are manual and the value is valid.
    • Old/new versions: an old host (no field) and a malformed value both produce today's text.
    • UI: the dialog and the server row, with and without a link.
  • Not tested:

    • a real old client or a real headless host with the variable set;
    • macOS or Windows (the change is platform-neutral; only Linux hosts report manual updates today).
  • I manually tested these changes locally

  • Automated tests added/updated, or explained why not below

AI Disclosure

Written by Claude (Fable 5.1 as the implementing worker; Opus 5.5 coordinating and reviewing).

Review

Agent skill upstream boundary

  • Not applicable, or this change follows docs/reference/agent-skill-sharing-upstream-boundary.md and copies or mechanically translates no upstream skill-installer source, tests, fixtures, registry entries, path tables, comments, or documentation.

Notes

  • Focus: when a host with a link is listed above one that can update itself, the link becomes the dialog's first focusable element and takes default focus.
  • Docs: the variable isn't documented in docs/ yet.

Checklist

  • This PR is small and focused
  • I explained what changed and why (ELI5, the user-facing before/after, the mechanism, and why over the alternatives)
  • Before/after screenshots or videos attached for UI changes, or N/A with reason
  • Self-reviewed for correctness, security, and performance
  • Cross-platform, SSH/remote, and path/shortcut impact considered (or N/A)
  • pnpm lint, pnpm typecheck, pnpm test, and pnpm build pass (or CI will cover; local preferred)

🤖 Generated with Claude Code


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.

A headless Linux `orca serve` host cannot install its own updates, so a
paired desktop tells the user to update it through its service manager.
On a host whose install is owned by its deployment that advice is wrong:
the next converge restores the pinned build.

The host now reads ORCA_SERVER_UPDATE_HELP_URL once at startup. When it is
an absolute https URL of at most 2048 characters with no control
characters, and the host reports `manual-service-update-required`, the
remote-update support carries it as an optional `helpUrl`. Anything else
is ignored with one warning, and an unset variable leaves the wire
byte-identical to before.

The client re-validates the value with the same parser where it reads the
status reply, dropping a malformed link without losing the rest of the
support. The update dialog and the settings server row then show that the
deployment manages updates, with a "How to update" link that opens in the
external browser. A host that publishes no link renders exactly as before.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@tenki-reviewer

tenki-reviewer Bot commented Sep 28, 2026 •

Copy link
Copy Markdown

Review complete. No blocking issues — approved ✅; 1 nitpick below.

🧹 Nitpicks (1) — 🟢 1 low
  • 🟢 Padded helpUrl passes validation untrimmed (remote-server-update-help-url.ts:17) — parseServerUpdateHelpUrl rejects control characters because the URL parser strips them, but the parser likewise strips leading/trailing spaces while the raw untrimmed value is returned (src/shared/remote-server-update-help-url.ts:33).

Adds a deployment-managed help link to the remote server update flow, with no significant issues found.

Reviewed commit: 1714bc2

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 28, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-09-28T14:40:51.907984Z 1714bc2 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

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