From c65f90ee09fd9d9d3c89a2eaf4892a0a3ef62476 Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Mon, 27 Apr 2026 13:51:16 +0900 Subject: [PATCH] fix(tmux): preserve configured fallback port Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus --- src/features/tmux-subagent/manager.test.ts | 73 +++++++++++++++++----- src/features/tmux-subagent/manager.ts | 3 +- 2 files changed, 60 insertions(+), 16 deletions(-) diff --git a/src/features/tmux-subagent/manager.test.ts b/src/features/tmux-subagent/manager.test.ts index e63f4bf4d..11724d1a6 100644 --- a/src/features/tmux-subagent/manager.test.ts +++ b/src/features/tmux-subagent/manager.test.ts @@ -3,7 +3,7 @@ import { describe, test, expect, mock, beforeEach, spyOn, afterAll } from 'bun:t import type { TmuxConfig } from '../../config/schema' import type { WindowState, PaneAction } from './types' import type { ActionResult, ExecuteContext } from './action-executor' -import type { TmuxUtilDeps } from './manager' +import type { TmuxSessionManager as TmuxSessionManagerType, TmuxUtilDeps } from './manager' import * as sharedModule from '../../shared' type ExecuteActionsResult = { @@ -287,24 +287,67 @@ describe('TmuxSessionManager', () => { 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 = createTmuxConfig({ enabled: true, - layout: 'main-vertical', - main_pane_size: 60, - main_pane_min_width: 80, - agent_pane_min_width: 40, }) + const previousOpenCodePort = process.env.OPENCODE_PORT + delete process.env.OPENCODE_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 - const manager = new TmuxSessionManager(ctx, config, mockTmuxDeps) + // 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') }) + + test('falls back to configured OPENCODE_PORT when serverUrl has port 0', async () => { + // given + const previousOpenCodePort = process.env.OPENCODE_PORT + process.env.OPENCODE_PORT = '5678' + 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:5678') + }) }) describe('onSessionCreated', () => { @@ -1989,7 +2032,7 @@ describe('TmuxSessionManager', () => { const cleanupPromise = manager.cleanup() // then - await expect(cleanupPromise).resolves.toBeUndefined() + expect(await cleanupPromise).toBeUndefined() expect(mockKillTmuxSessionIfExists).toHaveBeenCalledTimes(1) }) }) diff --git a/src/features/tmux-subagent/manager.ts b/src/features/tmux-subagent/manager.ts index a8d93ca16..3340fb55d 100644 --- a/src/features/tmux-subagent/manager.ts +++ b/src/features/tmux-subagent/manager.ts @@ -72,7 +72,8 @@ export class TmuxSessionManager { this.client = ctx.client this.tmuxConfig = tmuxConfig this.deps = deps - const fallbackUrl = "http://localhost:4096" + const defaultPort = process.env.OPENCODE_PORT ?? "4096" + const fallbackUrl = `http://localhost:${defaultPort}` const rawServerUrl = ctx.serverUrl?.toString() try { if (rawServerUrl) {