claude-dev-env 1.85.0 → 1.86.1
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.
- package/_shared/pr-loop/scripts/code_rules_gate.py +18 -1
- package/_shared/pr-loop/scripts/pr_loop_shared_constants/terminology_sweep_constants.py +142 -7
- package/_shared/pr-loop/scripts/terminology_sweep.py +288 -92
- package/_shared/pr-loop/scripts/tests/test_code_rules_gate.py +89 -0
- package/_shared/pr-loop/scripts/tests/test_terminology_sweep.py +180 -91
- package/agents/code-quality-agent.md +1 -1
- package/hooks/blocking/CLAUDE.md +1 -0
- package/hooks/blocking/code_rules_dead_module_constant.py +7 -4
- package/hooks/blocking/session_edit_stage_gate.py +654 -0
- package/hooks/blocking/test_session_edit_stage_gate.py +537 -0
- package/hooks/hooks.json +30 -0
- package/hooks/hooks_constants/CLAUDE.md +2 -0
- package/hooks/hooks_constants/session_edit_stage_gate_constants.py +92 -0
- package/hooks/hooks_constants/task_list_loop_starter_constants.py +18 -0
- package/hooks/lifecycle/CLAUDE.md +1 -1
- package/hooks/observability/CLAUDE.md +2 -0
- package/hooks/observability/session_file_edit_tracker.py +224 -0
- package/hooks/observability/test_session_file_edit_tracker.py +174 -0
- package/hooks/session/CLAUDE.md +6 -2
- package/hooks/session/session_edit_tracker_cleanup.py +120 -0
- package/hooks/session/task_list_loop_starter.py +36 -0
- package/hooks/session/test_session_edit_tracker_cleanup.py +157 -0
- package/hooks/session/test_task_list_loop_starter.py +53 -0
- package/package.json +1 -1
- package/rules/CLAUDE.md +1 -0
- package/rules/re-stage-before-commit.md +31 -0
- package/skills/autoconverge/SKILL.md +4 -4
- package/skills/autoconverge/reference/gotchas.md +3 -2
- package/skills/autoconverge/reference/stop-conditions.md +22 -6
- package/skills/autoconverge/workflow/converge.clean-audit.test.mjs +528 -1
- package/skills/autoconverge/workflow/converge.contract.test.mjs +29 -21
- package/skills/autoconverge/workflow/converge.copilot-gate.test.mjs +77 -8
- package/skills/autoconverge/workflow/converge.mjs +456 -59
|
@@ -55,7 +55,10 @@ from pr_loop_shared_constants.inline_duplicate_body_span_constants import ( # n
|
|
|
55
55
|
from pr_loop_shared_constants.terminology_sweep_constants import ( # noqa: E402
|
|
56
56
|
TERMINOLOGY_SWEEP_GATE_HEADER,
|
|
57
57
|
)
|
|
58
|
-
from terminology_sweep import
|
|
58
|
+
from terminology_sweep import ( # noqa: E402
|
|
59
|
+
repository_environment,
|
|
60
|
+
staged_terminology_findings,
|
|
61
|
+
)
|
|
59
62
|
|
|
60
63
|
ValidateContentCallable = Callable[..., list[str]]
|
|
61
64
|
|
|
@@ -176,6 +179,7 @@ def resolve_merge_base(repository_root: Path, base_reference: str) -> str:
|
|
|
176
179
|
encoding="utf-8",
|
|
177
180
|
errors="replace",
|
|
178
181
|
check=False,
|
|
182
|
+
env=repository_environment(),
|
|
179
183
|
)
|
|
180
184
|
if merge_result.returncode != 0:
|
|
181
185
|
print(
|
|
@@ -249,6 +253,7 @@ def paths_from_git_staged(repository_root: Path) -> list[Path]:
|
|
|
249
253
|
cwd=str(repository_root),
|
|
250
254
|
capture_output=True,
|
|
251
255
|
check=False,
|
|
256
|
+
env=repository_environment(),
|
|
252
257
|
)
|
|
253
258
|
if name_result.returncode != 0:
|
|
254
259
|
stderr_text = name_result.stderr.decode("utf-8", errors="replace")
|
|
@@ -299,6 +304,7 @@ def staged_file_line_count(
|
|
|
299
304
|
encoding="utf-8",
|
|
300
305
|
errors="replace",
|
|
301
306
|
check=False,
|
|
307
|
+
env=repository_environment(),
|
|
302
308
|
)
|
|
303
309
|
if show_result.returncode != 0:
|
|
304
310
|
print(
|
|
@@ -339,6 +345,7 @@ def is_staged_file_newly_added(
|
|
|
339
345
|
encoding="utf-8",
|
|
340
346
|
errors="replace",
|
|
341
347
|
check=False,
|
|
348
|
+
env=repository_environment(),
|
|
342
349
|
)
|
|
343
350
|
if status_result.returncode != 0:
|
|
344
351
|
print(
|
|
@@ -379,6 +386,7 @@ def added_lines_for_staged_file(
|
|
|
379
386
|
encoding="utf-8",
|
|
380
387
|
errors="replace",
|
|
381
388
|
check=False,
|
|
389
|
+
env=repository_environment(),
|
|
382
390
|
)
|
|
383
391
|
if diff_result.returncode != 0:
|
|
384
392
|
print(
|
|
@@ -451,6 +459,7 @@ def paths_from_git_diff(repository_root: Path, base_reference: str) -> list[Path
|
|
|
451
459
|
cwd=str(repository_root),
|
|
452
460
|
capture_output=True,
|
|
453
461
|
check=False,
|
|
462
|
+
env=repository_environment(),
|
|
454
463
|
)
|
|
455
464
|
if name_result.returncode != 0:
|
|
456
465
|
stderr_text = name_result.stderr.decode("utf-8", errors="replace")
|
|
@@ -696,6 +705,7 @@ def is_file_new_at_base(
|
|
|
696
705
|
encoding="utf-8",
|
|
697
706
|
errors="replace",
|
|
698
707
|
check=False,
|
|
708
|
+
env=repository_environment(),
|
|
699
709
|
)
|
|
700
710
|
return cat_result.returncode != 0
|
|
701
711
|
|
|
@@ -733,6 +743,7 @@ def added_lines_for_file(
|
|
|
733
743
|
encoding="utf-8",
|
|
734
744
|
errors="replace",
|
|
735
745
|
check=False,
|
|
746
|
+
env=repository_environment(),
|
|
736
747
|
)
|
|
737
748
|
if diff_result.returncode != 0:
|
|
738
749
|
print(
|
|
@@ -801,6 +812,7 @@ def renamed_file_source_map_since(
|
|
|
801
812
|
cwd=str(repository_root),
|
|
802
813
|
capture_output=True,
|
|
803
814
|
check=False,
|
|
815
|
+
env=repository_environment(),
|
|
804
816
|
)
|
|
805
817
|
if name_status_result.returncode != 0:
|
|
806
818
|
stderr_text = name_status_result.stderr.decode("utf-8", errors="replace")
|
|
@@ -875,6 +887,7 @@ def added_lines_for_renamed_file(
|
|
|
875
887
|
encoding="utf-8",
|
|
876
888
|
errors="replace",
|
|
877
889
|
check=False,
|
|
890
|
+
env=repository_environment(),
|
|
878
891
|
)
|
|
879
892
|
if diff_result.returncode != 0:
|
|
880
893
|
print(
|
|
@@ -1229,6 +1242,7 @@ def read_prior_committed_content(
|
|
|
1229
1242
|
encoding="utf-8",
|
|
1230
1243
|
errors="replace",
|
|
1231
1244
|
check=False,
|
|
1245
|
+
env=repository_environment(),
|
|
1232
1246
|
)
|
|
1233
1247
|
if show_result.returncode != 0:
|
|
1234
1248
|
return ""
|
|
@@ -1254,6 +1268,7 @@ def read_staged_content(
|
|
|
1254
1268
|
cwd=str(repository_root),
|
|
1255
1269
|
capture_output=True,
|
|
1256
1270
|
check=False,
|
|
1271
|
+
env=repository_environment(),
|
|
1257
1272
|
)
|
|
1258
1273
|
if git_show_process.returncode != 0:
|
|
1259
1274
|
return None
|
|
@@ -1281,6 +1296,7 @@ def staged_blob_exists(
|
|
|
1281
1296
|
cwd=str(repository_root),
|
|
1282
1297
|
capture_output=True,
|
|
1283
1298
|
check=False,
|
|
1299
|
+
env=repository_environment(),
|
|
1284
1300
|
)
|
|
1285
1301
|
return git_cat_file_process.returncode == 0
|
|
1286
1302
|
|
|
@@ -1567,6 +1583,7 @@ def run_staged_test_files(repository_root: Path) -> int:
|
|
|
1567
1583
|
cwd=str(repository_root),
|
|
1568
1584
|
timeout=STAGED_PYTEST_TIMEOUT_SECONDS,
|
|
1569
1585
|
check=False,
|
|
1586
|
+
env=repository_environment(),
|
|
1570
1587
|
)
|
|
1571
1588
|
if pytest_process.returncode == PYTEST_NO_TESTS_COLLECTED_EXIT_CODE:
|
|
1572
1589
|
return 0
|
|
@@ -8,7 +8,7 @@ ALL_SWEEP_CODE_FILE_EXTENSIONS: frozenset[str] = frozenset(
|
|
|
8
8
|
|
|
9
9
|
MARKDOWN_FILE_EXTENSION: str = ".md"
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
INLINE_CODE_SPAN_PATTERN: re.Pattern[str] = re.compile(r"`[^`]*`")
|
|
12
12
|
|
|
13
13
|
SNAKE_CASE_IDENTIFIER_PATTERN: re.Pattern[str] = re.compile(
|
|
14
14
|
r"\b[a-z][a-z0-9]*(?:_[a-z0-9]+)+\b"
|
|
@@ -26,16 +26,12 @@ HYPHENATED_PROSE_TOKEN_PATTERN: re.Pattern[str] = re.compile(
|
|
|
26
26
|
r"\b[A-Za-z][A-Za-z0-9]*(?:-[A-Za-z][A-Za-z0-9]*)+\b"
|
|
27
27
|
)
|
|
28
28
|
|
|
29
|
+
PROSE_WORD_PATTERN: re.Pattern[str] = re.compile(r"[A-Za-z][A-Za-z0-9]*")
|
|
30
|
+
|
|
29
31
|
STRING_LITERAL_CONTENT_PATTERN: re.Pattern[str] = re.compile(
|
|
30
32
|
r"\"([^\"]*)\"|'([^']*)'|`([^`]*)`"
|
|
31
33
|
)
|
|
32
34
|
|
|
33
|
-
TEST_DIRECTORY_PATH_SEGMENT: str = "/tests/"
|
|
34
|
-
|
|
35
|
-
TEST_FILE_NAME_PREFIX: str = "test_"
|
|
36
|
-
|
|
37
|
-
ALL_TEST_FILE_NAME_INFIX_MARKERS: tuple[str, ...] = ("_test.", ".test.", ".spec.")
|
|
38
|
-
|
|
39
35
|
DIFF_FILE_HEADER_PREFIX: str = "+++ "
|
|
40
36
|
|
|
41
37
|
DIFF_HUNK_HEADER_PATTERN: re.Pattern[str] = re.compile(
|
|
@@ -117,3 +113,142 @@ TERMINOLOGY_SWEEP_GATE_HEADER: str = (
|
|
|
117
113
|
"terminology_sweep: {finding_count} cross-surface terminology near-miss(es) "
|
|
118
114
|
"on staged prose:"
|
|
119
115
|
)
|
|
116
|
+
|
|
117
|
+
ALL_PROSE_STOPWORD_TOKENS: frozenset[str] = frozenset(
|
|
118
|
+
{
|
|
119
|
+
"a",
|
|
120
|
+
"an",
|
|
121
|
+
"the",
|
|
122
|
+
"to",
|
|
123
|
+
"of",
|
|
124
|
+
"in",
|
|
125
|
+
"on",
|
|
126
|
+
"at",
|
|
127
|
+
"by",
|
|
128
|
+
"as",
|
|
129
|
+
"is",
|
|
130
|
+
"are",
|
|
131
|
+
"was",
|
|
132
|
+
"were",
|
|
133
|
+
"be",
|
|
134
|
+
"been",
|
|
135
|
+
"being",
|
|
136
|
+
"it",
|
|
137
|
+
"its",
|
|
138
|
+
"this",
|
|
139
|
+
"that",
|
|
140
|
+
"these",
|
|
141
|
+
"those",
|
|
142
|
+
"each",
|
|
143
|
+
"every",
|
|
144
|
+
"any",
|
|
145
|
+
"all",
|
|
146
|
+
"both",
|
|
147
|
+
"few",
|
|
148
|
+
"many",
|
|
149
|
+
"some",
|
|
150
|
+
"such",
|
|
151
|
+
"and",
|
|
152
|
+
"or",
|
|
153
|
+
"nor",
|
|
154
|
+
"but",
|
|
155
|
+
"if",
|
|
156
|
+
"then",
|
|
157
|
+
"than",
|
|
158
|
+
"so",
|
|
159
|
+
"not",
|
|
160
|
+
"no",
|
|
161
|
+
"with",
|
|
162
|
+
"for",
|
|
163
|
+
"from",
|
|
164
|
+
"into",
|
|
165
|
+
"onto",
|
|
166
|
+
"over",
|
|
167
|
+
"under",
|
|
168
|
+
"up",
|
|
169
|
+
"down",
|
|
170
|
+
"out",
|
|
171
|
+
"off",
|
|
172
|
+
"own",
|
|
173
|
+
"same",
|
|
174
|
+
"just",
|
|
175
|
+
"still",
|
|
176
|
+
"yet",
|
|
177
|
+
"ever",
|
|
178
|
+
"never",
|
|
179
|
+
"now",
|
|
180
|
+
"here",
|
|
181
|
+
"there",
|
|
182
|
+
"where",
|
|
183
|
+
"when",
|
|
184
|
+
"how",
|
|
185
|
+
"what",
|
|
186
|
+
"which",
|
|
187
|
+
"who",
|
|
188
|
+
"whom",
|
|
189
|
+
"whose",
|
|
190
|
+
"why",
|
|
191
|
+
"we",
|
|
192
|
+
"you",
|
|
193
|
+
"they",
|
|
194
|
+
"he",
|
|
195
|
+
"she",
|
|
196
|
+
"i",
|
|
197
|
+
"me",
|
|
198
|
+
"my",
|
|
199
|
+
"your",
|
|
200
|
+
"their",
|
|
201
|
+
"our",
|
|
202
|
+
"his",
|
|
203
|
+
"her",
|
|
204
|
+
"them",
|
|
205
|
+
"us",
|
|
206
|
+
"do",
|
|
207
|
+
"does",
|
|
208
|
+
"did",
|
|
209
|
+
"done",
|
|
210
|
+
"has",
|
|
211
|
+
"have",
|
|
212
|
+
"had",
|
|
213
|
+
"having",
|
|
214
|
+
"can",
|
|
215
|
+
"could",
|
|
216
|
+
"may",
|
|
217
|
+
"might",
|
|
218
|
+
"must",
|
|
219
|
+
"shall",
|
|
220
|
+
"should",
|
|
221
|
+
"will",
|
|
222
|
+
"would",
|
|
223
|
+
"s",
|
|
224
|
+
}
|
|
225
|
+
)
|
|
226
|
+
|
|
227
|
+
ALL_GIT_GREP_BASE_TREE_COMMAND_PREFIX: tuple[str, ...] = (
|
|
228
|
+
"git",
|
|
229
|
+
"grep",
|
|
230
|
+
"--quiet",
|
|
231
|
+
"--word-regexp",
|
|
232
|
+
"--fixed-strings",
|
|
233
|
+
)
|
|
234
|
+
|
|
235
|
+
GIT_BASE_TREE_REVISION: str = "HEAD"
|
|
236
|
+
|
|
237
|
+
ALL_STRING_ESCAPE_SEQUENCES: tuple[str, ...] = (
|
|
238
|
+
"\\n",
|
|
239
|
+
"\\t",
|
|
240
|
+
"\\r",
|
|
241
|
+
"\\\\",
|
|
242
|
+
)
|
|
243
|
+
|
|
244
|
+
TEST_FILE_PREFIX: str = "test_"
|
|
245
|
+
|
|
246
|
+
TEST_FILE_SUFFIX: str = "_test"
|
|
247
|
+
|
|
248
|
+
TEST_DIRECTORY_PATH_SEGMENT: str = "/tests/"
|
|
249
|
+
|
|
250
|
+
ALL_TEST_FILE_NAME_INFIX_MARKERS: tuple[str, ...] = ("_test.", ".test.", ".spec.")
|
|
251
|
+
|
|
252
|
+
PROSE_WINDOW_WORD_SEPARATOR: str = " "
|
|
253
|
+
|
|
254
|
+
IDENTIFIER_TOKEN_SEPARATOR: str = "_"
|