diff --git a/src/cli/run/runner.ts b/src/cli/run/runner.ts index a648417af..30e46688f 100644 --- a/src/cli/run/runner.ts +++ b/src/cli/run/runner.ts @@ -6,6 +6,8 @@ import { createEventState, processEvents, serializeError } from "./events" const POLL_INTERVAL_MS = 500 const DEFAULT_TIMEOUT_MS = 0 +const SESSION_CREATE_MAX_RETRIES = 3 +const SESSION_CREATE_RETRY_DELAY_MS = 1000 export async function run(options: RunOptions): Promise { const { @@ -45,13 +47,49 @@ export async function run(options: RunOptions): Promise { }) try { - const sessionRes = await client.session.create({ - body: { title: "oh-my-opencode run" }, - }) + // Retry session creation with exponential backoff + // Server might not be fully ready even after "listening" message + let sessionID: string | undefined + let lastError: unknown + + for (let attempt = 1; attempt <= SESSION_CREATE_MAX_RETRIES; attempt++) { + const sessionRes = await client.session.create({ + body: { title: "oh-my-opencode run" }, + }) + + if (sessionRes.error) { + lastError = sessionRes.error + console.error(pc.yellow(`Session create attempt ${attempt}/${SESSION_CREATE_MAX_RETRIES} failed:`)) + console.error(pc.dim(` Error: ${serializeError(sessionRes.error)}`)) + + if (attempt < SESSION_CREATE_MAX_RETRIES) { + const delay = SESSION_CREATE_RETRY_DELAY_MS * attempt + console.log(pc.dim(` Retrying in ${delay}ms...`)) + await new Promise((resolve) => setTimeout(resolve, delay)) + continue + } + } + + sessionID = sessionRes.data?.id + if (sessionID) { + break + } + + // No error but also no session ID - unexpected response + lastError = new Error(`Unexpected response: ${JSON.stringify(sessionRes, null, 2)}`) + console.error(pc.yellow(`Session create attempt ${attempt}/${SESSION_CREATE_MAX_RETRIES}: No session ID returned`)) + + if (attempt < SESSION_CREATE_MAX_RETRIES) { + const delay = SESSION_CREATE_RETRY_DELAY_MS * attempt + console.log(pc.dim(` Retrying in ${delay}ms...`)) + await new Promise((resolve) => setTimeout(resolve, delay)) + } + } - const sessionID = sessionRes.data?.id if (!sessionID) { - console.error(pc.red("Failed to create session")) + console.error(pc.red("Failed to create session after all retries")) + console.error(pc.dim(`Last error: ${serializeError(lastError)}`)) + cleanup() return 1 }