chore: remove obsolete .auto-claude-security.json file and update Phase class to handle missing fields

- Deleted the .auto-claude-security.json file as it is no longer needed.
- Updated the Phase class's from_dict method to use default values for missing 'phase' and 'name' fields, improving robustness.
- Adjusted the ImplementationPlan class to ensure phases are indexed correctly when created from a dictionary.
- Updated the Linear SDK client model version for improved performance.
- Increased timeout duration for title generation in the TitleGenerator class and enhanced error logging for better diagnostics.
This commit is contained in:
AndyMik90
2025-12-13 15:55:01 +01:00
parent b0b5d71076
commit 93e0066391
4 changed files with 68 additions and 199 deletions
+62 -26
View File
@@ -133,10 +133,10 @@ export class TitleGenerator {
let output = '';
let errorOutput = '';
const timeout = setTimeout(() => {
debug('Title generation timed out');
console.log('[TitleGenerator] Title generation timed out after 60s');
childProcess.kill();
resolve(null);
}, 30000); // 30 second timeout
}, 60000); // 60 second timeout for SDK initialization + API call
childProcess.stdout?.on('data', (data: Buffer) => {
output += data.toString();
@@ -154,14 +154,19 @@ export class TitleGenerator {
debug('Generated title:', title);
resolve(title);
} else {
debug('Title generation failed', { code, errorOutput });
// Always log failures to help diagnose issues
console.log('[TitleGenerator] Title generation failed', {
code,
errorOutput: errorOutput.substring(0, 500),
output: output.substring(0, 200)
});
resolve(null);
}
});
childProcess.on('error', (err) => {
clearTimeout(timeout);
debug('Process error:', err.message);
console.log('[TitleGenerator] Process error:', err.message);
resolve(null);
});
});
@@ -180,36 +185,67 @@ Title:`;
}
/**
* Create the Python script to call Claude CLI
* Create the Python script to generate title using Claude Agent SDK
*/
private createGenerationScript(prompt: string): string {
// Escape the prompt for Python string
const escapedPrompt = prompt
.replace(/\\/g, '\\\\')
.replace(/"/g, '\\"')
.replace(/\n/g, '\\n');
// Escape the prompt for Python string - use JSON.stringify for safe escaping
const escapedPrompt = JSON.stringify(prompt);
return `
import subprocess
import asyncio
import sys
prompt = """${escapedPrompt}"""
async def generate_title():
try:
from claude_agent_sdk import ClaudeAgentOptions, ClaudeSDKClient
# Use Claude Code CLI to generate
# --max-turns 1: Single response (no back-and-forth needed)
# --model haiku: Faster model for simple text generation
result = subprocess.run(
['claude', '-p', prompt, '--output-format', 'text', '--max-turns', '1', '--model', 'haiku'],
capture_output=True,
text=True,
timeout=30
)
prompt = ${escapedPrompt}
if result.returncode == 0:
print(result.stdout.strip())
else:
print(result.stderr, file=sys.stderr)
sys.exit(1)
# Create a minimal client for simple text generation (no tools needed)
client = ClaudeSDKClient(
options=ClaudeAgentOptions(
model="claude-haiku-4-5",
system_prompt="You generate short, concise task titles (3-7 words). Output ONLY the title, nothing else. No quotes, no explanation, no preamble.",
max_turns=1,
)
)
async with client:
# Send the query
await client.query(prompt)
# Collect response text from AssistantMessage
response_text = ""
async for msg in client.receive_response():
msg_type = type(msg).__name__
if msg_type == "AssistantMessage" and hasattr(msg, "content"):
for block in msg.content:
block_type = type(block).__name__
if block_type == "TextBlock" and hasattr(block, "text"):
response_text += block.text
if response_text:
# Clean up the result
title = response_text.strip()
# Remove any quotes
title = title.strip('"').strip("'")
# Take first line only
title = title.split('\\n')[0].strip()
if title:
print(title)
sys.exit(0)
# If we get here, no valid response
sys.exit(1)
except ImportError as e:
print(f"Import error: {e}", file=sys.stderr)
sys.exit(1)
except Exception as e:
print(f"Error: {e}", file=sys.stderr)
sys.exit(1)
asyncio.run(generate_title())
`;
}
-168
View File
@@ -1,168 +0,0 @@
{
"base_commands": [
".",
"[",
"[[",
"ag",
"awk",
"basename",
"bash",
"bc",
"break",
"cat",
"cd",
"chmod",
"clear",
"cmp",
"column",
"comm",
"command",
"continue",
"cp",
"curl",
"cut",
"date",
"df",
"diff",
"dig",
"dirname",
"du",
"echo",
"egrep",
"env",
"eval",
"exec",
"exit",
"expand",
"export",
"expr",
"false",
"fd",
"fgrep",
"file",
"find",
"fmt",
"fold",
"gawk",
"gh",
"git",
"grep",
"gunzip",
"gzip",
"head",
"help",
"host",
"iconv",
"id",
"jobs",
"join",
"jq",
"kill",
"killall",
"less",
"let",
"ln",
"ls",
"lsof",
"man",
"mkdir",
"mktemp",
"more",
"mv",
"nl",
"paste",
"pgrep",
"ping",
"pkill",
"popd",
"printenv",
"printf",
"ps",
"pushd",
"pwd",
"read",
"readlink",
"realpath",
"reset",
"return",
"rev",
"rg",
"rm",
"rmdir",
"sed",
"seq",
"set",
"sh",
"shuf",
"sleep",
"sort",
"source",
"split",
"stat",
"tail",
"tar",
"tee",
"test",
"time",
"timeout",
"touch",
"tr",
"tree",
"true",
"type",
"uname",
"unexpand",
"uniq",
"unset",
"unzip",
"watch",
"wc",
"wget",
"whereis",
"which",
"whoami",
"xargs",
"yes",
"yq",
"zip",
"zsh"
],
"stack_commands": [
"ipython",
"jupyter",
"notebook",
"pdb",
"pip",
"pip3",
"pipx",
"pudb",
"python",
"python3"
],
"script_commands": [],
"custom_commands": [],
"detected_stack": {
"languages": [
"python"
],
"package_managers": [
"pip"
],
"frameworks": [],
"databases": [],
"infrastructure": [],
"cloud_providers": [],
"code_quality_tools": [],
"version_managers": []
},
"custom_scripts": {
"npm_scripts": [],
"make_targets": [],
"poetry_scripts": [],
"cargo_aliases": [],
"shell_scripts": []
},
"project_dir": "/Users/andremikalsen/Documents/Coding/autonomous-coding/auto-claude",
"created_at": "2025-12-11T21:19:19.074875",
"project_hash": "ef656cc9bb3236b96381a0dd319201e9"
}
+5 -4
View File
@@ -231,10 +231,11 @@ class Phase:
return result
@classmethod
def from_dict(cls, data: dict) -> "Phase":
def from_dict(cls, data: dict, fallback_phase: int = 1) -> "Phase":
"""Create Phase from dict. Uses fallback_phase if 'phase' field is missing."""
return cls(
phase=data["phase"],
name=data["name"],
phase=data.get("phase", fallback_phase),
name=data.get("name", f"Phase {fallback_phase}"),
type=PhaseType(data.get("type", "implementation")),
chunks=[Chunk.from_dict(c) for c in data.get("chunks", [])],
depends_on=data.get("depends_on", []),
@@ -314,7 +315,7 @@ class ImplementationPlan:
feature=data["feature"],
workflow_type=workflow_type,
services_involved=data.get("services_involved", []),
phases=[Phase.from_dict(p) for p in data.get("phases", [])],
phases=[Phase.from_dict(p, idx + 1) for idx, p in enumerate(data.get("phases", []))],
final_acceptance=data.get("final_acceptance", []),
created_at=data.get("created_at"),
updated_at=data.get("updated_at"),
+1 -1
View File
@@ -123,7 +123,7 @@ def _create_linear_client() -> ClaudeSDKClient:
return ClaudeSDKClient(
options=ClaudeAgentOptions(
model="claude-haiku-4-20250514", # Fast & cheap model for simple API calls
model="claude-haiku-4-5", # Fast & cheap model for simple API calls
system_prompt="You are a Linear API assistant. Execute the requested Linear operation precisely.",
allowed_tools=LINEAR_TOOLS,
mcp_servers={