From 93e0066391cdbdf82babcebd98325e9ef3517c08 Mon Sep 17 00:00:00 2001 From: AndyMik90 Date: Sat, 13 Dec 2025 15:55:01 +0100 Subject: [PATCH] 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. --- auto-claude-ui/src/main/title-generator.ts | 88 +++++++---- auto-claude/.auto-claude-security.json | 168 --------------------- auto-claude/implementation_plan.py | 9 +- auto-claude/linear_updater.py | 2 +- 4 files changed, 68 insertions(+), 199 deletions(-) delete mode 100644 auto-claude/.auto-claude-security.json diff --git a/auto-claude-ui/src/main/title-generator.ts b/auto-claude-ui/src/main/title-generator.ts index 33611de6..b3f0b62b 100644 --- a/auto-claude-ui/src/main/title-generator.ts +++ b/auto-claude-ui/src/main/title-generator.ts @@ -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()) `; } diff --git a/auto-claude/.auto-claude-security.json b/auto-claude/.auto-claude-security.json deleted file mode 100644 index 4a4fff8e..00000000 --- a/auto-claude/.auto-claude-security.json +++ /dev/null @@ -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" -} \ No newline at end of file diff --git a/auto-claude/implementation_plan.py b/auto-claude/implementation_plan.py index d5152484..2cc80813 100644 --- a/auto-claude/implementation_plan.py +++ b/auto-claude/implementation_plan.py @@ -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"), diff --git a/auto-claude/linear_updater.py b/auto-claude/linear_updater.py index add7fff1..e20f8d23 100644 --- a/auto-claude/linear_updater.py +++ b/auto-claude/linear_updater.py @@ -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={