diff --git a/agents/claude.ts b/agents/claude.ts index 86948f3..602a490 100644 --- a/agents/claude.ts +++ b/agents/claude.ts @@ -37,6 +37,9 @@ type SDKMessageHandlers = { [type in SDKMessageType]: SDKMessageHandler; }; +// Track bash tool IDs to identify when bash tool results come back +const bashToolIds = new Set(); + const messageHandlers: SDKMessageHandlers = { assistant: (data) => { if (data.message?.content) { @@ -46,6 +49,11 @@ const messageHandlers: SDKMessageHandlers = { } else if (content.type === "tool_use") { log.info(`→ ${content.name}`); + // Track bash tool IDs + if (content.name === "bash" && content.id) { + bashToolIds.add(content.id); + } + if (content.input) { const input = content.input as any; if (input.description) log.info(` └─ ${input.description}`); @@ -77,8 +85,35 @@ const messageHandlers: SDKMessageHandlers = { user: (data) => { if (data.message?.content) { for (const content of data.message.content) { - if (content.type === "tool_result" && content.is_error) { - log.warning(`Tool error: ${content.content}`); + if (content.type === "tool_result") { + const toolUseId = (content as any).tool_use_id; + const isBashTool = toolUseId && bashToolIds.has(toolUseId); + + if (isBashTool) { + // Log bash output in a collapsed group + const outputContent = + typeof content.content === "string" + ? content.content + : Array.isArray(content.content) + ? content.content + .map((c: any) => (typeof c === "string" ? c : c.text || JSON.stringify(c))) + .join("\n") + : String(content.content); + + log.startGroup(`bash output`); + if (content.is_error) { + log.warning(outputContent); + } else { + log.info(outputContent); + } + log.endGroup(); + // Clean up the tracked ID + bashToolIds.delete(toolUseId); + } else if (content.is_error) { + const errorContent = + typeof content.content === "string" ? content.content : String(content.content); + log.warning(`Tool error: ${errorContent}`); + } } } } @@ -107,4 +142,6 @@ const messageHandlers: SDKMessageHandlers = { }, system: () => {}, stream_event: () => {}, + tool_progress: () => {}, + auth_status: () => {}, }; diff --git a/fixtures/basic.txt b/fixtures/basic.txt index a023012..1b5a942 100644 --- a/fixtures/basic.txt +++ b/fixtures/basic.txt @@ -1 +1 @@ -add a github review for the following PR: https://github.com/pullfrogai/scratch/pull/16 +run npx cowsay "don't eat me" \ No newline at end of file diff --git a/todo.md b/todo.md index da17ae9..eb5c51a 100644 --- a/todo.md +++ b/todo.md @@ -1,4 +1,7 @@ -[] add modes to prompt -[] progressively update comment +[x] add modes to prompt +[x] progressively update comment [] don't allow rejecting prs [] fix pnpm caching +[] try to avoid claude narrating the initial comment +[] fix prompt to avoid narration like "I just read all tools from MCP server" +[] investigate including terminal output from bash commands as collapsed groups diff --git a/utils/cli.ts b/utils/cli.ts index d812fe0..19a490b 100644 --- a/utils/cli.ts +++ b/utils/cli.ts @@ -7,6 +7,28 @@ import * as core from "@actions/core"; const isGitHubActions = !!process.env.GITHUB_ACTIONS; const isDebugEnabled = process.env.LOG_LEVEL === "debug"; +/** + * Start a collapsed group (GitHub Actions) or regular group (local) + */ +function startGroup(name: string): void { + if (isGitHubActions) { + core.startGroup(name); + } else { + console.group(name); + } +} + +/** + * End a collapsed group + */ +function endGroup(): void { + if (isGitHubActions) { + core.endGroup(); + } else { + console.groupEnd(); + } +} + /** * Print a formatted box with text (for console output) */ @@ -229,4 +251,14 @@ export const log = { await core.summary.write(); } }, + + /** + * Start a collapsed group (GitHub Actions) or regular group (local) + */ + startGroup, + + /** + * End a collapsed group + */ + endGroup, };