fix(team-mode): skip tmux layout when opencode server unreachable
`createManagers` unconditionally called `markServerRunningInProcess()` whenever `tmuxConfig.enabled` was true, which made `isServerRunning()` short-circuit to `true` for *any* serverUrl — bypassing the guard in `createTeamLayout` that is supposed to skip pane creation when the opencode server is not running. When a user launches vanilla `opencode` (no `opencode serve` / `opencode web`), `ctx.serverUrl` is undefined and the TmuxSessionManager falls back to `http://localhost:4096`. With the in-process flag set, the team layout proceeded to spawn tmux panes whose `opencode attach` commands then failed with "Unable to connect" — exactly the symptom in the bug report. Only mark the server as in-process running when the SDK actually provides `ctx.serverUrl`. When it does not, `isServerRunning()` falls back to a real HTTP probe, the existing guard in `createTeamLayout` returns null, and no panes are created. Closes #3894
This commit is contained in:
@@ -175,6 +175,28 @@ describe("createManagers", () => {
|
||||
expect(markServerRunningInProcess).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
|
||||
it("#given tmux is enabled but ctx.serverUrl is undefined #when managers are created #then it does NOT mark the server as running (issue #3894)", () => {
|
||||
// Vanilla `opencode` (no `opencode serve` / `opencode web`) leaves
|
||||
// ctx.serverUrl undefined. Marking the server as in-process running
|
||||
// would short-circuit isServerRunning() in createTeamLayout, letting
|
||||
// it spawn tmux panes whose `opencode attach` then fails because no
|
||||
// server is actually listening on the fallback port.
|
||||
const ctx = createContext("/tmp")
|
||||
const ctxWithoutServerUrl = { ...ctx, serverUrl: undefined as unknown as URL }
|
||||
const args = {
|
||||
ctx: ctxWithoutServerUrl,
|
||||
pluginConfig: OhMyOpenCodeConfigSchema.parse({}),
|
||||
tmuxConfig: createTmuxConfig(true),
|
||||
modelCacheState: createModelCacheState(),
|
||||
backgroundNotificationHookEnabled: false,
|
||||
deps: createDeps(),
|
||||
}
|
||||
|
||||
createManagers(args)
|
||||
|
||||
expect(markServerRunningInProcess).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it("#given openclaw is enabled #when the background session-created callback runs #then it dispatches openclaw with the tracked pane id", async () => {
|
||||
const args = {
|
||||
ctx: createContext("/tmp/project"),
|
||||
|
||||
@@ -57,7 +57,15 @@ export function createManagers(args: {
|
||||
const { ctx, pluginConfig, tmuxConfig, modelCacheState, backgroundNotificationHookEnabled } = args
|
||||
const deps = { ...defaultCreateManagersDeps, ...args.deps }
|
||||
|
||||
if (tmuxConfig.enabled) {
|
||||
// Only mark the server as in-process when the SDK actually exposes a
|
||||
// serverUrl. `tmuxConfig.enabled` alone is not proof of a running server —
|
||||
// a vanilla `opencode` session (no `opencode serve`/`opencode web`) leaves
|
||||
// `ctx.serverUrl` undefined, and marking it running would make
|
||||
// `isServerRunning` short-circuit to true. That bypasses the guard in
|
||||
// `createTeamLayout` and lets it spawn tmux panes whose `opencode attach`
|
||||
// command then fails because nothing is actually listening on the
|
||||
// fallback port (issue #3894).
|
||||
if (tmuxConfig.enabled && ctx.serverUrl) {
|
||||
deps.markServerRunningInProcessFn()
|
||||
}
|
||||
const tmuxSessionManager = new deps.TmuxSessionManagerClass(ctx, tmuxConfig)
|
||||
|
||||
Reference in New Issue
Block a user