claude-dev-env 1.79.0 → 1.81.0

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 (76) hide show
  1. package/_shared/pr-loop/scripts/CLAUDE.md +3 -1
  2. package/_shared/pr-loop/scripts/code_rules_gate.py +116 -30
  3. package/_shared/pr-loop/scripts/copilot_quota.py +360 -0
  4. package/_shared/pr-loop/scripts/pr_loop_shared_constants/CLAUDE.md +2 -0
  5. package/_shared/pr-loop/scripts/pr_loop_shared_constants/code_rules_gate_constants.py +13 -0
  6. package/_shared/pr-loop/scripts/pr_loop_shared_constants/copilot_quota_constants.py +24 -0
  7. package/_shared/pr-loop/scripts/pr_loop_shared_constants/terminology_sweep_constants.py +113 -0
  8. package/_shared/pr-loop/scripts/terminology_sweep.py +467 -0
  9. package/_shared/pr-loop/scripts/tests/CLAUDE.md +8 -0
  10. package/_shared/pr-loop/scripts/tests/fixtures/copilot_internal_user_jonecho.json +76 -0
  11. package/_shared/pr-loop/scripts/tests/test_code_rules_gate.py +339 -0
  12. package/_shared/pr-loop/scripts/tests/test_copilot_quota.py +242 -0
  13. package/_shared/pr-loop/scripts/tests/test_copilot_quota_constants.py +63 -0
  14. package/_shared/pr-loop/scripts/tests/test_terminology_sweep.py +297 -0
  15. package/audit-rubrics/CLAUDE.md +3 -2
  16. package/audit-rubrics/category_rubrics/CLAUDE.md +2 -1
  17. package/audit-rubrics/category_rubrics/category-a-api-contracts.md +2 -1
  18. package/audit-rubrics/category_rubrics/category-j-code-rules-compliance.md +13 -1
  19. package/audit-rubrics/category_rubrics/category-p-name-vs-behavior-contract.md +19 -0
  20. package/audit-rubrics/category_rubrics/category-q-cross-surface-claims.md +46 -0
  21. package/audit-rubrics/prompts/CLAUDE.md +2 -1
  22. package/audit-rubrics/prompts/category-a-api-contracts.md +1 -0
  23. package/audit-rubrics/prompts/category-j-code-rules-compliance.md +19 -7
  24. package/audit-rubrics/prompts/category-p-name-vs-behavior-contract.md +14 -0
  25. package/audit-rubrics/prompts/category-q-cross-surface-claims.md +51 -0
  26. package/docs/CODE_RULES.md +2 -2
  27. package/hooks/blocking/CLAUDE.md +2 -0
  28. package/hooks/blocking/code_rules_annotations_length.py +59 -11
  29. package/hooks/blocking/code_rules_banned_identifiers.py +48 -9
  30. package/hooks/blocking/code_rules_command_dispatch.py +140 -0
  31. package/hooks/blocking/code_rules_docstrings.py +93 -0
  32. package/hooks/blocking/code_rules_enforcer.py +58 -4
  33. package/hooks/blocking/code_rules_imports_logging.py +136 -1
  34. package/hooks/blocking/code_rules_js_conventions.py +246 -0
  35. package/hooks/blocking/code_rules_naming_collection.py +5 -0
  36. package/hooks/blocking/code_rules_test_assertions.py +3 -0
  37. package/hooks/blocking/code_rules_unused_imports.py +7 -66
  38. package/hooks/blocking/duplicate_rmtree_helper_blocker.py +7 -0
  39. package/hooks/blocking/test_code_rules_command_dispatch.py +95 -0
  40. package/hooks/blocking/test_code_rules_enforcer_annotations.py +20 -2
  41. package/hooks/blocking/test_code_rules_enforcer_banned_identifier.py +10 -2
  42. package/hooks/blocking/test_code_rules_enforcer_banned_import_alias.py +8 -4
  43. package/hooks/blocking/test_code_rules_enforcer_dispatch_wiring.py +9 -3
  44. package/hooks/blocking/test_code_rules_enforcer_docstring_type_checking_gate.py +164 -0
  45. package/hooks/blocking/test_code_rules_enforcer_js_returns_object.py +72 -0
  46. package/hooks/blocking/test_code_rules_enforcer_unused_imports.py +112 -18
  47. package/hooks/blocking/test_code_rules_js_conventions.py +167 -0
  48. package/hooks/blocking/test_code_rules_js_returns_object_schemaless.py +167 -0
  49. package/hooks/hooks_constants/CLAUDE.md +2 -0
  50. package/hooks/hooks_constants/blocking_check_limits.py +10 -0
  51. package/hooks/hooks_constants/code_rules_enforcer_constants.py +14 -0
  52. package/hooks/hooks_constants/command_dispatch_constants.py +28 -0
  53. package/hooks/hooks_constants/js_conventions_constants.py +54 -0
  54. package/hooks/hooks_constants/test_code_rules_enforcer_constants.py +93 -0
  55. package/hooks/hooks_constants/unused_module_import_constants.py +0 -1
  56. package/package.json +1 -1
  57. package/rules/docstring-prose-matches-implementation.md +3 -1
  58. package/skills/_shared/pr-loop/scripts/build_audit_prompt.py +43 -1
  59. package/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/CLAUDE.md +2 -2
  60. package/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/path_resolver_constants.py +1 -4
  61. package/skills/_shared/pr-loop/scripts/test_build_audit_prompt.py +100 -4
  62. package/skills/autoconverge/SKILL.md +28 -7
  63. package/skills/autoconverge/reference/convergence.md +3 -3
  64. package/skills/autoconverge/reference/stop-conditions.md +1 -1
  65. package/skills/autoconverge/workflow/converge.clean-audit.test.mjs +4 -4
  66. package/skills/autoconverge/workflow/converge.contract.test.mjs +58 -122
  67. package/skills/autoconverge/workflow/converge.copilot-gate.test.mjs +289 -5
  68. package/skills/autoconverge/workflow/converge.fix-recovery.test.mjs +50 -46
  69. package/skills/autoconverge/workflow/converge.merge-conflict.test.mjs +6 -6
  70. package/skills/autoconverge/workflow/converge.mjs +235 -247
  71. package/skills/autoconverge/workflow/converge.run-input.test.mjs +11 -0
  72. package/skills/autoconverge/workflow/converge_multi.mjs +23 -7
  73. package/skills/autoconverge/workflow/converge_multi.run-input.test.mjs +28 -2
  74. package/skills/pr-converge/SKILL.md +28 -2
  75. package/skills/pr-converge/reference/convergence-gates.md +13 -1
  76. package/skills/pr-converge/reference/state-schema.md +11 -0
@@ -99,8 +99,8 @@ test('FIX_RECOVERY_MAX_ATTEMPTS is declared and bounds the recovery loop at 2',
99
99
  assert.match(constantLine('FIX_RECOVERY_MAX_ATTEMPTS'), /=\s*2\s*$/);
100
100
  });
101
101
 
102
- test('the commit path in resumeCodeEditorAgent separates an edit-requiring block from a transient failure', () => {
103
- const commitBody = functionSource('resumeCodeEditorAgent');
102
+ test('the commit path in runCodeEditorTask separates an edit-requiring block from a transient failure', () => {
103
+ const commitBody = functionSource('runCodeEditorTask');
104
104
  assert.match(commitBody, /blockedNeedingEdit/, 'expected the edit-block flag to be set in the prompt');
105
105
  assert.match(commitBody, /blockerDetail/, 'expected the verbatim blocker detail to be requested');
106
106
  assert.match(
@@ -115,8 +115,8 @@ test('the commit path in resumeCodeEditorAgent separates an edit-requiring block
115
115
  );
116
116
  });
117
117
 
118
- test('the commit-recover task in resumeCodeEditorAgent is a clean-coder edit step bound to the blocker detail and leaves changes uncommitted', () => {
119
- const recoverBody = functionSource('resumeCodeEditorAgent');
118
+ test('the commit-recover task in runCodeEditorTask is a clean-coder edit step bound to the blocker detail and leaves changes uncommitted', () => {
119
+ const recoverBody = functionSource('runCodeEditorTask');
120
120
  assert.match(recoverBody, /agentType:\s*'clean-coder'/, 'expected the fixer to use clean-coder');
121
121
  assert.match(recoverBody, /schema:\s*EDIT_SCHEMA/, 'expected the fixer to reuse EDIT_SCHEMA');
122
122
  assert.match(recoverBody, /task === 'commit-recover'/, 'expected the commit-recover task branch');
@@ -161,88 +161,92 @@ test('commitWithRecovery bounds the loop, re-verifies, and retries the commit on
161
161
  );
162
162
  });
163
163
 
164
- test('applyFixes routes through spawnFixerAgent and fixerWithRecovery', () => {
164
+ test('applyFixes routes through the fix-edit task and fixerWithRecovery', () => {
165
165
  const applyFixesBody = functionSource('applyFixes');
166
- assert.match(applyFixesBody, /spawnFixerAgent\(/, 'expected applyFixes to call spawnFixerAgent');
166
+ assert.match(applyFixesBody, /runCodeEditorTask\('fix-edit'/, "expected applyFixes to call runCodeEditorTask('fix-edit')");
167
167
  assert.match(applyFixesBody, /fixerWithRecovery\(/, 'expected applyFixes to call fixerWithRecovery');
168
168
  });
169
169
 
170
- test('applyFixes spawns a separate verifier and passes both ids into fixerWithRecovery', () => {
170
+ test('applyFixes delegates to fixerWithRecovery, which grades fixes with a separate verifier from the fixer', () => {
171
171
  const applyFixesBody = functionSource('applyFixes');
172
172
  assert.match(
173
173
  applyFixesBody,
174
- /spawnVerifierAgent\(/,
175
- 'expected applyFixes to spawn a separate verifier agent so the fix-path verdict is independent of the fixer',
174
+ /fixerWithRecovery\(head, findings, sourceLabel\)/,
175
+ 'expected applyFixes to delegate the verify and commit flow to fixerWithRecovery',
176
176
  );
177
- const fixerSpawnIndex = applyFixesBody.search(/spawnFixerAgent\(/);
178
- const verifierSpawnIndex = applyFixesBody.search(/spawnVerifierAgent\(/);
179
- assert.notEqual(fixerSpawnIndex, -1, 'expected applyFixes to spawn the fixer');
180
- assert.notEqual(verifierSpawnIndex, -1, 'expected applyFixes to spawn the verifier');
177
+ const recoveryBody = functionSource('fixerWithRecovery');
181
178
  assert.match(
182
- applyFixesBody,
183
- /fixerWithRecovery\(\s*fixerAgentId,\s*verifierId,/,
184
- 'expected applyFixes to pass both the fixer and verifier ids into fixerWithRecovery',
179
+ recoveryBody,
180
+ /runVerifierTask\('fix-verify'/,
181
+ 'expected fixerWithRecovery to grade the fixes with the code-verifier task so the verdict is independent of the fixer',
182
+ );
183
+ assert.match(
184
+ recoveryBody,
185
+ /runFixerTask\('commit'/,
186
+ 'expected fixerWithRecovery to commit through the clean-coder fixer task',
185
187
  );
186
188
  });
187
189
 
188
- test('fixerWithRecovery runs verify on the verifier id and edits/commits on the fixer id', () => {
190
+ test('fixerWithRecovery runs verify via runVerifierTask and edits/commits via runFixerTask', () => {
189
191
  const recoveryBody = functionSource('fixerWithRecovery');
190
192
  assert.match(
191
193
  recoveryBody,
192
- /resumeVerifierAgent\(\s*verifierId,/,
193
- 'expected fixerWithRecovery to resume the separate verifier for the verify step',
194
+ /runVerifierTask\('fix-verify'/,
195
+ 'expected fixerWithRecovery to run the verify step through the separate verifier task',
194
196
  );
195
197
  assert.match(
196
198
  recoveryBody,
197
- /resumeFixerAgent\(\s*fixerAgentId,\s*'commit'/,
198
- 'expected fixerWithRecovery to resume the fixer for the commit step',
199
+ /runFixerTask\('commit'/,
200
+ 'expected fixerWithRecovery to run the commit step through the fixer task',
199
201
  );
200
202
  assert.doesNotMatch(
201
203
  recoveryBody,
202
- /resumeFixerAgent\(\s*fixerAgentId,\s*'(?:verify-commit|fix-verify)'/,
203
- 'expected the verify step never to resume the fixer session — the verifier must grade a different session than the one that edits',
204
+ /runFixerTask\('(?:verify-commit|fix-verify)'/,
205
+ 'expected the verify step never to route through the fixer task — the verifier grades a different agent than the one that edits',
204
206
  );
205
207
  });
206
208
 
207
- test('the fix-path verify resumes a different agent id than the fix-path edits, mirroring the repair path', () => {
209
+ test('the fix-path verify routes through a different helper and agentType than the fix-path edits, mirroring the repair path', () => {
208
210
  const recoveryBody = functionSource('fixerWithRecovery');
209
- const verifyResumeMatch = /resumeVerifierAgent\(\s*(\w+),/.exec(recoveryBody);
210
- const editResumeMatch = /resumeFixerAgent\(\s*(\w+),/.exec(recoveryBody);
211
- assert.ok(verifyResumeMatch, 'expected a verify resume call naming its agent id');
212
- assert.ok(editResumeMatch, 'expected an edit/commit resume call naming its agent id');
211
+ const verifyHelperMatch = /(\w+)\('fix-verify'/.exec(recoveryBody);
212
+ const editHelperMatch = /(\w+)\('commit'/.exec(recoveryBody);
213
+ assert.ok(verifyHelperMatch, 'expected a verify call naming its task helper');
214
+ assert.ok(editHelperMatch, 'expected an edit/commit call naming its task helper');
215
+ assert.equal(verifyHelperMatch[1], 'runVerifierTask', 'expected verify to route through runVerifierTask (code-verifier)');
216
+ assert.equal(editHelperMatch[1], 'runFixerTask', 'expected commit to route through runFixerTask (clean-coder)');
213
217
  assert.notEqual(
214
- verifyResumeMatch[1],
215
- editResumeMatch[1],
216
- 'expected the verify step to resume a different agent id than the edit/commit step',
218
+ verifyHelperMatch[1],
219
+ editHelperMatch[1],
220
+ 'expected the verify step to route through a different helper than the edit/commit step',
217
221
  );
218
222
  });
219
223
 
220
- test('the verifier carries a fix-verify task so the fix path verdict comes from the verifier group', () => {
221
- const verifierBody = functionSource('resumeVerifierAgent');
222
- assert.match(verifierBody, /task === 'fix-verify'/, 'expected resumeVerifierAgent to handle the fix-verify task');
224
+ test('the verifier carries a fix-verify task so the fix path verdict comes from the verifier', () => {
225
+ const verifierBody = functionSource('runVerifierTask');
226
+ assert.match(verifierBody, /task === 'fix-verify'/, 'expected runVerifierTask to handle the fix-verify task');
223
227
  assert.match(verifierBody, /buildVerdictFenceSteps\(/, 'expected the fix-verify task to emit a verdict fence');
224
228
  assert.match(verifierBody, /agentType:\s*'code-verifier'/, 'expected the fix-verify task to run as code-verifier');
225
229
  });
226
230
 
227
- test('resumeFixerAgent no longer verifies its own edits — no code-verifier verify-commit task remains', () => {
228
- const fixerBody = functionSource('resumeFixerAgent');
231
+ test('runFixerTask no longer verifies its own edits — no code-verifier verify-commit task remains', () => {
232
+ const fixerBody = functionSource('runFixerTask');
229
233
  assert.doesNotMatch(
230
234
  fixerBody,
231
235
  /task === 'verify-commit'/,
232
- 'expected the fixer to no longer carry the verify-commit task that graded its own session',
236
+ 'expected the fixer to no longer carry the verify-commit task that graded its own edits',
233
237
  );
234
238
  assert.doesNotMatch(
235
239
  fixerBody,
236
240
  /agentType:\s*'code-verifier'/,
237
- 'expected the fixer session to be clean-coder only — a separate verifier grades the working tree',
241
+ 'expected the fixer to be clean-coder only — a separate verifier grades the working tree',
238
242
  );
239
243
  });
240
244
 
241
245
  test('repairConvergence routes its commit through commitWithRecovery wired to the repair-path steps', () => {
242
246
  const repairBody = functionSource('repairConvergence');
243
247
  assert.match(repairBody, /commitWithRecovery\(/, 'expected repairConvergence to call commitWithRecovery');
244
- assert.match(repairBody, /resumeCodeEditorAgent\(/, 'expected repairConvergence to use resumeCodeEditorAgent');
245
- assert.match(repairBody, /resumeVerifierAgent\(/, 'expected repairConvergence to use resumeVerifierAgent');
248
+ assert.match(repairBody, /runCodeEditorTask\(/, 'expected repairConvergence to use runCodeEditorTask');
249
+ assert.match(repairBody, /runVerifierTask\(/, 'expected repairConvergence to use runVerifierTask');
246
250
  });
247
251
 
248
252
  test('the round-loop fix-stalled blockers survive the recovery wiring', () => {
@@ -334,8 +338,8 @@ test('extractVerifyObjection falls back when no finding yields usable text', ()
334
338
  assert.equal(extractVerifyObjection(transcript), VERIFY_OBJECTION_FALLBACK);
335
339
  });
336
340
 
337
- test('the verify-recover task in resumeCodeEditorAgent is a clean-coder edit step bound to the verifier objection and leaves changes uncommitted', () => {
338
- const recoverBody = functionSource('resumeCodeEditorAgent');
341
+ test('the verify-recover task in runCodeEditorTask is a clean-coder edit step bound to the verifier objection and leaves changes uncommitted', () => {
342
+ const recoverBody = functionSource('runCodeEditorTask');
339
343
  assert.match(recoverBody, /agentType:\s*'clean-coder'/, 'expected the fixer to use clean-coder');
340
344
  assert.match(recoverBody, /schema:\s*EDIT_SCHEMA/, 'expected the fixer to reuse EDIT_SCHEMA');
341
345
  assert.match(recoverBody, /VERIFY-RECOVERY fixer/, 'expected the verify-recovery prompt body');
@@ -372,12 +376,12 @@ test('verifyWithRecovery bounds the loop, re-fixes on a failed verdict, and re-v
372
376
  test('applyFixes routes through fixerWithRecovery which handles verify and commit', () => {
373
377
  const applyFixesBody = functionSource('applyFixes');
374
378
  assert.match(applyFixesBody, /fixerWithRecovery\(/, 'expected applyFixes to call fixerWithRecovery');
375
- assert.match(applyFixesBody, /spawnFixerAgent\(/, 'expected applyFixes to call spawnFixerAgent');
379
+ assert.match(applyFixesBody, /runCodeEditorTask\('fix-edit'/, "expected applyFixes to call runCodeEditorTask('fix-edit')");
376
380
  });
377
381
 
378
- test('repairConvergence routes its verify through verifyWithRecovery wired to resume helpers', () => {
382
+ test('repairConvergence routes its verify through verifyWithRecovery wired to the task helpers', () => {
379
383
  const repairBody = functionSource('repairConvergence');
380
384
  assert.match(repairBody, /verifyWithRecovery\(/, 'expected repairConvergence to call verifyWithRecovery');
381
- assert.match(repairBody, /resumeVerifierAgent\(/, 'expected repairConvergence to use resumeVerifierAgent for verify');
382
- assert.match(repairBody, /resumeCodeEditorAgent\(/, 'expected repairConvergence to use resumeCodeEditorAgent for recover');
385
+ assert.match(repairBody, /runVerifierTask\(/, 'expected repairConvergence to use runVerifierTask for verify');
386
+ assert.match(repairBody, /runCodeEditorTask\(/, 'expected repairConvergence to use runCodeEditorTask for recover');
383
387
  });
@@ -32,7 +32,7 @@ test('isMergeConflicting reports a conflict only when the check returned conflic
32
32
  });
33
33
 
34
34
  test('the git agent handles merge-conflict checks with shell-agnostic polling', () => {
35
- const gitBody = functionBody('resumeGitAgent');
35
+ const gitBody = functionBody('runGitTask');
36
36
  assert.match(gitBody, /mergeable/, 'expected the git agent to read the PR mergeable field');
37
37
  assert.match(
38
38
  gitBody,
@@ -43,8 +43,8 @@ test('the git agent handles merge-conflict checks with shell-agnostic polling',
43
43
  assert.match(gitBody, /sleep 5|Start-Sleep/, 'expected a shell-agnostic poll delay');
44
44
  });
45
45
 
46
- test('resumeCodeEditorAgent conflict-edit path rebases onto origin/main and makes no push', () => {
47
- const body = functionBody('resumeCodeEditorAgent');
46
+ test('runCodeEditorTask conflict-edit path rebases onto origin/main and makes no push', () => {
47
+ const body = functionBody('runCodeEditorTask');
48
48
  assert.match(body, /git rebase origin\/main/, 'expected the edit path to rebase onto origin/main');
49
49
  assert.match(
50
50
  body,
@@ -55,9 +55,9 @@ test('resumeCodeEditorAgent conflict-edit path rebases onto origin/main and make
55
55
 
56
56
  test('resolveMergeConflicts runs check -> edit -> verify -> commit and gates the push on the verdict', () => {
57
57
  const body = functionBody('resolveMergeConflicts');
58
- const checkIndex = body.indexOf("resumeGitAgent(gitAgentId, 'check-merge-conflicts'");
59
- const editIndex = body.indexOf('spawnCodeEditorAgent(');
60
- const verifyIndex = body.indexOf('spawnVerifierAgent(');
58
+ const checkIndex = body.indexOf("runGitTask('check-merge-conflicts'");
59
+ const editIndex = body.indexOf("runCodeEditorTask('conflict-edit'");
60
+ const verifyIndex = body.indexOf('runVerifierTask(');
61
61
  const commitIndex = body.indexOf('commitWithRecovery(');
62
62
  assert.notEqual(checkIndex, -1, 'expected the conflict check to run');
63
63
  assert.notEqual(editIndex, -1, 'expected the edit step to run');