Update Claude agent to use proper headless mode

- Replace --dangerously-skip-permissions with official headless mode flags
- Use -p (--print) for non-interactive mode
- Add --output-format json for structured responses
- Use --permission-mode acceptEdits for automation
- Parse JSON response and extract metadata (cost, duration, session_id)
- Handle both successful and error responses properly
- Reference: https://docs.anthropic.com/en/docs/claude-code/sdk/sdk-headless
This commit is contained in:
Colin McDonnell
2025-08-28 13:42:04 -07:00
parent 1abbd7ff41
commit 7745a0befb
2 changed files with 38 additions and 14 deletions
+20 -7
View File
@@ -39,8 +39,8 @@ export class ClaudeAgent implements Agent {
// Create a temporary file for the prompt
const promptFile = createTempFile(prompt, "prompt.txt");
// Execute Claude Code with the prompt
const command = `$HOME/.local/bin/claude --dangerously-skip-permissions "${promptFile}"`;
// Execute Claude Code with the prompt using proper headless mode
const command = `$HOME/.local/bin/claude -p "${promptFile}" --output-format json --permission-mode acceptEdits`;
core.info(`Executing: ${command}`);
const { stdout, stderr } = await executeCommand(command, {
@@ -51,20 +51,33 @@ export class ClaudeAgent implements Agent {
core.warning(`Claude Code stderr: ${stderr}`);
}
if (stdout) {
// Parse JSON response from Claude Code
let claudeResponse: any;
try {
claudeResponse = JSON.parse(stdout);
} catch {
core.warning("Failed to parse Claude Code JSON response, using raw output");
claudeResponse = { result: stdout };
}
if (claudeResponse.result) {
core.info("Claude Code output:");
console.log(stdout);
console.log(claudeResponse.result);
}
core.info("Claude Code executed successfully");
return {
success: true,
output: stdout,
error: stderr || undefined,
success: !claudeResponse.is_error,
output: claudeResponse.result || stdout,
error: claudeResponse.is_error ? claudeResponse.result : (stderr || undefined),
metadata: {
promptFile,
command,
session_id: claudeResponse.session_id,
cost_usd: claudeResponse.total_cost_usd,
duration_ms: claudeResponse.duration_ms,
num_turns: claudeResponse.num_turns,
},
};
} catch (error) {
+18 -7
View File
@@ -19861,7 +19861,7 @@ var ClaudeAgent = class {
core.info("Executing Claude Code...");
try {
const promptFile = createTempFile(prompt, "prompt.txt");
const command = `$HOME/.local/bin/claude --dangerously-skip-permissions "${promptFile}"`;
const command = `$HOME/.local/bin/claude -p "${promptFile}" --output-format json --permission-mode acceptEdits`;
core.info(`Executing: ${command}`);
const { stdout, stderr } = await executeCommand(command, {
ANTHROPIC_API_KEY: this.apiKey
@@ -19869,18 +19869,29 @@ var ClaudeAgent = class {
if (stderr) {
core.warning(`Claude Code stderr: ${stderr}`);
}
if (stdout) {
let claudeResponse;
try {
claudeResponse = JSON.parse(stdout);
} catch {
core.warning("Failed to parse Claude Code JSON response, using raw output");
claudeResponse = { result: stdout };
}
if (claudeResponse.result) {
core.info("Claude Code output:");
console.log(stdout);
console.log(claudeResponse.result);
}
core.info("Claude Code executed successfully");
return {
success: true,
output: stdout,
error: stderr || void 0,
success: !claudeResponse.is_error,
output: claudeResponse.result || stdout,
error: claudeResponse.is_error ? claudeResponse.result : stderr || void 0,
metadata: {
promptFile,
command
command,
session_id: claudeResponse.session_id,
cost_usd: claudeResponse.total_cost_usd,
duration_ms: claudeResponse.duration_ms,
num_turns: claudeResponse.num_turns
}
};
} catch (error) {