etch-loop 0.4.5__tar.gz → 0.4.7__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.
Files changed (24) hide show
  1. {etch_loop-0.4.5 → etch_loop-0.4.7}/PKG-INFO +1 -1
  2. {etch_loop-0.4.5 → etch_loop-0.4.7}/pyproject.toml +1 -1
  3. etch_loop-0.4.7/src/etch/__init__.py +1 -0
  4. {etch_loop-0.4.5 → etch_loop-0.4.7}/src/etch/analyze.py +25 -22
  5. {etch_loop-0.4.5 → etch_loop-0.4.7}/src/etch/signals.py +19 -10
  6. {etch_loop-0.4.5 → etch_loop-0.4.7}/src/etch/templates/BREAK.md +6 -6
  7. {etch_loop-0.4.5 → etch_loop-0.4.7}/src/etch/templates/ETCH.md +6 -10
  8. {etch_loop-0.4.5 → etch_loop-0.4.7}/src/etch/templates/RUN.md +7 -10
  9. {etch_loop-0.4.5 → etch_loop-0.4.7}/src/etch/templates/SCAN.md +6 -6
  10. etch_loop-0.4.5/src/etch/__init__.py +0 -1
  11. {etch_loop-0.4.5 → etch_loop-0.4.7}/.github/workflows/workflow.yml +0 -0
  12. {etch_loop-0.4.5 → etch_loop-0.4.7}/README.md +0 -0
  13. {etch_loop-0.4.5 → etch_loop-0.4.7}/src/etch/agent.py +0 -0
  14. {etch_loop-0.4.5 → etch_loop-0.4.7}/src/etch/cli.py +0 -0
  15. {etch_loop-0.4.5 → etch_loop-0.4.7}/src/etch/display.py +0 -0
  16. {etch_loop-0.4.5 → etch_loop-0.4.7}/src/etch/git.py +0 -0
  17. {etch_loop-0.4.5 → etch_loop-0.4.7}/src/etch/loop.py +0 -0
  18. {etch_loop-0.4.5 → etch_loop-0.4.7}/src/etch/prompt.py +0 -0
  19. {etch_loop-0.4.5 → etch_loop-0.4.7}/src/etch/report.py +0 -0
  20. {etch_loop-0.4.5 → etch_loop-0.4.7}/tests/__init__.py +0 -0
  21. {etch_loop-0.4.5 → etch_loop-0.4.7}/tests/test_git.py +0 -0
  22. {etch_loop-0.4.5 → etch_loop-0.4.7}/tests/test_loop.py +0 -0
  23. {etch_loop-0.4.5 → etch_loop-0.4.7}/tests/test_prompt.py +0 -0
  24. {etch_loop-0.4.5 → etch_loop-0.4.7}/tests/test_signals.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: etch-loop
3
- Version: 0.4.5
3
+ Version: 0.4.7
4
4
  Summary: Run Claude Code in a fix-break loop until your codebase is clean
5
5
  License: MIT
6
6
  Requires-Python: >=3.11
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "etch-loop"
3
- version = "0.4.5"
3
+ version = "0.4.7"
4
4
  requires-python = ">=3.11"
5
5
  description = "Run Claude Code in a fix-break loop until your codebase is clean"
6
6
  readme = "README.md"
@@ -0,0 +1 @@
1
+ __version__ = "0.4.7"
@@ -179,9 +179,12 @@ For each issue, include the file path, line number (if known), and a one-line de
179
179
  5. List each confirmed issue on its own line, e.g.:
180
180
  - src/auth.py:42 — crashes with empty token string (no guard)
181
181
  - src/api.js:108 — unhandled promise rejection will silently fail
182
- 6. End your output with EXACTLY one of these tokens on its own line:
183
- - `ETCH_ISSUES_FOUND`if you found confirmed bugs worth fixing
184
- - `ETCH_ALL_CLEAR` if the code looks solid or you found nothing certain
182
+ 6. Before the signal token, write your summary in this exact format it appears directly in the terminal:
183
+ `<etch_summary>3 bugs found null deref in auth.py:42, off-by-one in parser.py:88</etch_summary>`
184
+ `<etch_summary>no confirmed bugs found</etch_summary>`
185
+ 7. End with EXACTLY one of these on its own line:
186
+ `ETCH_ISSUES_FOUND`
187
+ `ETCH_ALL_CLEAR`
185
188
 
186
189
  ## Scope
187
190
 
@@ -210,18 +213,18 @@ Scan the codebase for:
210
213
  ## Rules
211
214
 
212
215
  1. Fix only what you find — do not refactor, rename, or reorganize
213
- 2. One logical fix per commit (the harness will commit for you)
214
- 3. Do not add comments explaining what you fixed
215
- 4. If you find nothing, make no changes
216
+ 2. Do not add comments explaining what you fixed
217
+ 3. If you find nothing, make no changes
216
218
 
217
219
  ## Scope
218
220
 
219
221
  {scope}
220
222
 
221
- ## Commit format
223
+ ## Terminal output (required)
222
224
 
223
- The harness commits automatically. Each commit will be:
224
- fix(edge): <short description of what was fixed>
225
+ After making changes (or deciding there is nothing to fix), write your summary in this exact format — it appears in the terminal and is used as the commit message:
226
+ `<etch_summary>fixed 3 issues null guard in auth.py, bounds check in parser.py, timeout in agent.py</etch_summary>`
227
+ `<etch_summary>nothing to fix — all reported issues were already handled</etch_summary>`
225
228
  """
226
229
 
227
230
 
@@ -250,9 +253,12 @@ Be adversarial — think like someone actively trying to make this code fail.
250
253
 
251
254
  1. DO NOT edit any files — read only
252
255
  2. Report your findings clearly, one per line
253
- 3. End your output with EXACTLY one of these tokens on its own line:
254
- - `ETCH_ISSUES_FOUND`if you found anything worth fixing
255
- - `ETCH_ALL_CLEAR`if the code looks solid
256
+ 3. Before the signal token, write your summary in this exact format it appears directly in the terminal:
257
+ `<etch_summary>2 issuesunguarded empty list in sorter.py:14, exception swallowed in loader.py:67</etch_summary>`
258
+ `<etch_summary>no issues found — code looks solid</etch_summary>`
259
+ 4. End with EXACTLY one of these on its own line:
260
+ `ETCH_ISSUES_FOUND`
261
+ `ETCH_ALL_CLEAR`
256
262
 
257
263
  ## Scope
258
264
 
@@ -292,16 +298,13 @@ You are a test engineer. The fixer has just made changes. Your job is to write t
292
298
 
293
299
  1. You MAY edit test files — that is your job
294
300
  2. Do NOT touch production code — only tests
295
- 3. After running, report clearly:
296
- - If ALL tests pass:
297
- - `ETCH_SUMMARY: <e.g. "wrote 4 tests, all 51 passed">`
298
- - `ETCH_ALL_CLEAR`
299
- - If ANY test fails due to a bug in the production code:
300
- - `ETCH_SUMMARY: <what failed and why>`
301
- - Include the relevant error output
302
- - `ETCH_ISSUES_FOUND`
303
- - If tests fail because the tests themselves are wrong (flawed test logic):
304
- - Fix the test and re-run before reporting
301
+ 3. If tests fail because of flawed test logic, fix the test and re-run before reporting
302
+ 4. When done, write your summary in this exact format — it appears directly in the terminal:
303
+ `<etch_summary>wrote 4 tests, all 51 passed</etch_summary>`
304
+ `<etch_summary>2 tests failed — TypeError in test_auth.py:38, production bug in token.py:12</etch_summary>`
305
+ 5. End with EXACTLY one of these on its own line:
306
+ `ETCH_ALL_CLEAR` if all tests pass
307
+ `ETCH_ISSUES_FOUND` if tests reveal a bug in production code
305
308
  """
306
309
 
307
310
 
@@ -1,5 +1,7 @@
1
1
  """Signal parsing for breaker agent output."""
2
2
 
3
+ import re
4
+
3
5
  _TOKEN_CLEAR = "ETCH_ALL_CLEAR"
4
6
  _TOKEN_ISSUES = "ETCH_ISSUES_FOUND"
5
7
  _PUNCTUATION_ONLY = set("-=*_`~><|")
@@ -35,14 +37,22 @@ def parse(output: str) -> str:
35
37
  def extract_commit_message(output: str, fallback: str) -> str:
36
38
  """Extract a short commit message from fixer output.
37
39
 
38
- Looks for the first substantive line that describes what was changed.
39
- Falls back to `fallback` if nothing useful is found.
40
+ Tries ETCH_SUMMARY first (the explicit summary line), then falls back to
41
+ scanning for the first substantive line that describes what was changed.
40
42
  Returns a string starting with 'fix(edge): '.
41
43
  """
42
44
  if not isinstance(output, str) or not output.strip():
43
45
  return fallback
44
46
 
45
- _SKIP_STARTS = ("i ", "i've ", "i have ", "here ", "the following", "done", "no ")
47
+ # Prefer the explicit ETCH_SUMMARY line
48
+ summary = extract_summary(output)
49
+ if summary:
50
+ msg = summary[:72].rstrip(".,;:")
51
+ if not msg.lower().startswith("fix"):
52
+ msg = f"fix(edge): {msg[0].lower()}{msg[1:]}"
53
+ return msg
54
+
55
+ _SKIP_STARTS = ("i ", "i've ", "i have ", "here ", "here's", "the following", "done", "no ", "summary", "below")
46
56
  _SKIP_WORDS = {"ok", "done", "nothing", "complete", "finished"}
47
57
 
48
58
  for line in output.splitlines():
@@ -70,19 +80,18 @@ def extract_commit_message(output: str, fallback: str) -> str:
70
80
 
71
81
 
72
82
  def extract_summary(output: str) -> str:
73
- """Extract the ETCH_SUMMARY line written by an agent.
83
+ """Extract the summary from an <etch_summary> tag in agent output.
74
84
 
75
- Agents are prompted to write a line like:
76
- ETCH_SUMMARY: fixed 3 null-guard issues in auth.py
85
+ Agents are prompted to write:
86
+ <etch_summary>fixed 3 null-guard issues in auth.py</etch_summary>
77
87
 
78
88
  Returns the summary text, or empty string if not found.
79
89
  """
80
90
  if not isinstance(output, str):
81
91
  return ""
82
- for line in output.splitlines():
83
- stripped = line.strip()
84
- if stripped.startswith("ETCH_SUMMARY:"):
85
- return stripped[len("ETCH_SUMMARY:"):].strip()
92
+ m = re.search(r"<etch_summary>(.*?)</etch_summary>", output, re.DOTALL)
93
+ if m:
94
+ return m.group(1).strip()
86
95
  return ""
87
96
 
88
97
 
@@ -19,12 +19,12 @@ Be adversarial — think like someone actively trying to make this code fail.
19
19
 
20
20
  1. DO NOT edit any files — read only
21
21
  2. Report your findings clearly, one per line
22
- 3. Before the signal token, write one line starting with `ETCH_SUMMARY:` summarising what you found:
23
- - `ETCH_SUMMARY: 2 issues — unguarded empty list in sorter.py:14, exception swallowed in loader.py:67`
24
- - `ETCH_SUMMARY: no issues found — code looks solid`
25
- 4. End your output with EXACTLY one of these tokens on its own line:
26
- - `ETCH_ISSUES_FOUND` — if you found anything worth fixing
27
- - `ETCH_ALL_CLEAR` — if the code looks solid
22
+ 3. Before the signal token, write your summary in this exact format it appears directly in the terminal:
23
+ `<etch_summary>2 issues — unguarded empty list in sorter.py:14, exception swallowed in loader.py:67</etch_summary>`
24
+ `<etch_summary>no issues found — code looks solid</etch_summary>`
25
+ 4. End with EXACTLY one of these on its own line:
26
+ `ETCH_ISSUES_FOUND`
27
+ `ETCH_ALL_CLEAR`
28
28
 
29
29
  ## Scope
30
30
 
@@ -15,19 +15,15 @@ Scan the codebase for:
15
15
  ## Rules
16
16
 
17
17
  1. Fix only what you find — do not refactor, rename, or reorganize
18
- 2. One logical fix per commit (the harness will commit for you)
19
- 3. Do not add comments explaining what you fixed
20
- 4. If you find nothing, make no changes
18
+ 2. Do not add comments explaining what you fixed
19
+ 3. If you find nothing, make no changes
21
20
 
22
21
  ## Scope
23
22
 
24
23
  Focus on: [edit this to narrow your scope, e.g. "src/auth/", "the payment module"]
25
24
 
26
- ## Output format
25
+ ## Terminal output (required)
27
26
 
28
- After making your changes, write one line at the end of your output:
29
- ETCH_SUMMARY: <concise summary, e.g. "fixed 3 issues — added null guards in auth.py, guarded empty input in parser.py">
30
- ETCH_SUMMARY: no changesnothing to fix
31
-
32
- The harness commits automatically. Each commit will be:
33
- fix(edge): <short description of what was fixed>
27
+ After making changes (or deciding there is nothing to fix), write your summary in this exact format — it appears in the terminal and is used as the commit message:
28
+ `<etch_summary>fixed 3 issues — null guard in auth.py, bounds check in parser.py, timeout in agent.py</etch_summary>`
29
+ `<etch_summary>nothing to fixall reported issues were already handled</etch_summary>`
@@ -20,13 +20,10 @@ You are a test engineer. The fixer has just made changes. Your job is to write t
20
20
 
21
21
  1. You MAY edit test files — that is your job
22
22
  2. Do NOT touch production code — only tests
23
- 3. After running, report clearly:
24
- - If ALL tests pass:
25
- - `ETCH_SUMMARY: <e.g. "wrote 4 tests, all 51 passed">`
26
- - `ETCH_ALL_CLEAR`
27
- - If ANY test fails due to a bug in the production code:
28
- - `ETCH_SUMMARY: <what failed and why>`
29
- - Include the relevant error output
30
- - `ETCH_ISSUES_FOUND`
31
- - If tests fail because the tests themselves are wrong (flawed test logic):
32
- - Fix the test and re-run before reporting
23
+ 3. If tests fail because of flawed test logic, fix the test and re-run before reporting
24
+ 4. When done, write your summary in this exact format — it appears directly in the terminal:
25
+ `<etch_summary>wrote 4 tests, all 51 passed</etch_summary>`
26
+ `<etch_summary>2 tests failed — TypeError in test_auth.py:38, production bug in token.py:12</etch_summary>`
27
+ 5. End with EXACTLY one of these on its own line:
28
+ `ETCH_ALL_CLEAR` if all tests pass
29
+ `ETCH_ISSUES_FOUND` if tests reveal a bug in production code
@@ -23,12 +23,12 @@ For each issue, include the file path, line number (if known), and a one-line de
23
23
  5. List each confirmed issue on its own line, e.g.:
24
24
  - src/auth.py:42 — crashes with empty token string (no guard)
25
25
  - src/api.js:108 — unhandled promise rejection will silently fail
26
- 6. Before the signal token, write one line starting with `ETCH_SUMMARY:` summarising what you found in plain English:
27
- - `ETCH_SUMMARY: found 3 issues — null dereference in auth.py:42, off-by-one in parser.py:88, unhandled OSError in git.py:31`
28
- - `ETCH_SUMMARY: no confirmed bugs found`
29
- 7. End your output with EXACTLY one of these tokens on its own line:
30
- - `ETCH_ISSUES_FOUND` — if you found confirmed bugs worth fixing
31
- - `ETCH_ALL_CLEAR` — if the code looks solid or you found nothing certain
26
+ 6. Before the signal token, write your summary in this exact format it appears directly in the terminal:
27
+ `<etch_summary>3 bugs found — null deref in auth.py:42, off-by-one in parser.py:88</etch_summary>`
28
+ `<etch_summary>no confirmed bugs found</etch_summary>`
29
+ 7. End with EXACTLY one of these on its own line:
30
+ `ETCH_ISSUES_FOUND`
31
+ `ETCH_ALL_CLEAR`
32
32
 
33
33
  ## Scope
34
34
 
@@ -1 +0,0 @@
1
- __version__ = "0.4.5"
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