From 986e40a89c9b4dcf81e2877c259dbe5c6972d6d0 Mon Sep 17 00:00:00 2001 From: km-anthropic Date: Mon, 25 Aug 2025 12:13:11 -0700 Subject: [PATCH] refactor: Remove timeout_minutes parameter from action (#482) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This change removes the custom timeout_minutes parameter from the action in favor of using GitHub Actions' native timeout-minutes feature. Changes: - Removed timeout_minutes input from action.yml and base-action/action.yml - Removed all timeout handling logic from base-action/src/run-claude.ts - Updated base-action/src/index.ts to remove timeoutMinutes parameter - Removed timeout-related tests from base-action/test/run-claude.test.ts - Removed timeout_minutes from all example workflow files (19 files) Rationale: - Simplifies the codebase by removing custom timeout logic - Users can use GitHub Actions' native timeout-minutes at the job/step level - Reduces complexity and maintenance burden - Follows GitHub Actions best practices BREAKING CHANGE: The timeout_minutes parameter is no longer supported. Users should use GitHub Actions' native timeout-minutes instead. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-authored-by: Claude --- .github/workflows/issue-triage.yml | 1 - .github/workflows/test-base-action.yml | 2 - .github/workflows/test-custom-executables.yml | 1 - .github/workflows/test-settings.yml | 4 -- action.yml | 5 -- base-action/action.yml | 5 -- base-action/examples/issue-triage.yml | 1 - base-action/src/index.ts | 1 - base-action/src/run-claude.ts | 61 ++----------------- base-action/test/run-claude.test.ts | 30 --------- .../auto-fix-ci-signed/auto-fix-ci-signed.yml | 1 - examples/auto-fix-ci/auto-fix-ci.yml | 1 - examples/claude-auto-review.yml | 1 - examples/claude-experimental-review-mode.yml | 1 - examples/claude-pr-path-specific.yml | 1 - examples/claude-review-from-author.yml | 1 - examples/issue-deduplication.yml | 1 - examples/issue-triage.yml | 1 - 18 files changed, 4 insertions(+), 115 deletions(-) diff --git a/.github/workflows/issue-triage.yml b/.github/workflows/issue-triage.yml index beaeef2..7f120ea 100644 --- a/.github/workflows/issue-triage.yml +++ b/.github/workflows/issue-triage.yml @@ -102,7 +102,6 @@ jobs: prompt_file: /tmp/claude-prompts/triage-prompt.txt allowed_tools: "Bash(gh label list),mcp__github__get_issue,mcp__github__get_issue_comments,mcp__github__update_issue,mcp__github__search_issues,mcp__github__list_issues" mcp_config: /tmp/mcp-config/mcp-servers.json - timeout_minutes: "5" anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }} env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/test-base-action.yml b/.github/workflows/test-base-action.yml index 9d60358..dddbf57 100644 --- a/.github/workflows/test-base-action.yml +++ b/.github/workflows/test-base-action.yml @@ -25,7 +25,6 @@ jobs: 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" - timeout_minutes: "3" - name: Verify inline prompt output run: | @@ -83,7 +82,6 @@ jobs: prompt_file: "test-prompt.txt" anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }} allowed_tools: "LS,Read" - timeout_minutes: "3" - name: Verify prompt file output run: | diff --git a/.github/workflows/test-custom-executables.yml b/.github/workflows/test-custom-executables.yml index e05f71f..2fd2fc0 100644 --- a/.github/workflows/test-custom-executables.yml +++ b/.github/workflows/test-custom-executables.yml @@ -53,7 +53,6 @@ jobs: path_to_claude_code_executable: /home/runner/.local/bin/claude path_to_bun_executable: /home/runner/.bun/bin/bun allowed_tools: "LS,Read" - timeout_minutes: "3" - name: Verify custom executables worked run: | diff --git a/.github/workflows/test-settings.yml b/.github/workflows/test-settings.yml index 2ee861e..c666155 100644 --- a/.github/workflows/test-settings.yml +++ b/.github/workflows/test-settings.yml @@ -26,7 +26,6 @@ jobs: "allow": ["Bash(echo:*)"] } } - timeout_minutes: "2" - name: Verify echo worked run: | @@ -76,7 +75,6 @@ jobs: "deny": ["Bash(echo:*)"] } } - timeout_minutes: "2" - name: Verify echo was denied run: | @@ -114,7 +112,6 @@ jobs: Use Bash to echo "Hello from settings file test" anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }} settings: "test-settings.json" - timeout_minutes: "2" - name: Verify echo worked run: | @@ -169,7 +166,6 @@ jobs: Use Bash to echo "This should not work from file" anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }} settings: "test-settings.json" - timeout_minutes: "2" - name: Verify echo was denied run: | diff --git a/action.yml b/action.yml index cd61a0d..eb905c0 100644 --- a/action.yml +++ b/action.yml @@ -57,10 +57,6 @@ inputs: required: false default: "false" - timeout_minutes: - description: "Timeout in minutes for execution" - required: false - default: "30" claude_args: description: "Additional arguments to pass directly to Claude CLI" required: false @@ -197,7 +193,6 @@ runs: CLAUDE_CODE_ACTION: "1" INPUT_PROMPT_FILE: ${{ runner.temp }}/claude-prompts/claude-prompt.txt INPUT_SETTINGS: ${{ inputs.settings }} - INPUT_TIMEOUT_MINUTES: ${{ inputs.timeout_minutes }} INPUT_CLAUDE_ARGS: ${{ steps.prepare.outputs.claude_args }} INPUT_EXPERIMENTAL_SLASH_COMMANDS_DIR: ${{ github.action_path }}/slash-commands INPUT_ACTION_INPUTS_PRESENT: ${{ steps.prepare.outputs.action_inputs_present }} diff --git a/base-action/action.yml b/base-action/action.yml index 904bb1c..210f7d6 100644 --- a/base-action/action.yml +++ b/base-action/action.yml @@ -20,10 +20,6 @@ inputs: default: "" # Action settings - timeout_minutes: - description: "Timeout in minutes for Claude Code execution" - required: false - default: "10" claude_args: description: "Additional arguments to pass directly to Claude CLI (e.g., '--max-turns 3 --mcp-config /path/to/config.json')" required: false @@ -130,7 +126,6 @@ runs: INPUT_PROMPT: ${{ inputs.prompt }} INPUT_PROMPT_FILE: ${{ inputs.prompt_file }} INPUT_SETTINGS: ${{ inputs.settings }} - INPUT_TIMEOUT_MINUTES: ${{ inputs.timeout_minutes }} INPUT_CLAUDE_ARGS: ${{ inputs.claude_args }} INPUT_EXPERIMENTAL_SLASH_COMMANDS_DIR: ${{ inputs.experimental_slash_commands_dir }} INPUT_PATH_TO_CLAUDE_CODE_EXECUTABLE: ${{ inputs.path_to_claude_code_executable }} diff --git a/base-action/examples/issue-triage.yml b/base-action/examples/issue-triage.yml index 17f0af6..78a8caa 100644 --- a/base-action/examples/issue-triage.yml +++ b/base-action/examples/issue-triage.yml @@ -104,5 +104,4 @@ jobs: prompt_file: /tmp/claude-prompts/triage-prompt.txt allowed_tools: "Bash(gh label list),mcp__github__get_issue,mcp__github__get_issue_comments,mcp__github__update_issue,mcp__github__search_issues,mcp__github__list_issues" mcp_config: /tmp/mcp-config/mcp-servers.json - timeout_minutes: "5" anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }} diff --git a/base-action/src/index.ts b/base-action/src/index.ts index 8e2fae9..eb81bb1 100644 --- a/base-action/src/index.ts +++ b/base-action/src/index.ts @@ -22,7 +22,6 @@ async function run() { }); await runClaude(promptConfig.path, { - timeoutMinutes: process.env.INPUT_TIMEOUT_MINUTES, claudeArgs: process.env.INPUT_CLAUDE_ARGS, allowedTools: process.env.INPUT_ALLOWED_TOOLS, disallowedTools: process.env.INPUT_DISALLOWED_TOOLS, diff --git a/base-action/src/run-claude.ts b/base-action/src/run-claude.ts index b44432a..58c58c0 100644 --- a/base-action/src/run-claude.ts +++ b/base-action/src/run-claude.ts @@ -13,7 +13,6 @@ const EXECUTION_FILE = `${process.env.RUNNER_TEMP}/claude-execution-output.json` const BASE_ARGS = ["--verbose", "--output-format", "stream-json"]; export type ClaudeOptions = { - timeoutMinutes?: string; claudeArgs?: string; model?: string; pathToClaudeCodeExecutable?: string; @@ -56,16 +55,6 @@ export function prepareRunConfig( // BASE_ARGS are always appended last (cannot be overridden) claudeArgs.push(...BASE_ARGS); - // Validate timeout if provided (affects process wrapper, not Claude) - if (options.timeoutMinutes) { - const timeoutMinutesNum = parseInt(options.timeoutMinutes, 10); - if (isNaN(timeoutMinutesNum) || timeoutMinutesNum <= 0) { - throw new Error( - `timeoutMinutes must be a positive number, got: ${options.timeoutMinutes}`, - ); - } - } - const customEnv: Record = {}; if (process.env.INPUT_ACTION_INPUTS_PRESENT) { @@ -194,57 +183,15 @@ export async function runClaude(promptPath: string, options: ClaudeOptions) { claudeProcess.kill("SIGTERM"); }); - // Wait for Claude to finish with timeout - let timeoutMs = 10 * 60 * 1000; // Default 10 minutes - if (options.timeoutMinutes) { - timeoutMs = parseInt(options.timeoutMinutes, 10) * 60 * 1000; - } else if (process.env.INPUT_TIMEOUT_MINUTES) { - const envTimeout = parseInt(process.env.INPUT_TIMEOUT_MINUTES, 10); - if (isNaN(envTimeout) || envTimeout <= 0) { - throw new Error( - `INPUT_TIMEOUT_MINUTES must be a positive number, got: ${process.env.INPUT_TIMEOUT_MINUTES}`, - ); - } - timeoutMs = envTimeout * 60 * 1000; - } + // Wait for Claude to finish const exitCode = await new Promise((resolve) => { - let resolved = false; - - // Set a timeout for the process - const timeoutId = setTimeout(() => { - if (!resolved) { - console.error( - `Claude process timed out after ${timeoutMs / 1000} seconds`, - ); - claudeProcess.kill("SIGTERM"); - // Give it 5 seconds to terminate gracefully, then force kill - setTimeout(() => { - try { - claudeProcess.kill("SIGKILL"); - } catch (e) { - // Process may already be dead - } - }, 5000); - resolved = true; - resolve(124); // Standard timeout exit code - } - }, timeoutMs); - claudeProcess.on("close", (code) => { - if (!resolved) { - clearTimeout(timeoutId); - resolved = true; - resolve(code || 0); - } + resolve(code || 0); }); claudeProcess.on("error", (error) => { - if (!resolved) { - console.error("Claude process error:", error); - clearTimeout(timeoutId); - resolved = true; - resolve(1); - } + console.error("Claude process error:", error); + resolve(1); }); }); diff --git a/base-action/test/run-claude.test.ts b/base-action/test/run-claude.test.ts index 027a7c8..1c7d131 100644 --- a/base-action/test/run-claude.test.ts +++ b/base-action/test/run-claude.test.ts @@ -30,36 +30,6 @@ describe("prepareRunConfig", () => { expect(prepared.promptPath).toBe("/custom/prompt/path.txt"); }); - describe("timeoutMinutes validation", () => { - test("should accept valid timeoutMinutes value", () => { - const options: ClaudeOptions = { timeoutMinutes: "15" }; - expect(() => - prepareRunConfig("/tmp/test-prompt.txt", options), - ).not.toThrow(); - }); - - test("should throw error for non-numeric timeoutMinutes", () => { - const options: ClaudeOptions = { timeoutMinutes: "abc" }; - expect(() => prepareRunConfig("/tmp/test-prompt.txt", options)).toThrow( - "timeoutMinutes must be a positive number, got: abc", - ); - }); - - test("should throw error for negative timeoutMinutes", () => { - const options: ClaudeOptions = { timeoutMinutes: "-5" }; - expect(() => prepareRunConfig("/tmp/test-prompt.txt", options)).toThrow( - "timeoutMinutes must be a positive number, got: -5", - ); - }); - - test("should throw error for zero timeoutMinutes", () => { - const options: ClaudeOptions = { timeoutMinutes: "0" }; - expect(() => prepareRunConfig("/tmp/test-prompt.txt", options)).toThrow( - "timeoutMinutes must be a positive number, got: 0", - ); - }); - }); - describe("claudeArgs handling", () => { test("should parse and include custom claude arguments", () => { const options: ClaudeOptions = { diff --git a/examples/auto-fix-ci-signed/auto-fix-ci-signed.yml b/examples/auto-fix-ci-signed/auto-fix-ci-signed.yml index a6c6c4e..60145e0 100644 --- a/examples/auto-fix-ci-signed/auto-fix-ci-signed.yml +++ b/examples/auto-fix-ci-signed/auto-fix-ci-signed.yml @@ -93,6 +93,5 @@ jobs: Error logs: ${{ toJSON(fromJSON(steps.failure_details.outputs.result).errorLogs) }} anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }} - timeout_minutes: "30" use_commit_signing: true claude_args: "--allowedTools 'Edit,MultiEdit,Write,Read,Glob,Grep,LS,Bash(bun:*),Bash(npm:*),Bash(npx:*),Bash(gh:*),mcp__github_file_ops__commit_files,mcp__github_file_ops__delete_files'" diff --git a/examples/auto-fix-ci/auto-fix-ci.yml b/examples/auto-fix-ci/auto-fix-ci.yml index 87b5369..b6247fe 100644 --- a/examples/auto-fix-ci/auto-fix-ci.yml +++ b/examples/auto-fix-ci/auto-fix-ci.yml @@ -94,5 +94,4 @@ jobs: Error logs: ${{ toJSON(fromJSON(steps.failure_details.outputs.result).errorLogs) }} anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }} - timeout_minutes: "30" claude_args: "--allowedTools 'Edit,MultiEdit,Write,Read,Glob,Grep,LS,Bash(git:*),Bash(bun:*),Bash(npm:*),Bash(npx:*),Bash(gh:*)'" diff --git a/examples/claude-auto-review.yml b/examples/claude-auto-review.yml index 5e28039..004fdf3 100644 --- a/examples/claude-auto-review.yml +++ b/examples/claude-auto-review.yml @@ -21,7 +21,6 @@ jobs: uses: anthropics/claude-code-action@v1-dev with: anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }} - timeout_minutes: "60" prompt: | Please review this pull request and provide comprehensive feedback. diff --git a/examples/claude-experimental-review-mode.yml b/examples/claude-experimental-review-mode.yml index dfec8b3..bc9a367 100644 --- a/examples/claude-experimental-review-mode.yml +++ b/examples/claude-experimental-review-mode.yml @@ -31,7 +31,6 @@ jobs: with: anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }} # github_token not needed - uses default GITHUB_TOKEN for GitHub operations - timeout_minutes: "30" prompt: | Review this pull request comprehensively. diff --git a/examples/claude-pr-path-specific.yml b/examples/claude-pr-path-specific.yml index 1642e7d..6830a2e 100644 --- a/examples/claude-pr-path-specific.yml +++ b/examples/claude-pr-path-specific.yml @@ -27,7 +27,6 @@ jobs: uses: anthropics/claude-code-action@v1-dev with: anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }} - timeout_minutes: "60" prompt: | Please review this pull request focusing on the changed files. Provide feedback on: diff --git a/examples/claude-review-from-author.yml b/examples/claude-review-from-author.yml index 6361047..54cf559 100644 --- a/examples/claude-review-from-author.yml +++ b/examples/claude-review-from-author.yml @@ -26,7 +26,6 @@ jobs: uses: anthropics/claude-code-action@v1-dev with: anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }} - timeout_minutes: "60" prompt: | Please provide a thorough review of this pull request. diff --git a/examples/issue-deduplication.yml b/examples/issue-deduplication.yml index 3352e74..7a13d71 100644 --- a/examples/issue-deduplication.yml +++ b/examples/issue-deduplication.yml @@ -61,4 +61,3 @@ jobs: anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }} claude_args: | --allowedTools "mcp__github__get_issue,mcp__github__search_issues,mcp__github__list_issues,mcp__github__create_issue_comment,mcp__github__update_issue,mcp__github__get_issue_comments" - timeout_minutes: "5" diff --git a/examples/issue-triage.yml b/examples/issue-triage.yml index 9d169f2..4ad4ad7 100644 --- a/examples/issue-triage.yml +++ b/examples/issue-triage.yml @@ -73,4 +73,3 @@ jobs: anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }} claude_args: | --allowedTools "Bash(gh label list),mcp__github__get_issue,mcp__github__get_issue_comments,mcp__github__update_issue,mcp__github__search_issues,mcp__github__list_issues" - timeout_minutes: "5"