etch-loop 0.5.1__tar.gz → 0.5.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {etch_loop-0.5.1 → etch_loop-0.5.2}/PKG-INFO +1 -1
- {etch_loop-0.5.1 → etch_loop-0.5.2}/pyproject.toml +1 -1
- etch_loop-0.5.2/src/etch/__init__.py +1 -0
- {etch_loop-0.5.1 → etch_loop-0.5.2}/src/etch/agent.py +4 -0
- {etch_loop-0.5.1 → etch_loop-0.5.2}/src/etch/git.py +1 -1
- {etch_loop-0.5.1 → etch_loop-0.5.2}/src/etch/loop.py +13 -7
- etch_loop-0.5.1/src/etch/__init__.py +0 -1
- {etch_loop-0.5.1 → etch_loop-0.5.2}/.github/workflows/workflow.yml +0 -0
- {etch_loop-0.5.1 → etch_loop-0.5.2}/README.md +0 -0
- {etch_loop-0.5.1 → etch_loop-0.5.2}/src/etch/analyze.py +0 -0
- {etch_loop-0.5.1 → etch_loop-0.5.2}/src/etch/cli.py +0 -0
- {etch_loop-0.5.1 → etch_loop-0.5.2}/src/etch/display.py +0 -0
- {etch_loop-0.5.1 → etch_loop-0.5.2}/src/etch/prompt.py +0 -0
- {etch_loop-0.5.1 → etch_loop-0.5.2}/src/etch/report.py +0 -0
- {etch_loop-0.5.1 → etch_loop-0.5.2}/src/etch/signals.py +0 -0
- {etch_loop-0.5.1 → etch_loop-0.5.2}/src/etch/templates/BREAK.md +0 -0
- {etch_loop-0.5.1 → etch_loop-0.5.2}/src/etch/templates/ETCH.md +0 -0
- {etch_loop-0.5.1 → etch_loop-0.5.2}/src/etch/templates/RUN.md +0 -0
- {etch_loop-0.5.1 → etch_loop-0.5.2}/src/etch/templates/SCAN.md +0 -0
- {etch_loop-0.5.1 → etch_loop-0.5.2}/uv.lock +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.5.2"
|
|
@@ -67,9 +67,11 @@ def run(
|
|
|
67
67
|
stdin_writer.join(timeout=30)
|
|
68
68
|
if stdin_writer.is_alive():
|
|
69
69
|
process.kill()
|
|
70
|
+
process.wait()
|
|
70
71
|
raise AgentError("Timed out writing prompt to claude stdin")
|
|
71
72
|
if stdin_exc:
|
|
72
73
|
process.kill()
|
|
74
|
+
process.wait()
|
|
73
75
|
raise AgentError(f"Failed to write prompt to claude stdin: {stdin_exc[0]}") from stdin_exc[0]
|
|
74
76
|
|
|
75
77
|
output_lines: list[str] = []
|
|
@@ -96,6 +98,7 @@ def run(
|
|
|
96
98
|
reader.join(timeout=timeout)
|
|
97
99
|
if reader.is_alive():
|
|
98
100
|
process.kill()
|
|
101
|
+
process.wait()
|
|
99
102
|
raise AgentError("claude subprocess timed out (output reader still running)")
|
|
100
103
|
|
|
101
104
|
stderr_reader.join(timeout=10)
|
|
@@ -104,6 +107,7 @@ def run(
|
|
|
104
107
|
process.wait(timeout=10)
|
|
105
108
|
except subprocess.TimeoutExpired:
|
|
106
109
|
process.kill()
|
|
110
|
+
process.wait()
|
|
107
111
|
raise AgentError("claude subprocess timed out waiting for exit")
|
|
108
112
|
|
|
109
113
|
stderr_output = "".join(stderr_lines).strip()
|
|
@@ -69,7 +69,7 @@ def commit(message: str, paths: list[str] | None = None) -> None:
|
|
|
69
69
|
raise GitError("Commit message must not be empty.")
|
|
70
70
|
|
|
71
71
|
# Stage all changes (or specific paths)
|
|
72
|
-
add_cmd = ["git", "add"] + (paths if paths else ["
|
|
72
|
+
add_cmd = ["git", "add"] + (paths if paths is not None else ["--all"])
|
|
73
73
|
try:
|
|
74
74
|
add_result = subprocess.run(
|
|
75
75
|
add_cmd,
|
|
@@ -84,8 +84,18 @@ def run(
|
|
|
84
84
|
# ── Scanner phase ─────────────────────────────────────────────────
|
|
85
85
|
disp.start_phase("scanner")
|
|
86
86
|
scanner_start = time.monotonic()
|
|
87
|
+
# Give the scanner any unresolved breaker findings as extra hints,
|
|
88
|
+
# so it can verify whether those areas are still broken.
|
|
89
|
+
effective_scan_text = scan_text
|
|
90
|
+
if last_breaker_output:
|
|
91
|
+
effective_scan_text += (
|
|
92
|
+
f"\n\n## Unresolved areas from previous adversarial review\n\n"
|
|
93
|
+
f"{last_breaker_output.strip()}\n\n"
|
|
94
|
+
f"Pay special attention to these spots — confirm whether each is "
|
|
95
|
+
f"still a genuine bug or has already been fixed.\n"
|
|
96
|
+
)
|
|
87
97
|
try:
|
|
88
|
-
scanner_output = agent.run(
|
|
98
|
+
scanner_output = agent.run(effective_scan_text, verbose=verbose)
|
|
89
99
|
except AgentError as exc:
|
|
90
100
|
disp.finish_phase("scanner", status="error", detail=str(exc),
|
|
91
101
|
duration=time.monotonic() - scanner_start, success=False)
|
|
@@ -124,17 +134,13 @@ def run(
|
|
|
124
134
|
iter_entry["scanner"] = {"status": "issues found", "detail": scanner_detail}
|
|
125
135
|
|
|
126
136
|
# ── Build fixer prompt ────────────────────────────────────────────
|
|
137
|
+
# Only the scanner's confirmed findings go to the fixer — the scanner
|
|
138
|
+
# already re-checked any breaker issues and reported only real ones.
|
|
127
139
|
fixer_prompt = prompt_text
|
|
128
140
|
fixer_prompt += (
|
|
129
141
|
f"\n\n## Scanner findings\n\n{scanner_output.strip()}\n\n"
|
|
130
142
|
f"Fix these specific issues.\n"
|
|
131
143
|
)
|
|
132
|
-
if last_breaker_output:
|
|
133
|
-
fixer_prompt += (
|
|
134
|
-
f"\n\n## Breaker findings from previous iteration\n\n"
|
|
135
|
-
f"{last_breaker_output.strip()}\n\n"
|
|
136
|
-
f"Also address these if not already covered above.\n"
|
|
137
|
-
)
|
|
138
144
|
|
|
139
145
|
# ── Fixer phase ───────────────────────────────────────────────────
|
|
140
146
|
disp.start_phase("fixer")
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "0.5.1"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|