Skip to content

feat(settings): add OpenCode update action#585

Open
pascalandr wants to merge 3 commits into
NeuralNomadsAI:devfrom
pascalandr:feat/opencode-update-settings
Open

feat(settings): add OpenCode update action#585
pascalandr wants to merge 3 commits into
NeuralNomadsAI:devfrom
pascalandr:feat/opencode-update-settings

Conversation

@pascalandr

@pascalandr pascalandr commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Summary

  • add an OpenCode update card to the OpenCode settings section
  • show the installed version and a versioned update button only when npm advertises a newer release
  • run the upgrade through the generated OpenCode SDK against a ready instance using the configured binary
  • keep running instances uninterrupted; newly started instances use the installed version
  • localize loading, unavailable-instance, success, and failure states across all supported locales

Server behavior

  • resolve the selected binary with the existing binary probe
  • check opencode-ai/latest with a 10-second timeout and a five-minute cache
  • require a ready workspace using that exact binary before enabling the upgrade
  • invoke client.global.upgrade({ target }) rather than assembling an OpenCode API request manually
  • return stable error codes without exposing server details

Validation

  • pm run typecheck in packages/server
  • pm run typecheck in packages/ui
  • ode --import tsx --test src/opencode-update/service.test.ts
  • pm run build in packages/ui
  • pm run build in packages/server
  • git diff --check

The local OpenCode version and npm latest version were both 1.17.18, confirming the up-to-date state hides the update action.

Show the installed OpenCode version in the OpenCode settings section and expose an update button only when the npm registry advertises a newer release. The button includes the target version and reports loading, success, unavailable-instance, and failure states in every supported locale.

Resolve the configured binary version on the server, cache registry checks for five minutes, and invoke the generated OpenCode SDK global upgrade command through a running instance that uses the same binary. Existing instances remain uninterrupted while newly started instances use the installed update.

Cover update detection, cache reuse, SDK target selection, and missing-instance behavior with focused service tests. Validated with server and UI typechecks plus full UI and server builds.
@github-actions

Copy link
Copy Markdown

PR builds are available as GitHub Actions artifacts:

https://github.com/NeuralNomadsAI/CodeNomad/actions/runs/29257301316

Artifacts expire in 7 days.
Artifacts:

  • pr-585-18c9ca86fee663d3a2866a3f06d161eed266c744-tauri-macos
  • pr-585-18c9ca86fee663d3a2866a3f06d161eed266c744-electron-macos
  • pr-585-18c9ca86fee663d3a2866a3f06d161eed266c744-tauri-windows
  • pr-585-18c9ca86fee663d3a2866a3f06d161eed266c744-tauri-macos-arm64
  • pr-585-18c9ca86fee663d3a2866a3f06d161eed266c744-tauri-linux
  • pr-585-18c9ca86fee663d3a2866a3f06d161eed266c744-electron-linux
  • pr-585-18c9ca86fee663d3a2866a3f06d161eed266c744-electron-windows

@pascalandr pascalandr left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Gatekeeper review: CHANGES REQUIRED

Findings

  1. High: arbitrary binary probing through GET is unsafe on Windows. packages/server/src/server/routes/opencode-update.ts:11-12,27-30 accepts an arbitrary binary query parameter and packages/server/src/opencode-update/service.ts:39-42,86-90 executes it with --version. .cmd paths are interpolated into a cmd.exe /c command line by packages/server/src/workspaces/spawn.ts:82-91, so crafted quotes/metacharacters can become command injection. Because the session cookie is SameSite=Lax, a cross-site top-level GET can carry authentication. Resolve only persisted/validated binaries server-side and do not expose command execution through a parameterized GET.

  2. High: the normal Windows npm installation cannot show status or update. The service probes the raw configured value, normally opencode, while workspace launch first resolves it with where. Reproduced locally: opencode --version returns 1.17.18, but probeBinaryVersion("opencode") returns spawnSync opencode ENOENT; where resolves opencode.cmd. Status and upgrade must use the same canonical resolution as workspace startup.

  3. High: upgrade inherits an unsuitable 10-second timeout. createInstanceClient applies AbortSignal.timeout(10_000) in packages/server/src/workspaces/instance-client.ts:42-46, and the upgrade uses that client at packages/server/src/opencode-update/service.ts:145-149. npm/Homebrew/Chocolatey/WSL upgrades routinely exceed ten seconds, potentially reporting failure during a still-running or partial installation. Use an upgrade-specific longer timeout and deterministic in-flight handling.

  4. Medium: success is not verified against the selected executable. The SDK result is trusted and the UI immediately declares the target version installed. Re-probe the canonical selected binary after upgrade and only report success when its actual version matches the target; otherwise a custom/portable binary may leave a different global installation updated.

  5. Medium: registry failure hides the locally installed version. Local probing and the npm request are combined into one failing status operation. Return the installed version independently and model update availability as unavailable when the registry cannot be reached.

  6. Medium: concurrent clients can launch overlapping package-manager upgrades. Add a per-canonical-binary in-flight guard that joins or rejects duplicate requests.

  7. Medium: WSL binary matching lowercases the Linux path suffix. packages/server/src/workspaces/manager.ts:81-86 lowercases the entire UNC path on Windows, although the Linux path portion is case-sensitive. Preserve Linux path casing when matching WSL binaries.

  8. Low: tests cover only mocked service behavior. Missing coverage includes route validation, Windows command resolution, timeout behavior, post-upgrade verification, concurrency, WSL identity, and UI states. The focused service test is also not wired into the current package/CI test scripts.

Residual context

All current CI builds are green or completing successfully, but they compile the feature without exercising the runtime paths above.

Verdict: CHANGES REQUIRED

Remove request-controlled binary paths from the update API and resolve the persisted OpenCode binary through the same canonical path logic used for workspace startup. Preserve WSL Linux path casing while retaining case-insensitive matching for Windows paths.

Allow the SDK upgrade call to run for up to ten minutes, coalesce concurrent upgrades per binary, and verify the selected executable reports the target version before returning success. Registry failures now preserve the installed version in settings, and stale completions cannot overwrite status after the selected binary changes.

Add service, route, Windows path, concurrency, verification, registry-failure, and WSL matching coverage. Validated with ten focused tests, server and UI typechecks, full UI and server builds, and a real Windows resolution from opencode to opencode.cmd.

@pascalandr pascalandr left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Gatekeeper follow-up: PASS

Commit 30c81867 resolves the blocking findings from the previous review:

  • removed request-controlled binary paths from both update endpoints;
  • resolved the persisted binary with the same canonical lookup used by workspace startup;
  • verified the Windows npm wrapper resolves from opencode to opencode.cmd and reports its version;
  • extended only the upgrade SDK call to a ten-minute timeout;
  • re-probed the configured executable after upgrade before reporting success;
  • preserved the installed version when the npm registry check fails;
  • coalesced concurrent upgrades per canonical binary;
  • preserved Linux path case when comparing WSL UNC binaries;
  • ignored stale upgrade completions after the configured binary changes;
  • added route, service, concurrency, verification, registry-failure, Windows-path, and WSL-path tests.

Validation completed locally:

  • 10 focused tests passed;
  • server typecheck passed;
  • UI typecheck passed;
  • UI build passed;
  • full server build passed;
  • real Windows resolution/probe passed for opencode.cmd.

Residual non-blocking gaps: there is no dedicated component test for the stale-completion transition, and the focused tests are not yet wired into a dedicated CI job. The full server suite produced 153 passes and one unrelated existing failure caused by the local Git default branch name.

Verdict: PASS

@github-actions

Copy link
Copy Markdown

PR builds are available as GitHub Actions artifacts:

https://github.com/NeuralNomadsAI/CodeNomad/actions/runs/29265271400

Artifacts expire in 7 days.
Artifacts:

  • pr-585-30c81867c7d58d929dea8caf39eeabc98eb2230d-tauri-macos
  • pr-585-30c81867c7d58d929dea8caf39eeabc98eb2230d-tauri-windows
  • pr-585-30c81867c7d58d929dea8caf39eeabc98eb2230d-tauri-macos-arm64
  • pr-585-30c81867c7d58d929dea8caf39eeabc98eb2230d-electron-macos
  • pr-585-30c81867c7d58d929dea8caf39eeabc98eb2230d-tauri-linux
  • pr-585-30c81867c7d58d929dea8caf39eeabc98eb2230d-electron-linux
  • pr-585-30c81867c7d58d929dea8caf39eeabc98eb2230d-electron-windows

1 similar comment
@github-actions

Copy link
Copy Markdown

PR builds are available as GitHub Actions artifacts:

https://github.com/NeuralNomadsAI/CodeNomad/actions/runs/29265271400

Artifacts expire in 7 days.
Artifacts:

  • pr-585-30c81867c7d58d929dea8caf39eeabc98eb2230d-tauri-macos
  • pr-585-30c81867c7d58d929dea8caf39eeabc98eb2230d-tauri-windows
  • pr-585-30c81867c7d58d929dea8caf39eeabc98eb2230d-tauri-macos-arm64
  • pr-585-30c81867c7d58d929dea8caf39eeabc98eb2230d-electron-macos
  • pr-585-30c81867c7d58d929dea8caf39eeabc98eb2230d-tauri-linux
  • pr-585-30c81867c7d58d929dea8caf39eeabc98eb2230d-electron-linux
  • pr-585-30c81867c7d58d929dea8caf39eeabc98eb2230d-electron-windows

@github-actions

Copy link
Copy Markdown

PR builds are available as GitHub Actions artifacts:

https://github.com/NeuralNomadsAI/CodeNomad/actions/runs/29331927591

Artifacts expire in 7 days.
Artifacts:

  • pr-585-c3377aa2cc0d070ee806a84a1644c7361c25184d-tauri-macos
  • pr-585-c3377aa2cc0d070ee806a84a1644c7361c25184d-electron-macos
  • pr-585-c3377aa2cc0d070ee806a84a1644c7361c25184d-tauri-windows
  • pr-585-c3377aa2cc0d070ee806a84a1644c7361c25184d-tauri-macos-arm64
  • pr-585-c3377aa2cc0d070ee806a84a1644c7361c25184d-tauri-linux
  • pr-585-c3377aa2cc0d070ee806a84a1644c7361c25184d-electron-linux
  • pr-585-c3377aa2cc0d070ee806a84a1644c7361c25184d-electron-windows

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