From d9cfc1ec97a9800423be94dc5c5a5f275d444ed4 Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Thu, 25 Dec 2025 21:55:32 +0900 Subject: [PATCH] debug(cli): add verbose event logging for CI debugging with message content and tool details MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - logEventVerbose() logs all event types including message content, tool calls, and results - Session tags distinguish main vs child sessions for multi-session tracking - completion.ts error logging instead of silently swallowing API errors - Helps diagnose realtime streaming behavior in CI environments 🤖 Generated with assistance of OhMyOpenCode (https://github.com/code-yeongyu/oh-my-opencode) --- src/cli/run/completion.ts | 4 +-- src/cli/run/events.ts | 75 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 76 insertions(+), 3 deletions(-) diff --git a/src/cli/run/completion.ts b/src/cli/run/completion.ts index e921fcf..11a24f4 100644 --- a/src/cli/run/completion.ts +++ b/src/cli/run/completion.ts @@ -12,8 +12,8 @@ export async function checkCompletionConditions(ctx: RunContext): Promise | undefined + const info = props?.info as Record | undefined + const sessionID = props?.sessionID ?? info?.sessionID + const isMainSession = sessionID === ctx.sessionID + const sessionTag = isMainSession + ? pc.green("[MAIN]") + : pc.yellow(`[${String(sessionID).slice(0, 8)}]`) + + switch (payload.type) { + case "session.idle": + case "session.status": { + const status = (props?.status as { type?: string })?.type ?? "idle" + console.error(pc.dim(`${sessionTag} ${payload.type}: ${status}`)) + break + } + + case "message.part.updated": { + const partProps = props as MessagePartUpdatedProps | undefined + const role = partProps?.info?.role ?? "unknown" + const part = partProps?.part + if (part?.type === "text" && part.text) { + const preview = part.text.slice(0, 100).replace(/\n/g, "\\n") + console.error( + pc.dim(`${sessionTag} message.part (${role}): "${preview}${part.text.length > 100 ? "..." : ""}"`) + ) + } else if (part?.type === "tool-invocation") { + const toolPart = part as { toolName?: string; state?: string } + console.error( + pc.dim(`${sessionTag} message.part (tool): ${toolPart.toolName} [${toolPart.state}]`) + ) + } + break + } + + case "message.updated": { + const msgProps = props as MessageUpdatedProps | undefined + const role = msgProps?.info?.role ?? "unknown" + const content = msgProps?.content ?? "" + const preview = content.slice(0, 100).replace(/\n/g, "\\n") + console.error( + pc.dim(`${sessionTag} message.updated (${role}): "${preview}${content.length > 100 ? "..." : ""}"`) + ) + break + } + + case "tool.execute": { + const toolProps = props as ToolExecuteProps | undefined + const toolName = toolProps?.name ?? "unknown" + const input = toolProps?.input ?? {} + const inputStr = JSON.stringify(input).slice(0, 150) + console.error( + pc.cyan(`${sessionTag} ⚡ TOOL.EXECUTE: ${pc.bold(toolName)}`) + ) + console.error(pc.dim(` input: ${inputStr}${inputStr.length >= 150 ? "..." : ""}`)) + break + } + + case "tool.result": { + const resultProps = props as ToolResultProps | undefined + const output = resultProps?.output ?? "" + const preview = output.slice(0, 200).replace(/\n/g, "\\n") + console.error( + pc.green(`${sessionTag} ✓ TOOL.RESULT: "${preview}${output.length > 200 ? "..." : ""}"`) + ) + break + } + + default: + console.error(pc.dim(`${sessionTag} ${payload.type}`)) + } +} + function handleSessionIdle( ctx: RunContext, payload: EventPayload,