feat: add claudeArgs input for direct CLI argument passing

- Add claude_args input to action.yml for flexible CLI control
- Parse arguments with industry-standard shell-quote library
- Maintain proper argument order: -p [claudeArgs] [legacy] [BASE_ARGS]
- Keep tag mode defaults (needed for functionality)
- Agent mode has no defaults (full user control)
- Add comprehensive tests for new functionality
- Add example workflow showing usage
This commit is contained in:
km-anthropic
2025-08-07 15:45:17 -07:00
parent e2bdca6133
commit a7759cfcd1
5 changed files with 156 additions and 101 deletions

View File

@@ -10,7 +10,8 @@ const execAsync = promisify(exec);
const PIPE_PATH = `${process.env.RUNNER_TEMP}/claude_prompt_pipe`;
const EXECUTION_FILE = `${process.env.RUNNER_TEMP}/claude-execution-output.json`;
const BASE_ARGS = ["-p", "--verbose", "--output-format", "stream-json"];
// These base args are always appended at the end
const BASE_ARGS = ["--verbose", "--output-format", "stream-json"];
export type ClaudeOptions = {
allowedTools?: string;
@@ -68,10 +69,21 @@ export function prepareRunConfig(
promptPath: string,
options: ClaudeOptions,
): PreparedConfig {
// Start with base args
const claudeArgs = [...BASE_ARGS];
// Add specific options first (these can be overridden by claudeArgs)
// Build arguments in correct order:
// 1. -p flag for prompt via pipe
const claudeArgs = ["-p"];
// 2. User's custom arguments (can override defaults)
if (options.claudeArgs && options.claudeArgs.trim() !== "") {
const parsed = parseShellArgs(options.claudeArgs);
const customArgs = parsed.filter(
(arg): arg is string => typeof arg === "string",
);
claudeArgs.push(...customArgs);
}
// 3. Legacy specific options for backward compatibility
// These will eventually be removed in favor of claudeArgs
if (options.allowedTools) {
claudeArgs.push("--allowedTools", options.allowedTools);
}
@@ -79,12 +91,6 @@ export function prepareRunConfig(
claudeArgs.push("--disallowedTools", options.disallowedTools);
}
if (options.maxTurns) {
const maxTurnsNum = parseInt(options.maxTurns, 10);
if (isNaN(maxTurnsNum) || maxTurnsNum <= 0) {
throw new Error(
`maxTurns must be a positive number, got: ${options.maxTurns}`,
);
}
claudeArgs.push("--max-turns", options.maxTurns);
}
if (options.mcpConfig) {
@@ -102,6 +108,11 @@ export function prepareRunConfig(
if (options.model) {
claudeArgs.push("--model", options.model);
}
// 4. Base args always at the end
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) {
@@ -111,15 +122,6 @@ export function prepareRunConfig(
}
}
// Parse and append custom arguments (these can override the above)
if (options.claudeArgs && options.claudeArgs.trim() !== "") {
const parsed = parseShellArgs(options.claudeArgs);
const customArgs = parsed.filter(
(arg): arg is string => typeof arg === "string",
);
claudeArgs.push(...customArgs);
}
// Parse custom environment variables
const customEnv = parseCustomEnvVars(options.claudeEnv);