Repository navigation
Conversation
There was a problem hiding this comment.
The fix works for the scenario in #58141. Run from source, the base attaches two different OPENCODE_CONFIG_DIR profiles (and the default) to a single service. With this PR each profile gets its own service and port, and service stop on one leaves the other running. The new and changed service tests and tsc -b were run: the existing lifecycle failures also happen on the base, but the new end-to-end test failed here (see inline).
This is also a design change. The bot's reply on #58141 says one shared service per user is the documented v2 behaviour and marks the issue as a feature request, so maintainers should confirm that one service per config dir is the direction they want, rather than the server using the client's env or a warning on mismatch. A different XDG_DATA_HOME/XDG_STATE_HOME, which the issue also mentions, isn't handled.
Public API: no SDK, HTTP, plugin or config-schema changes. The behaviour around the OPENCODE_CONFIG_DIR environment variable does change:
- Registration file: for any non-default config dir,
$XDG_STATE_HOME/opencode/service.json→service-<hash>.json(service-<channel>.json→service-<channel>-<hash>.json). - Default port: 49374 (or the channel port) → a hash-derived port between 10000 and 59999.
- Spawned service: its env now always includes
OPENCODE_CONFIG_DIR.
This isn't backwards compatible for people who already use one custom OPENCODE_CONFIG_DIR for everything:
- Their running service and its
service.jsonare no longer found, because migration is skipped. It stays running on 49374, unreachable byservice stop, and a second server starts. - Clients that rely on the default
service.json, such as the promise client'sfallback()inpackages/client/src/service-probe.ts, won't see the profile's service.
The upgrade path needs handling (see inline).
3392451 to
ab283d9
Compare
There was a problem hiding this comment.
The new commit addresses all three earlier points. I checked the upgrade case by starting a service with the base build under one custom OPENCODE_CONFIG_DIR, then running this branch. service status found the existing service through the moved registration, service stop stopped it, and the next service start used the profile's own port. A second profile still got its own service. Profile ports now stay in 10000–32767, below the Linux range for outgoing connections and the Windows remap. The flaky end-to-end test is gone. test/service.test.ts (26 pass) and tsc -b pass.
Public API: unchanged since the last review. When OPENCODE_CONFIG_DIR points to a non-default directory, the registration file becomes service[-<channel>]-<hash>.json and the default port is derived from the directory (10000–32767). An existing service.json registration is moved over when its password matches the profile's saved one, so existing single-profile setups keep their running service.
No new concerns.
Derive the managed service registration filename in global state and the default service port from the resolved OPENCODE_CONFIG_DIR path when a non-default config directory is active, and propagate the canonicalized config path into the spawned service environment before changing to the home directory. Profile ports stay below 32768 so they never overlap the ephemeral port range. An existing unhashed service registration is adopted by the profile only when its password matches the one stored in that profile's config, so users who set one custom OPENCODE_CONFIG_DIR keep their running service across the upgrade instead of orphaning it. Previously, all profiles shared ~/.local/state/opencode/service.json and port 49374, causing secondary OPENCODE_CONFIG_DIR launches to attach to the first profile's background server and inherit its config and environment. Fixes anomalyco#58141
ab283d9 to
73e9a3f
Compare
|
Rebased onto current The only conflict was with #58331. A dev build still gets its own service. A non-default @Hona the triage on #58141 called this a feature request and asked for a direction: one service per config dir (this PR), the server scoping to the client env, or a warning on mismatch. Happy to change course if one service per config dir is not what you want. |
There was a problem hiding this comment.
The rebase onto the latest dev keeps the fix working, and the merge with the new dev-channel split and processEnv is consistent. Released channels share one hashed registration and port per config dir. A dev build with a custom config dir gets its own service-dev-<hash>.json. The spawned service's env still includes OPENCODE_CONFIG_DIR while XDG_STATE_HOME is still removed from it.
I re-ran the earlier checks from source. Two custom config dirs get separate services and stop independently, while the base attaches both to one service. Upgrading from a base-started service under one custom config dir still moves its registration, so service status and service stop reach it. test/service.test.ts (29 pass) and tsc -b pass.
Public API: same as the last review. With a non-default OPENCODE_CONFIG_DIR, the registration becomes service[-<channel>]-<hash>.json and the default port is derived from the directory (10000–32767). An existing registration is moved over when its password matches the profile's saved one.
No new concerns.
Issue for this PR
Closes #58141
Type of change
What does this PR do?
Previously, the managed background service registered a single per-user state file (
~/.local/state/opencode/service.json) and bound a single default port (49374/0xc0de) regardless ofOPENCODE_CONFIG_DIR. Launching a second profile with a differentOPENCODE_CONFIG_DIR(and profile-specific environment variables) discovered and attached to the first profile's background server instead of starting its own.This change:
OPENCODE_CONFIG_DIRresolves to a non-default config directory (ServiceConfig.activeProfile()).global.state(service-<hash>.json/service-<channel>-<hash>.json) and a profile-specific default port (ServiceConfig.defaultPort) from the resolvedOPENCODE_CONFIG_DIRpath, while keeping the default profile (service.jsonand port49374) unchanged.OPENCODE_CONFIG_DIRbeforeServerProcesschanges directory to$HOMEand passes it inServiceConfig.options().envso spawned background services and CLI commands (service start,status,restart,stop) consistently resolve the same profile.How did you verify your code works?
packages/cli/test/service.test.tscovering per-profile port derivation, registration filename derivation, andServiceConfig.options()isolation in a shared state directory.packages/cli/test/service.test.tsverifying that twoOPENCODE_CONFIG_DIRprofiles start on distinct ports, report independentservice status, and stop independently without affecting each other.bun test test/service.test.tsandbun run check.Screenshots / recordings
N/A
Checklist
Added by the opencode bot (AI-generated).
Related: #56708, #42690, #52891
Public API: with a non-default OPENCODE_CONFIG_DIR, the background service uses a per-profile registration file and a derived default port (existing registrations are migrated when the saved password matches)