From acf293de96d1d0e83fbfc7d16cb4f8da5d9f727f Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Mon, 27 Apr 2026 14:24:42 +0900 Subject: [PATCH] fix(tmux): validate fallback port Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus --- src/features/tmux-subagent/manager.test.ts | 32 ++++++++++++++++++++++ src/features/tmux-subagent/manager.ts | 6 +++- 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/src/features/tmux-subagent/manager.test.ts b/src/features/tmux-subagent/manager.test.ts index 11724d1a6..943f246fb 100644 --- a/src/features/tmux-subagent/manager.test.ts +++ b/src/features/tmux-subagent/manager.test.ts @@ -348,6 +348,38 @@ describe('TmuxSessionManager', () => { // then expect((manager as any).serverUrl).toBe('http://localhost:5678') }) + + test('ignores invalid OPENCODE_PORT when serverUrl has port 0', async () => { + // given + const previousOpenCodePort = process.env.OPENCODE_PORT + process.env.OPENCODE_PORT = 'not-a-port' + let manager: TmuxSessionManagerType | undefined + try { + mockIsInsideTmux.mockReturnValue(true) + const { TmuxSessionManager } = await import('./manager') + const ctx = { + ...createMockContext(), + serverUrl: new URL('http://127.0.0.1:0/'), + } + const config = createTmuxConfig({ enabled: true, + layout: 'main-vertical', + main_pane_size: 60, + main_pane_min_width: 80, + agent_pane_min_width: 40, }) + + // when + manager = new TmuxSessionManager(ctx, config, mockTmuxDeps) + } finally { + if (previousOpenCodePort === undefined) { + delete process.env.OPENCODE_PORT + } else { + process.env.OPENCODE_PORT = previousOpenCodePort + } + } + + // 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 3340fb55d..353bdffec 100644 --- a/src/features/tmux-subagent/manager.ts +++ b/src/features/tmux-subagent/manager.ts @@ -72,7 +72,11 @@ export class TmuxSessionManager { this.client = ctx.client this.tmuxConfig = tmuxConfig this.deps = deps - const defaultPort = process.env.OPENCODE_PORT ?? "4096" + const configuredPort = process.env.OPENCODE_PORT + const parsedPort = configuredPort ? Number(configuredPort) : 4096 + const defaultPort = Number.isInteger(parsedPort) && parsedPort > 0 && parsedPort <= 65535 + ? String(parsedPort) + : "4096" const fallbackUrl = `http://localhost:${defaultPort}` const rawServerUrl = ctx.serverUrl?.toString() try {