From 166d6d9b5c4c51535c0a94d17e6123e721f4d89d Mon Sep 17 00:00:00 2001 From: nrslib <38722970+nrslib@users.noreply.github.com> Date: Wed, 11 Feb 2026 07:04:46 +0900 Subject: [PATCH] =?UTF-8?q?=E3=83=9D=E3=83=BC=E3=83=88=E7=AB=B6=E5=90=88?= =?UTF-8?q?=E5=9B=9E=E9=81=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/__tests__/engine-error.test.ts | 1 + src/infra/opencode/client.ts | 27 +++++++++++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/src/__tests__/engine-error.test.ts b/src/__tests__/engine-error.test.ts index d018242..bcc9ca2 100644 --- a/src/__tests__/engine-error.test.ts +++ b/src/__tests__/engine-error.test.ts @@ -109,6 +109,7 @@ describe('PieceEngine Integration: Error Handling', () => { const reason = abortFn.mock.calls[0]![1] as string; expect(reason).toContain('API connection failed'); }); + }); // ===================================================== diff --git a/src/infra/opencode/client.ts b/src/infra/opencode/client.ts index 42f2918..1a5dd25 100644 --- a/src/infra/opencode/client.ts +++ b/src/infra/opencode/client.ts @@ -6,6 +6,7 @@ */ import { createOpencode } from '@opencode-ai/sdk/v2'; +import { createServer } from 'node:net'; import type { AgentResponse } from '../../core/models/index.js'; import { createLogger, getErrorMessage } from '../../shared/utils/index.js'; import { mapToOpenCodePermissionReply, type OpenCodeCallOptions } from './types.js'; @@ -35,8 +36,32 @@ const OPENCODE_RETRYABLE_ERROR_PATTERNS = [ 'etimedout', 'eai_again', 'fetch failed', + 'failed to start server on port', ]; +async function getFreePort(): Promise { + return new Promise((resolve, reject) => { + const server = createServer(); + server.unref(); + server.on('error', reject); + server.listen(0, '127.0.0.1', () => { + const addr = server.address(); + if (!addr || typeof addr === 'string') { + server.close(() => reject(new Error('Failed to allocate free TCP port'))); + return; + } + const port = addr.port; + server.close((err) => { + if (err) { + reject(err); + return; + } + resolve(port); + }); + }); + }); +} + /** * Client for OpenCode SDK agent interactions. * @@ -129,7 +154,9 @@ export class OpenCodeClient { attempt, }); + const port = await getFreePort(); const { client, server } = await createOpencode({ + port, signal: streamAbortController.signal, ...(options.opencodeApiKey ? { config: { provider: { opencode: { options: { apiKey: options.opencodeApiKey } } } } }