From 0810e37240115c5efbfb2fccf95a24834fb2f495 Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Mon, 23 Mar 2026 18:09:31 +0900 Subject: [PATCH] fix: validate serverUrl port before tmux pane spawn (fixes #2729) --- src/features/tmux-subagent/manager.test.ts | 23 ++++++++++++++++++++++ src/features/tmux-subagent/manager.ts | 12 +++++++++-- 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/src/features/tmux-subagent/manager.test.ts b/src/features/tmux-subagent/manager.test.ts index 976871982..f252b3efe 100644 --- a/src/features/tmux-subagent/manager.test.ts +++ b/src/features/tmux-subagent/manager.test.ts @@ -226,6 +226,29 @@ describe('TmuxSessionManager', () => { // then expect(manager).toBeDefined() }) + + test('falls back to default port when serverUrl has port 0', async () => { + // given + mockIsInsideTmux.mockReturnValue(true) + const { TmuxSessionManager } = await import('./manager') + const ctx = { + ...createMockContext(), + serverUrl: new URL('http://127.0.0.1:0/'), + } + const config: TmuxConfig = { + enabled: true, + layout: 'main-vertical', + main_pane_size: 60, + main_pane_min_width: 80, + agent_pane_min_width: 40, + } + + // when + const manager = new TmuxSessionManager(ctx, config, mockTmuxDeps) + + // then + expect((manager as any).serverUrl).toBe('http://localhost:4096') + }) }) describe('onSessionCreated', () => { diff --git a/src/features/tmux-subagent/manager.ts b/src/features/tmux-subagent/manager.ts index 27909db71..ca329ac3c 100644 --- a/src/features/tmux-subagent/manager.ts +++ b/src/features/tmux-subagent/manager.ts @@ -73,10 +73,18 @@ export class TmuxSessionManager { this.tmuxConfig = tmuxConfig this.deps = deps const defaultPort = process.env.OPENCODE_PORT ?? "4096" + const fallbackUrl = `http://localhost:${defaultPort}` try { - this.serverUrl = ctx.serverUrl?.toString() ?? `http://localhost:${defaultPort}` + const raw = ctx.serverUrl?.toString() + if (raw) { + const parsed = new URL(raw) + const port = parsed.port || (parsed.protocol === 'https:' ? '443' : '80') + this.serverUrl = port === '0' ? fallbackUrl : raw + } else { + this.serverUrl = fallbackUrl + } } catch { - this.serverUrl = `http://localhost:${defaultPort}` + this.serverUrl = fallbackUrl } this.sourcePaneId = deps.getCurrentPaneId() this.pollingManager = new TmuxPollingManager(