File size: 2,901 Bytes
71b4454
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
import ast
import os
from typing import Dict, List, Any, Optional, Callable

class AutonomousCodeBuilder:
    """Manages file generation, incremental patching, syntax validation, and self-healing repair loops."""

    def __init__(self, workspace_root: str = "."):
        self.workspace_root = workspace_root

    def generate_project(self, files: Dict[str, str]) -> List[str]:
        """Scaffolds directory structures and writes initial project file assets."""
        created_files = []
        for relative_path, content in files.items():
            full_path = os.path.join(self.workspace_root, relative_path)
            os.makedirs(os.path.dirname(full_path), exist_ok=True)
            with open(full_path, "w", encoding="utf-8") as f:
                f.write(content)
            created_files.append(relative_path)
        return created_files

    def apply_patch(self, relative_path: str, search_text: str, replace_text: str) -> bool:
        """Applies targeted incremental search-and-replace patches to workspace files."""
        full_path = os.path.join(self.workspace_root, relative_path)
        if not os.path.exists(full_path):
            return False

        with open(full_path, "r", encoding="utf-8") as f:
            content = f.read()

        if search_text not in content:
            return False

        new_content = content.replace(search_text, replace_text, 1)
        with open(full_path, "w", encoding="utf-8") as f:
            f.write(new_content)
        return True

    def validate_syntax(self, relative_path: str) -> Optional[str]:
        """Validates Python AST structure and returns syntax error message if invalid."""
        full_path = os.path.join(self.workspace_root, relative_path)
        if not os.path.exists(full_path):
            return f"File not found: {relative_path}"

        with open(full_path, "r", encoding="utf-8") as f:
            content = f.read()

        try:
            ast.parse(content)
            return None
        except SyntaxError as e:
            return f"SyntaxError on line {e.lineno}: {e.msg}"

    def auto_repair(
        self,
        relative_path: str,
        repair_fn: Callable[[str, str], Optional[str]],
        max_attempts: int = 3
    ) -> bool:
        """Executes automated repair loop until syntax validation passes or max_attempts is reached."""
        error_msg = self.validate_syntax(relative_path)
        attempts = 0

        while error_msg and attempts < max_attempts:
            attempts += 1
            repaired_code = repair_fn(relative_path, error_msg)
            if repaired_code is not None:
                full_path = os.path.join(self.workspace_root, relative_path)
                with open(full_path, "w", encoding="utf-8") as f:
                    f.write(repaired_code)

            error_msg = self.validate_syntax(relative_path)

        return error_msg is None