diff --git a/.github/workflows/test-base-action.yml b/.github/workflows/test-base-action.yml index dddbf57..b489663 100644 --- a/.github/workflows/test-base-action.yml +++ b/.github/workflows/test-base-action.yml @@ -118,3 +118,61 @@ jobs: echo "❌ Execution log file not found" exit 1 fi + + test-agent-sdk: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 + + - name: Test with Agent SDK + id: sdk-test + uses: ./base-action + env: + USE_AGENT_SDK: "true" + with: + prompt: ${{ github.event.inputs.test_prompt || 'List the files in the current directory starting with "package"' }} + anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }} + allowed_tools: "LS,Read" + + - name: Verify SDK output + run: | + OUTPUT_FILE="${{ steps.sdk-test.outputs.execution_file }}" + CONCLUSION="${{ steps.sdk-test.outputs.conclusion }}" + + echo "Conclusion: $CONCLUSION" + echo "Output file: $OUTPUT_FILE" + + if [ "$CONCLUSION" = "success" ]; then + echo "✅ Action completed successfully with Agent SDK" + else + echo "❌ Action failed with Agent SDK" + exit 1 + fi + + if [ -f "$OUTPUT_FILE" ]; then + if [ -s "$OUTPUT_FILE" ]; then + echo "✅ Execution log file created successfully with content" + echo "Validating JSON format:" + if jq . "$OUTPUT_FILE" > /dev/null 2>&1; then + echo "✅ Output is valid JSON" + # Verify SDK output contains total_cost_usd (SDK field name) + if jq -e '.[] | select(.type == "result") | .total_cost_usd' "$OUTPUT_FILE" > /dev/null 2>&1; then + echo "✅ SDK output contains total_cost_usd field" + else + echo "❌ SDK output missing total_cost_usd field" + exit 1 + fi + echo "Content preview:" + head -c 500 "$OUTPUT_FILE" + else + echo "❌ Output is not valid JSON" + exit 1 + fi + else + echo "❌ Execution log file is empty" + exit 1 + fi + else + echo "❌ Execution log file not found" + exit 1 + fi diff --git a/base-action/bun.lock b/base-action/bun.lock index 16ee322..81b0993 100644 --- a/base-action/bun.lock +++ b/base-action/bun.lock @@ -5,6 +5,7 @@ "name": "@anthropic-ai/claude-code-base-action", "dependencies": { "@actions/core": "^1.10.1", + "@anthropic-ai/claude-agent-sdk": "^0.1.52", "shell-quote": "^1.8.3", }, "devDependencies": { @@ -25,8 +26,40 @@ "@actions/io": ["@actions/io@1.1.3", "", {}, "sha512-wi9JjgKLYS7U/z8PPbco+PvTb/nRWjeoFlJ1Qer83k/3C5PHQi28hiVdeE2kHXmIL99mQFawx8qt/JPjZilJ8Q=="], + "@anthropic-ai/claude-agent-sdk": ["@anthropic-ai/claude-agent-sdk@0.1.52", "", { "optionalDependencies": { "@img/sharp-darwin-arm64": "^0.33.5", "@img/sharp-darwin-x64": "^0.33.5", "@img/sharp-linux-arm": "^0.33.5", "@img/sharp-linux-arm64": "^0.33.5", "@img/sharp-linux-x64": "^0.33.5", "@img/sharp-linuxmusl-arm64": "^0.33.5", "@img/sharp-linuxmusl-x64": "^0.33.5", "@img/sharp-win32-x64": "^0.33.5" }, "peerDependencies": { "zod": "^3.24.1" } }, "sha512-yF8N05+9NRbqYA/h39jQ726HTQFrdXXp7pEfDNKIJ2c4FdWvEjxBA/8ciZIebN6/PyvGDcbEp3yq2Co4rNpg6A=="], + "@fastify/busboy": ["@fastify/busboy@2.1.1", "", {}, "sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA=="], + "@img/sharp-darwin-arm64": ["@img/sharp-darwin-arm64@0.33.5", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-arm64": "1.0.4" }, "os": "darwin", "cpu": "arm64" }, "sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ=="], + + "@img/sharp-darwin-x64": ["@img/sharp-darwin-x64@0.33.5", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-x64": "1.0.4" }, "os": "darwin", "cpu": "x64" }, "sha512-fyHac4jIc1ANYGRDxtiqelIbdWkIuQaI84Mv45KvGRRxSAa7o7d1ZKAOBaYbnepLC1WqxfpimdeWfvqqSGwR2Q=="], + + "@img/sharp-libvips-darwin-arm64": ["@img/sharp-libvips-darwin-arm64@1.0.4", "", { "os": "darwin", "cpu": "arm64" }, "sha512-XblONe153h0O2zuFfTAbQYAX2JhYmDHeWikp1LM9Hul9gVPjFY427k6dFEcOL72O01QxQsWi761svJ/ev9xEDg=="], + + "@img/sharp-libvips-darwin-x64": ["@img/sharp-libvips-darwin-x64@1.0.4", "", { "os": "darwin", "cpu": "x64" }, "sha512-xnGR8YuZYfJGmWPvmlunFaWJsb9T/AO2ykoP3Fz/0X5XV2aoYBPkX6xqCQvUTKKiLddarLaxpzNe+b1hjeWHAQ=="], + + "@img/sharp-libvips-linux-arm": ["@img/sharp-libvips-linux-arm@1.0.5", "", { "os": "linux", "cpu": "arm" }, "sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g=="], + + "@img/sharp-libvips-linux-arm64": ["@img/sharp-libvips-linux-arm64@1.0.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA=="], + + "@img/sharp-libvips-linux-x64": ["@img/sharp-libvips-linux-x64@1.0.4", "", { "os": "linux", "cpu": "x64" }, "sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw=="], + + "@img/sharp-libvips-linuxmusl-arm64": ["@img/sharp-libvips-linuxmusl-arm64@1.0.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA=="], + + "@img/sharp-libvips-linuxmusl-x64": ["@img/sharp-libvips-linuxmusl-x64@1.0.4", "", { "os": "linux", "cpu": "x64" }, "sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw=="], + + "@img/sharp-linux-arm": ["@img/sharp-linux-arm@0.33.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-arm": "1.0.5" }, "os": "linux", "cpu": "arm" }, "sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ=="], + + "@img/sharp-linux-arm64": ["@img/sharp-linux-arm64@0.33.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-arm64": "1.0.4" }, "os": "linux", "cpu": "arm64" }, "sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA=="], + + "@img/sharp-linux-x64": ["@img/sharp-linux-x64@0.33.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-x64": "1.0.4" }, "os": "linux", "cpu": "x64" }, "sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA=="], + + "@img/sharp-linuxmusl-arm64": ["@img/sharp-linuxmusl-arm64@0.33.5", "", { "optionalDependencies": { "@img/sharp-libvips-linuxmusl-arm64": "1.0.4" }, "os": "linux", "cpu": "arm64" }, "sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g=="], + + "@img/sharp-linuxmusl-x64": ["@img/sharp-linuxmusl-x64@0.33.5", "", { "optionalDependencies": { "@img/sharp-libvips-linuxmusl-x64": "1.0.4" }, "os": "linux", "cpu": "x64" }, "sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw=="], + + "@img/sharp-win32-x64": ["@img/sharp-win32-x64@0.33.5", "", { "os": "win32", "cpu": "x64" }, "sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg=="], + "@types/bun": ["@types/bun@1.2.19", "", { "dependencies": { "bun-types": "1.2.19" } }, "sha512-d9ZCmrH3CJ2uYKXQIUuZ/pUnTqIvLDS0SK7pFmbx8ma+ziH/FRMoAq5bYpRG7y+w1gl+HgyNZbtqgMq4W4e2Lg=="], "@types/node": ["@types/node@20.19.9", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-cuVNgarYWZqxRJDQHEB58GEONhOK79QVR/qYx4S7kcUObQvUwvFnYxJuuHUKm2aieN9X3yZB4LZsuYNU1Qphsw=="], @@ -50,5 +83,7 @@ "undici": ["undici@5.29.0", "", { "dependencies": { "@fastify/busboy": "^2.0.0" } }, "sha512-raqeBD6NQK4SkWhQzeYKd1KmIG6dllBOTt55Rmkt4HtI9mwdWtJljnrXjAFUBLTSN67HWrOIZ3EPF4kjUw80Bg=="], "undici-types": ["undici-types@6.21.0", "", {}, "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ=="], + + "zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], } } diff --git a/base-action/package.json b/base-action/package.json index d0a5973..469c68b 100644 --- a/base-action/package.json +++ b/base-action/package.json @@ -11,6 +11,7 @@ }, "dependencies": { "@actions/core": "^1.10.1", + "@anthropic-ai/claude-agent-sdk": "^0.1.52", "shell-quote": "^1.8.3" }, "devDependencies": { diff --git a/base-action/src/parse-sdk-options.ts b/base-action/src/parse-sdk-options.ts new file mode 100644 index 0000000..cc07366 --- /dev/null +++ b/base-action/src/parse-sdk-options.ts @@ -0,0 +1,105 @@ +import { parse as parseShellArgs } from "shell-quote"; +import type { ClaudeOptions } from "./run-claude"; +import type { Options as SdkOptions } from "@anthropic-ai/claude-agent-sdk"; + +/** + * Result of parsing ClaudeOptions for SDK usage + */ +export type ParsedSdkOptions = { + sdkOptions: SdkOptions; + showFullOutput: boolean; + hasJsonSchema: boolean; +}; + +/** + * Parse claudeArgs string into extraArgs record for SDK pass-through + * The SDK/CLI will handle --mcp-config, --json-schema, etc. + */ +function parseClaudeArgsToExtraArgs( + claudeArgs?: string, +): Record { + if (!claudeArgs?.trim()) return {}; + + const result: Record = {}; + const args = parseShellArgs(claudeArgs).filter( + (arg): arg is string => typeof arg === "string", + ); + + for (let i = 0; i < args.length; i++) { + const arg = args[i]; + if (arg?.startsWith("--")) { + const flag = arg.slice(2); + const nextArg = args[i + 1]; + + // Check if next arg is a value (not another flag) + if (nextArg && !nextArg.startsWith("--")) { + result[flag] = nextArg; + i++; // Skip the value + } else { + result[flag] = null; // Boolean flag + } + } + } + + return result; +} + +/** + * Parse ClaudeOptions into SDK-compatible options + * Uses extraArgs for CLI pass-through instead of duplicating option parsing + */ +export function parseSdkOptions(options: ClaudeOptions): ParsedSdkOptions { + // Determine output verbosity + const isDebugMode = process.env.ACTIONS_STEP_DEBUG === "true"; + const showFullOutput = options.showFullOutput === "true" || isDebugMode; + + // Parse claudeArgs into extraArgs for CLI pass-through + const extraArgs = parseClaudeArgsToExtraArgs(options.claudeArgs); + + // Detect if --json-schema is present (for hasJsonSchema flag) + const hasJsonSchema = "json-schema" in extraArgs; + + // Build custom environment + const env: Record = { ...process.env }; + if (process.env.INPUT_ACTION_INPUTS_PRESENT) { + env.GITHUB_ACTION_INPUTS = process.env.INPUT_ACTION_INPUTS_PRESENT; + } + + // Build system prompt option + let systemPrompt: SdkOptions["systemPrompt"]; + if (options.systemPrompt) { + systemPrompt = options.systemPrompt; + } else if (options.appendSystemPrompt) { + systemPrompt = { + type: "preset", + preset: "claude_code", + append: options.appendSystemPrompt, + }; + } + + // Build SDK options - use direct options for explicit inputs, extraArgs for claudeArgs pass-through + const sdkOptions: SdkOptions = { + // Direct options from ClaudeOptions inputs + model: options.model, + maxTurns: options.maxTurns ? parseInt(options.maxTurns, 10) : undefined, + allowedTools: options.allowedTools + ? options.allowedTools.split(",").map((t) => t.trim()) + : undefined, + disallowedTools: options.disallowedTools + ? options.disallowedTools.split(",").map((t) => t.trim()) + : undefined, + systemPrompt, + fallbackModel: options.fallbackModel, + pathToClaudeCodeExecutable: options.pathToClaudeCodeExecutable, + + // Pass through claudeArgs as extraArgs - CLI handles --mcp-config, --json-schema, etc. + extraArgs, + env, + }; + + return { + sdkOptions, + showFullOutput, + hasJsonSchema, + }; +} diff --git a/base-action/src/run-claude-sdk.ts b/base-action/src/run-claude-sdk.ts new file mode 100644 index 0000000..cea7035 --- /dev/null +++ b/base-action/src/run-claude-sdk.ts @@ -0,0 +1,148 @@ +import * as core from "@actions/core"; +import { readFile, writeFile } from "fs/promises"; +import { query } from "@anthropic-ai/claude-agent-sdk"; +import type { + SDKMessage, + SDKResultMessage, +} from "@anthropic-ai/claude-agent-sdk"; +import type { ParsedSdkOptions } from "./parse-sdk-options"; + +const EXECUTION_FILE = `${process.env.RUNNER_TEMP}/claude-execution-output.json`; + +/** + * Sanitizes SDK output to match CLI sanitization behavior + */ +function sanitizeSdkOutput( + message: SDKMessage, + showFullOutput: boolean, +): string | null { + if (showFullOutput) { + return JSON.stringify(message, null, 2); + } + + // System initialization - safe to show + if (message.type === "system" && message.subtype === "init") { + return JSON.stringify( + { + type: "system", + subtype: "init", + message: "Claude Code initialized", + model: "model" in message ? message.model : "unknown", + }, + null, + 2, + ); + } + + // Result messages - show sanitized summary + if (message.type === "result") { + const resultMsg = message as SDKResultMessage; + return JSON.stringify( + { + type: "result", + subtype: resultMsg.subtype, + is_error: resultMsg.is_error, + duration_ms: resultMsg.duration_ms, + num_turns: resultMsg.num_turns, + total_cost_usd: resultMsg.total_cost_usd, + permission_denials: resultMsg.permission_denials, + }, + null, + 2, + ); + } + + // Suppress other message types in non-full-output mode + return null; +} + +/** + * Run Claude using the Agent SDK + */ +export async function runClaudeWithSdk( + promptPath: string, + { sdkOptions, showFullOutput, hasJsonSchema }: ParsedSdkOptions, +): Promise { + const prompt = await readFile(promptPath, "utf-8"); + + if (!showFullOutput) { + console.log( + "Running Claude Code via SDK (full output hidden for security)...", + ); + console.log( + "Rerun in debug mode or enable `show_full_output: true` in your workflow file for full output.", + ); + } + + console.log(`Running Claude with prompt from file: ${promptPath}`); + + const messages: SDKMessage[] = []; + let resultMessage: SDKResultMessage | undefined; + + try { + for await (const message of query({ prompt, options: sdkOptions })) { + messages.push(message); + + const sanitized = sanitizeSdkOutput(message, showFullOutput); + if (sanitized) { + console.log(sanitized); + } + + if (message.type === "result") { + resultMessage = message as SDKResultMessage; + } + } + } catch (error) { + console.error("SDK execution error:", error); + core.setOutput("conclusion", "failure"); + process.exit(1); + } + + // Write execution file + try { + await writeFile(EXECUTION_FILE, JSON.stringify(messages, null, 2)); + console.log(`Log saved to ${EXECUTION_FILE}`); + core.setOutput("execution_file", EXECUTION_FILE); + } catch (error) { + core.warning(`Failed to write execution file: ${error}`); + } + + if (!resultMessage) { + core.setOutput("conclusion", "failure"); + core.error("No result message received from Claude"); + process.exit(1); + } + + const isSuccess = resultMessage.subtype === "success"; + core.setOutput("conclusion", isSuccess ? "success" : "failure"); + + // Handle structured output + if (hasJsonSchema) { + if ( + isSuccess && + "structured_output" in resultMessage && + resultMessage.structured_output + ) { + const structuredOutputJson = JSON.stringify( + resultMessage.structured_output, + ); + core.setOutput("structured_output", structuredOutputJson); + core.info( + `Set structured_output with ${Object.keys(resultMessage.structured_output as object).length} field(s)`, + ); + } else { + core.setFailed( + `--json-schema was provided but Claude did not return structured_output. Result subtype: ${resultMessage.subtype}`, + ); + core.setOutput("conclusion", "failure"); + process.exit(1); + } + } + + if (!isSuccess) { + if ("errors" in resultMessage && resultMessage.errors) { + core.error(`Execution failed: ${resultMessage.errors.join(", ")}`); + } + process.exit(1); + } +} diff --git a/base-action/src/run-claude.ts b/base-action/src/run-claude.ts index e330894..b2fc99f 100644 --- a/base-action/src/run-claude.ts +++ b/base-action/src/run-claude.ts @@ -5,6 +5,8 @@ import { unlink, writeFile, stat, readFile } from "fs/promises"; import { createWriteStream } from "fs"; import { spawn } from "child_process"; import { parse as parseShellArgs } from "shell-quote"; +import { runClaudeWithSdk } from "./run-claude-sdk"; +import { parseSdkOptions } from "./parse-sdk-options"; const execAsync = promisify(exec); @@ -165,6 +167,17 @@ export async function parseAndSetStructuredOutputs( } export async function runClaude(promptPath: string, options: ClaudeOptions) { + // Feature flag: use SDK path when USE_AGENT_SDK=true + const useAgentSdk = process.env.USE_AGENT_SDK === "true"; + console.log( + `Using ${useAgentSdk ? "Agent SDK" : "CLI"} path (USE_AGENT_SDK=${process.env.USE_AGENT_SDK ?? "unset"})`, + ); + + if (useAgentSdk) { + const parsedOptions = parseSdkOptions(options); + return runClaudeWithSdk(promptPath, parsedOptions); + } + const config = prepareRunConfig(promptPath, options); // Detect if --json-schema is present in claude args diff --git a/bun.lock b/bun.lock index 364c2da..76ce794 100644 --- a/bun.lock +++ b/bun.lock @@ -6,6 +6,7 @@ "dependencies": { "@actions/core": "^1.10.1", "@actions/github": "^6.0.1", + "@anthropic-ai/claude-agent-sdk": "^0.1.52", "@modelcontextprotocol/sdk": "^1.11.0", "@octokit/graphql": "^8.2.2", "@octokit/rest": "^21.1.1", @@ -35,8 +36,40 @@ "@actions/io": ["@actions/io@1.1.3", "", {}, "sha512-wi9JjgKLYS7U/z8PPbco+PvTb/nRWjeoFlJ1Qer83k/3C5PHQi28hiVdeE2kHXmIL99mQFawx8qt/JPjZilJ8Q=="], + "@anthropic-ai/claude-agent-sdk": ["@anthropic-ai/claude-agent-sdk@0.1.52", "", { "optionalDependencies": { "@img/sharp-darwin-arm64": "^0.33.5", "@img/sharp-darwin-x64": "^0.33.5", "@img/sharp-linux-arm": "^0.33.5", "@img/sharp-linux-arm64": "^0.33.5", "@img/sharp-linux-x64": "^0.33.5", "@img/sharp-linuxmusl-arm64": "^0.33.5", "@img/sharp-linuxmusl-x64": "^0.33.5", "@img/sharp-win32-x64": "^0.33.5" }, "peerDependencies": { "zod": "^3.24.1" } }, "sha512-yF8N05+9NRbqYA/h39jQ726HTQFrdXXp7pEfDNKIJ2c4FdWvEjxBA/8ciZIebN6/PyvGDcbEp3yq2Co4rNpg6A=="], + "@fastify/busboy": ["@fastify/busboy@2.1.1", "", {}, "sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA=="], + "@img/sharp-darwin-arm64": ["@img/sharp-darwin-arm64@0.33.5", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-arm64": "1.0.4" }, "os": "darwin", "cpu": "arm64" }, "sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ=="], + + "@img/sharp-darwin-x64": ["@img/sharp-darwin-x64@0.33.5", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-x64": "1.0.4" }, "os": "darwin", "cpu": "x64" }, "sha512-fyHac4jIc1ANYGRDxtiqelIbdWkIuQaI84Mv45KvGRRxSAa7o7d1ZKAOBaYbnepLC1WqxfpimdeWfvqqSGwR2Q=="], + + "@img/sharp-libvips-darwin-arm64": ["@img/sharp-libvips-darwin-arm64@1.0.4", "", { "os": "darwin", "cpu": "arm64" }, "sha512-XblONe153h0O2zuFfTAbQYAX2JhYmDHeWikp1LM9Hul9gVPjFY427k6dFEcOL72O01QxQsWi761svJ/ev9xEDg=="], + + "@img/sharp-libvips-darwin-x64": ["@img/sharp-libvips-darwin-x64@1.0.4", "", { "os": "darwin", "cpu": "x64" }, "sha512-xnGR8YuZYfJGmWPvmlunFaWJsb9T/AO2ykoP3Fz/0X5XV2aoYBPkX6xqCQvUTKKiLddarLaxpzNe+b1hjeWHAQ=="], + + "@img/sharp-libvips-linux-arm": ["@img/sharp-libvips-linux-arm@1.0.5", "", { "os": "linux", "cpu": "arm" }, "sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g=="], + + "@img/sharp-libvips-linux-arm64": ["@img/sharp-libvips-linux-arm64@1.0.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA=="], + + "@img/sharp-libvips-linux-x64": ["@img/sharp-libvips-linux-x64@1.0.4", "", { "os": "linux", "cpu": "x64" }, "sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw=="], + + "@img/sharp-libvips-linuxmusl-arm64": ["@img/sharp-libvips-linuxmusl-arm64@1.0.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA=="], + + "@img/sharp-libvips-linuxmusl-x64": ["@img/sharp-libvips-linuxmusl-x64@1.0.4", "", { "os": "linux", "cpu": "x64" }, "sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw=="], + + "@img/sharp-linux-arm": ["@img/sharp-linux-arm@0.33.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-arm": "1.0.5" }, "os": "linux", "cpu": "arm" }, "sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ=="], + + "@img/sharp-linux-arm64": ["@img/sharp-linux-arm64@0.33.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-arm64": "1.0.4" }, "os": "linux", "cpu": "arm64" }, "sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA=="], + + "@img/sharp-linux-x64": ["@img/sharp-linux-x64@0.33.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-x64": "1.0.4" }, "os": "linux", "cpu": "x64" }, "sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA=="], + + "@img/sharp-linuxmusl-arm64": ["@img/sharp-linuxmusl-arm64@0.33.5", "", { "optionalDependencies": { "@img/sharp-libvips-linuxmusl-arm64": "1.0.4" }, "os": "linux", "cpu": "arm64" }, "sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g=="], + + "@img/sharp-linuxmusl-x64": ["@img/sharp-linuxmusl-x64@0.33.5", "", { "optionalDependencies": { "@img/sharp-libvips-linuxmusl-x64": "1.0.4" }, "os": "linux", "cpu": "x64" }, "sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw=="], + + "@img/sharp-win32-x64": ["@img/sharp-win32-x64@0.33.5", "", { "os": "win32", "cpu": "x64" }, "sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg=="], + "@modelcontextprotocol/sdk": ["@modelcontextprotocol/sdk@1.16.0", "", { "dependencies": { "ajv": "^6.12.6", "content-type": "^1.0.5", "cors": "^2.8.5", "cross-spawn": "^7.0.5", "eventsource": "^3.0.2", "eventsource-parser": "^3.0.0", "express": "^5.0.1", "express-rate-limit": "^7.5.0", "pkce-challenge": "^5.0.0", "raw-body": "^3.0.0", "zod": "^3.23.8", "zod-to-json-schema": "^3.24.1" } }, "sha512-8ofX7gkZcLj9H9rSd50mCgm3SSF8C7XoclxJuLoV0Cz3rEQ1tv9MZRYYvJtm9n1BiEQQMzSmE/w2AEkNacLYfg=="], "@octokit/auth-token": ["@octokit/auth-token@4.0.0", "", {}, "sha512-tY/msAuJo6ARbK6SPIxZrPBms3xPbfwBrulZe0Wtr/DIY9lje2HeV1uoebShn6mx7SjCHif6EjMvoREj+gZ+SA=="], diff --git a/package.json b/package.json index d4f47ff..8825a03 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,7 @@ "dependencies": { "@actions/core": "^1.10.1", "@actions/github": "^6.0.1", + "@anthropic-ai/claude-agent-sdk": "^0.1.52", "@modelcontextprotocol/sdk": "^1.11.0", "@octokit/graphql": "^8.2.2", "@octokit/rest": "^21.1.1", diff --git a/src/entrypoints/update-comment-link.ts b/src/entrypoints/update-comment-link.ts index 3a14e66..849f954 100644 --- a/src/entrypoints/update-comment-link.ts +++ b/src/entrypoints/update-comment-link.ts @@ -152,7 +152,7 @@ async function run() { // Check if action failed and read output file for execution details let executionDetails: { - cost_usd?: number; + total_cost_usd?: number; duration_ms?: number; duration_api_ms?: number; } | null = null; @@ -179,11 +179,11 @@ async function run() { const lastElement = outputData[outputData.length - 1]; if ( lastElement.type === "result" && - "cost_usd" in lastElement && + "total_cost_usd" in lastElement && "duration_ms" in lastElement ) { executionDetails = { - cost_usd: lastElement.cost_usd, + total_cost_usd: lastElement.total_cost_usd, duration_ms: lastElement.duration_ms, duration_api_ms: lastElement.duration_api_ms, }; diff --git a/src/github/operations/comment-logic.ts b/src/github/operations/comment-logic.ts index 6a4551a..03b5d86 100644 --- a/src/github/operations/comment-logic.ts +++ b/src/github/operations/comment-logic.ts @@ -1,7 +1,7 @@ import { GITHUB_SERVER_URL } from "../api/config"; export type ExecutionDetails = { - cost_usd?: number; + total_cost_usd?: number; duration_ms?: number; duration_api_ms?: number; }; diff --git a/test/comment-logic.test.ts b/test/comment-logic.test.ts index f1b3754..d55c82d 100644 --- a/test/comment-logic.test.ts +++ b/test/comment-logic.test.ts @@ -258,7 +258,7 @@ describe("updateCommentBody", () => { const input = { ...baseInput, executionDetails: { - cost_usd: 0.13382595, + total_cost_usd: 0.13382595, duration_ms: 31033, duration_api_ms: 31034, }, @@ -301,7 +301,7 @@ describe("updateCommentBody", () => { const input = { ...baseInput, executionDetails: { - cost_usd: 0.25, + total_cost_usd: 0.25, }, triggerUsername: "testuser", }; @@ -322,7 +322,7 @@ describe("updateCommentBody", () => { branchName: "claude-branch-123", prLink: "\n[Create a PR](https://github.com/owner/repo/pr-url)", executionDetails: { - cost_usd: 0.01, + total_cost_usd: 0.01, duration_ms: 65000, // 1 minute 5 seconds }, triggerUsername: "trigger-user", diff --git a/test/fixtures/sample-turns.json b/test/fixtures/sample-turns.json index 2690675..d7e4e78 100644 --- a/test/fixtures/sample-turns.json +++ b/test/fixtures/sample-turns.json @@ -189,7 +189,7 @@ }, { "type": "result", - "cost_usd": 0.0347, + "total_cost_usd": 0.0347, "duration_ms": 18750, "result": "Successfully removed debug print statement from file and added review comment to document the change." }