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:
@@ -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())
|
||||
`;
|
||||
}
|
||||
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
@@ -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"),
|
||||
|
||||
@@ -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={
|
||||
|
||||
Reference in New Issue
Block a user