Repository navigation
fix(desktop): preserve CLI service channels - #60683
jerome-benoit wants to merge 8 commits into
Conversation
Preserve the raw CLI channel for service registration while normalizing only the Desktop app identity. Keep existing prod configuration and state. Closes anomalyco#60676
Nix integration verification (
|
There was a problem hiding this comment.
The fix works from source. I started a prod-channel CLI (OPENCODE_CHANNEL="prod", serve --service) with isolated XDG directories, then looked the service up the way Desktop does. On the base nothing is found, and fallback() always points at service.json. With this PR, fallback("prod") resolves to service-prod.json and Service.discover({ file }) finds the running service. latest, dev, beta and next still map to service.json, so official builds keep the same registration file. The Electron app itself was not built or launched.
The nearby desktop, client and CLI service tests pass. tsc passes for all three packages.
Public API: @opencode/client adds registrationFilename(channel). fallback() gains an optional channel argument that defaults to latest, so existing callers are unaffected. Both changes are additive and backwards compatible. Desktop's staged CLI directories under userData are now named <version>-<arch>-<channel>, so each user re-stages once after upgrading. Legacy stages that an adopted service may still run from are kept.
One non-blocking point is noted inline. With a prebuilt CLI and no OPENCODE_CHANNEL, Desktop assumes dev, but the CLI build takes its channel from the git branch name.
| } | ||
|
|
||
| export function resolveCliChannel(built: boolean) { | ||
| return built ? process.env.OPENCODE_CHANNEL || "dev" : resolveChannel() |
There was a problem hiding this comment.
When OPENCODE_CHANNEL is unset, this assumes the prebuilt CLI is dev. packages/script builds the CLI with the git branch name as its channel instead (or latest when a release OPENCODE_VERSION is set). On a feature branch the CLI then registers service-<branch>.json, while Desktop looks in service.json, which is the same mismatch this PR fixes for Nix. The base has the same gap, so this isn't a regression. It would hold up better to read the channel from the built CLI's own metadata, or to fail when packages/cli/dist is used without an explicit OPENCODE_CHANNEL.
There was a problem hiding this comment.
Set OPENCODE_CHANNEL explicitly to the value used to build a prebuilt CLI. Missing or empty values are rejected before resource preparation. Downloaded CLIs retain the dev/beta fallback; explicit custom channels remain unchanged.
The rejection cases fail before the fix and pass after it. Desktop service/build-policy tests: 280 passed across ten runs. The real build entrypoint was exercised in an isolated workspace: both invalid cases stop before any resources or output are created.
Implementation: 36cfa45.
Prebuilt CLI manifests do not record their channel. Reject missing OPENCODE_CHANNEL before preparing Desktop build resources.
There was a problem hiding this comment.
The new commit fixes my earlier point. A Desktop build with a prebuilt CLI now fails when OPENCODE_CHANNEL is unset or empty, instead of assuming dev. The new test cases cover this, and the Desktop tests (28) and tsc -b pass. The release workflow and the Nix build both set the channel, so neither should hit the new error. The discovery fix itself is unchanged since my last review. Public API: nothing new beyond the backwards-compatible client additions noted before. No new concerns.
There was a problem hiding this comment.
The merge with upstream dev keeps the fix. I re-ran the from-source reproduction: a prod-channel CLI registers service-prod.json, and Desktop's lookup now finds it (latest still maps to service.json). The Desktop (46) and client (8) tests and tsc pass. My earlier point about prebuilt CLIs without OPENCODE_CHANNEL was fixed in 36cfa45, and the merge doesn't change that. Public API: no change since the last review. One small new point from the merge is noted inline.
packages/desktop/src/main/service/background-service.ts:49: Upstream took the probe beforeprepare()so that the result is used only once. Nowprepare()(which resolves the CLI and can fail, e.g. a stage copy blocked by antivirus) runs first. If it fails,takeSidecarProbeis never called and the boot-time probe stays stored. The next initial attempt can then adopt a service that may have exited since launch, which is what the comment ontakeSidecarProbeis meant to prevent. The check that follows would still replace a dead service, so this is minor. Taking the probe first and comparing its file afterprepare()would keep both properties.
|
Fixed in 9077bab. |
There was a problem hiding this comment.
The new commit fixes my earlier point about the probe order: the boot-time probe is now taken before the CLI is prepared, and the state-directory check still applies. bun run test in packages/desktop passes, as does tsc -b. Public API: no change since the last review.
The new test is worth reworking. It replaces electron and @opencode/client/service for the whole test process. Without the new --isolate flag, those replacements leak into other test files and break 3 of them. Details are inline.
| Object.defineProperty(process, "resourcesPath", { value: resources, configurable: true }) | ||
| writeFileSync(path.join(resources, "opencode-cli.version"), "1.0.0\n") | ||
|
|
||
| mock.module("electron", () => ({ |
There was a problem hiding this comment.
mock.module("electron") and mock.module("@opencode/client/service") apply to the whole test process, and the file also overrides process.resourcesPath at module scope. That's why package.json now runs the entire Desktop suite with --isolate. Without it, bun test --timeout 30000 fails 3 tests in other files ("Missing 'default' export in module .../electron/index.js"). With this file removed, the suite passes without --isolate. The test only checks that takeSidecarProbe() returns its result once, which the five-line function already shows. Please drop this test and the --isolate change so the fix stays small and the test runner stays as it was.
|
Dropped in ae2858f, per the inline point on |
There was a problem hiding this comment.
The new commit removes the mocked probe test, and the Desktop suite now passes without --isolate (bun test --timeout 30000: 0 failures). The --isolate flag that was added for that test is still in the Desktop test script in packages/desktop/package.json. Please revert it so the test runner stays as it was. Public API: no change since the last review.
|
Correction on my previous comment: commit |
Issue for this PR
Closes #60676
Type of change
What does this PR do?
Keep Desktop service discovery aligned with the bundled CLI's build channel. Official
latestbuilds useservice.json; Nixprodbuilds useservice-prod.json. Nix Desktop also requires the dependency-packaging changes in #59403.How did you verify your code works?
6b0567d: full Desktop package suite 578 passed / 0 failed on the base runner script; rootbun run checkpasses (lint with warnings, 34/34 typecheck tasks).tsc). Earlier review rounds: 28 service/build-policy tests repeated ten times passed, and the missing/empty prebuilt-channel cases fail before the fix and pass after it.Service.ensurepassed.Combined Nix runtime verification covers
122ead5+d8dde3e, not the current Desktop head. No fresh combined Nix build was run. Windows/ARM/macOS runtimes are untested. Port-change recovery requires a renderer reload; baseline regression status is unverified.Checklist
Added by the opencode bot (AI-generated).
Related: #52121, #59601
Public API: adds registrationFilename() and an optional channel argument to fallback() in @opencode/client/service (backwards compatible)