claude-dev-env 4.2.0 → 7.0.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 (350) hide show
  1. package/.agents/agents/pr-description-writer.md +2 -2
  2. package/.agents/agents/test_agent_frontmatter.py +2 -2
  3. package/.agents/agents/test_pr_description_writer_style.py +1 -3
  4. package/.agents/skills/e-code-review/SKILL.md +12 -12
  5. package/.agents/skills/e-code-review/preflight-proposal.contract.test.mjs +20 -0
  6. package/.agents/skills/e-code-review/reference/fix.md +15 -17
  7. package/.agents/skills/e-code-review/reference/loop.md +35 -39
  8. package/.agents/skills/e-code-review/reference/mode-contract.test.mjs +2 -1
  9. package/.agents/skills/e-code-review/reference/preflight-proposal.md +44 -9
  10. package/.agents/skills/e-code-review/reference/runner-selection.md +13 -14
  11. package/.agents/skills/issue-tracker/SKILL.md +7 -0
  12. package/.agents/skills/pull-request/SKILL.md +216 -0
  13. package/.agents/skills/pull-request/reference/publication-tasks.md +18 -0
  14. package/.agents/skills/pull-request/scripts/github_pr_command_constants/__init__.py +1 -0
  15. package/.agents/skills/pull-request/scripts/github_pr_command_constants/config/__init__.py +1 -0
  16. package/.agents/skills/pull-request/scripts/github_pr_command_constants/config/constants.py +69 -0
  17. package/.agents/skills/pull-request/scripts/pull_request.py +265 -0
  18. package/.agents/skills/pull-request/scripts/recover_legacy_author.py +251 -0
  19. package/.agents/skills/pull-request/scripts/test_github_pr_command_constants.py +58 -0
  20. package/.agents/skills/pull-request/scripts/test_pull_request.py +396 -0
  21. package/.agents/skills/pull-request/scripts/test_recover_legacy_author.py +221 -0
  22. package/.agents/skills/skill-builder/SKILL.md +3 -196
  23. package/.agents/skills/test-runner/SKILL.md +69 -0
  24. package/.agents/skills/test-runner/scripts/preflight_checks.py +365 -0
  25. package/.agents/skills/test-runner/scripts/run_tests.py +316 -0
  26. package/.agents/skills/test-runner/scripts/test_preflight_checks.py +185 -0
  27. package/.agents/skills/test-runner/scripts/test_run_tests.py +281 -0
  28. package/.agents/skills/test-runner/scripts/test_runner_constants/__init__.py +1 -0
  29. package/.agents/skills/test-runner/scripts/test_runner_constants/config/__init__.py +1 -0
  30. package/.agents/skills/test-runner/scripts/test_runner_constants/config/constants.py +96 -0
  31. package/.agents/skills-archived/pr-loop-cloud-transport/reference/identity-and-hooks.md +1 -1
  32. package/_shared/pr-loop/scripts/pr_loop_shared_constants/terminology_sweep_constants.py +6 -0
  33. package/_shared/pr-loop/scripts/terminology_sweep.py +64 -19
  34. package/_shared/pr-loop/scripts/tests/test_terminology_sweep.py +59 -0
  35. package/bin/ever-shipped-skills.mjs +2 -0
  36. package/bin/ever-shipped-skills.test.mjs +8 -0
  37. package/bin/install.agents-home.test.mjs +15 -13
  38. package/bin/install.mjs +37 -1
  39. package/bin/install.policy-lint.test.mjs +78 -0
  40. package/bin/install.prune.test.mjs +149 -20
  41. package/bin/install.pstack-plugin.test.mjs +114 -0
  42. package/bin/install.test.mjs +61 -7
  43. package/bin/refresh-pstack-plugin-skills.test.mjs +211 -0
  44. package/hooks/advisory/pr_done_reminder.py +342 -0
  45. package/hooks/advisory/test_pr_done_reminder.py +249 -0
  46. package/hooks/blocking/bash_post_call_dispatcher.py +53 -6
  47. package/hooks/blocking/code_rules_paired_test.py +22 -15
  48. package/hooks/blocking/pii_prevention_blocker.py +32 -51
  49. package/hooks/blocking/test_bash_post_call_dispatcher.py +55 -17
  50. package/hooks/blocking/test_bash_pre_tool_use_dispatcher.py +1 -4
  51. package/hooks/blocking/test_code_rules_command_dispatch.py +2 -2
  52. package/hooks/blocking/test_code_rules_enforcer_paired_test.py +36 -29
  53. package/hooks/blocking/test_code_rules_js_resume_task_enumeration.py +4 -4
  54. package/hooks/blocking/test_code_rules_js_returns_object_schemaless.py +5 -5
  55. package/hooks/blocking/test_pii_prevention_blocker.py +37 -89
  56. package/hooks/blocking/test_pre_tool_use_dispatcher.py +68 -133
  57. package/hooks/blocking/test_pre_tool_use_dispatcher_native.py +20 -51
  58. package/hooks/blocking/test_precommit_code_rules_gate_native_owner.py +18 -18
  59. package/hooks/gh_post_body_texts.py +195 -0
  60. package/hooks/git-hooks/git_hooks_constants/staged_policy_lint.py +12 -0
  61. package/hooks/git-hooks/pre_commit.py +52 -11
  62. package/hooks/git-hooks/test_installed_policy_lint.py +159 -0
  63. package/hooks/git-hooks/test_native_policy_commit.py +87 -0
  64. package/hooks/git-hooks/test_pre_commit.py +246 -0
  65. package/hooks/hooks.json +1 -16
  66. package/hooks/hooks_constants/bash_post_call_dispatcher_constants.py +14 -2
  67. package/hooks/hooks_constants/bash_pre_tool_use_dispatcher_constants.py +0 -8
  68. package/hooks/hooks_constants/gh_post_body_texts_constants.py +12 -0
  69. package/hooks/hooks_constants/pr_done_reminder_constants.py +98 -0
  70. package/hooks/hooks_constants/pre_tool_use_dispatcher_constants.py +10 -43
  71. package/hooks/hooks_constants/test_bash_post_call_dispatcher_constants.py +17 -7
  72. package/hooks/hooks_constants/test_bash_pre_tool_use_dispatcher_constants.py +0 -7
  73. package/hooks/hooks_constants/test_failure_recorder_constants.py +3 -3
  74. package/hooks/hooks_constants/test_gh_post_body_texts_constants.py +19 -0
  75. package/hooks/hooks_constants/test_pr_done_reminder_constants.py +40 -0
  76. package/hooks/hooks_constants/test_pre_tool_use_dispatcher_constants.py +20 -32
  77. package/hooks/observability/test_failure_recorder.py +1 -1
  78. package/hooks/pyproject.toml +1 -1
  79. package/hooks/test_gh_post_body_texts.py +79 -0
  80. package/package.json +2 -2
  81. package/rules/durable-post-artifacts.md +32 -20
  82. package/rules/gh-cli-conventions.md +23 -13
  83. package/rules/git-workflow.md +21 -8
  84. package/scripts/check.ps1 +0 -1
  85. package/{.agents/skills/run-claude-dev-env/driver.mjs → scripts/ci/installer-lifecycle.mjs} +3 -28
  86. package/scripts/ci/installer-lifecycle.test.mjs +26 -0
  87. package/scripts/ci/windows-installer-lifecycle.ps1 +1 -11
  88. package/scripts/dev_env_scripts_constants/shared_tree_constants.py +4 -5
  89. package/scripts/durable_post_lint.py +206 -0
  90. package/scripts/durable_post_lint_config/config/constants.py +96 -0
  91. package/scripts/durable_post_lint_config/config/test_constants.py +25 -0
  92. package/scripts/policy_lint/adapter_configuration.py +53 -12
  93. package/scripts/policy_lint/adapter_detectors.py +13 -6
  94. package/scripts/policy_lint/adapters.py +7 -4
  95. package/scripts/policy_lint/config/constants.py +5 -0
  96. package/scripts/policy_lint/engine.py +48 -4
  97. package/scripts/policy_lint/model.py +1 -0
  98. package/scripts/policy_lint/registry.py +1 -1
  99. package/scripts/policy_lint/selection.py +2 -1
  100. package/scripts/policy_lint/selection_git.py +2 -0
  101. package/scripts/refresh_pstack_plugin_skills.mjs +200 -0
  102. package/scripts/repository_checks/config/constants.py +0 -5
  103. package/scripts/shared_tree_paths.py +32 -3
  104. package/scripts/test_durable_post_lint.py +332 -0
  105. package/scripts/test_shared_tree_paths.py +33 -0
  106. package/scripts/tests/test_adapter_configuration.py +54 -0
  107. package/scripts/tests/test_policy_lint_rules_archive.py +120 -0
  108. package/scripts/tests/test_policy_lint_rules_engine.py +25 -4
  109. package/scripts/tests/test_policy_lint_rules_installed_loader.py +29 -0
  110. package/scripts/tests/test_policy_lint_rules_registry.py +227 -13
  111. package/scripts/tests/test_policy_lint_selection.py +25 -2
  112. package/scripts/tests/test_policy_lint_selection_native_index.py +30 -0
  113. package/scripts/tests/test_rules.py +3 -7
  114. package/.agents/skills/_shared/pr-loop/.claude/CLAUDE.md +0 -1
  115. package/.agents/skills/_shared/pr-loop/AGENTS.md +0 -1
  116. package/.agents/skills/_shared/pr-loop/audit-contract.md +0 -5
  117. package/.agents/skills/_shared/pr-loop/audit-reply-template.md +0 -5
  118. package/.agents/skills/_shared/pr-loop/code-rules-gate.md +0 -5
  119. package/.agents/skills/_shared/pr-loop/fix-protocol.md +0 -5
  120. package/.agents/skills/_shared/pr-loop/gh-payloads.md +0 -5
  121. package/.agents/skills/_shared/pr-loop/portable-driver.md +0 -149
  122. package/.agents/skills/_shared/pr-loop/post-audit-thread-contract.md +0 -5
  123. package/.agents/skills/_shared/pr-loop/precatch-rubric.md +0 -5
  124. package/.agents/skills/_shared/pr-loop/preflight-proposal.contract.test.mjs +0 -119
  125. package/.agents/skills/_shared/pr-loop/preflight-proposal.md +0 -5
  126. package/.agents/skills/_shared/pr-loop/prompts/.claude/CLAUDE.md +0 -1
  127. package/.agents/skills/_shared/pr-loop/prompts/AGENTS.md +0 -1
  128. package/.agents/skills/_shared/pr-loop/prompts/pr-consistency-audit.xml +0 -324
  129. package/.agents/skills/_shared/pr-loop/scripts/.claude/CLAUDE.md +0 -1
  130. package/.agents/skills/_shared/pr-loop/scripts/AGENTS.md +0 -1
  131. package/.agents/skills/_shared/pr-loop/scripts/RUNTIME_SCRIPTS.md +0 -29
  132. package/.agents/skills/_shared/pr-loop/scripts/_cli_utils.py +0 -22
  133. package/.agents/skills/_shared/pr-loop/scripts/_path_resolver.py +0 -186
  134. package/.agents/skills/_shared/pr-loop/scripts/_xml_utils.py +0 -20
  135. package/.agents/skills/_shared/pr-loop/scripts/audit_category_schema.py +0 -355
  136. package/.agents/skills/_shared/pr-loop/scripts/build_audit_prompt.py +0 -289
  137. package/.agents/skills/_shared/pr-loop/scripts/build_converge_task_list.py +0 -310
  138. package/.agents/skills/_shared/pr-loop/scripts/build_fix_prompt.py +0 -292
  139. package/.agents/skills/_shared/pr-loop/scripts/init_loop_state.py +0 -134
  140. package/.agents/skills/_shared/pr-loop/scripts/portable_converge_driver.py +0 -1646
  141. package/.agents/skills/_shared/pr-loop/scripts/preflight_worktree.py +0 -392
  142. package/.agents/skills/_shared/pr-loop/scripts/select_converge_pacer.py +0 -215
  143. package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/.claude/CLAUDE.md +0 -1
  144. package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/AGENTS.md +0 -1
  145. package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/__init__.py +0 -0
  146. package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/audit_category_schema_constants.py +0 -37
  147. package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/converge_task_list_constants.py +0 -56
  148. package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/handoff_constants.py +0 -45
  149. package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/pacer_constants.py +0 -47
  150. package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/path_resolver_constants.py +0 -157
  151. package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/portable_driver_constants.py +0 -177
  152. package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/preflight_constants.py +0 -70
  153. package/.agents/skills/_shared/pr-loop/scripts/teardown_worktrees.py +0 -172
  154. package/.agents/skills/_shared/pr-loop/scripts/test__path_resolver.py +0 -106
  155. package/.agents/skills/_shared/pr-loop/scripts/test_audit_category_schema.py +0 -94
  156. package/.agents/skills/_shared/pr-loop/scripts/test_build_audit_prompt.py +0 -499
  157. package/.agents/skills/_shared/pr-loop/scripts/test_build_converge_task_list.py +0 -140
  158. package/.agents/skills/_shared/pr-loop/scripts/test_build_fix_prompt.py +0 -262
  159. package/.agents/skills/_shared/pr-loop/scripts/test_init_loop_state.py +0 -71
  160. package/.agents/skills/_shared/pr-loop/scripts/test_portable_converge_driver.py +0 -1119
  161. package/.agents/skills/_shared/pr-loop/scripts/test_preflight_worktree.py +0 -287
  162. package/.agents/skills/_shared/pr-loop/scripts/test_select_converge_pacer.py +0 -207
  163. package/.agents/skills/_shared/pr-loop/scripts/test_teardown_worktrees.py +0 -59
  164. package/.agents/skills/_shared/pr-loop/scripts/test_write_handoff.py +0 -201
  165. package/.agents/skills/_shared/pr-loop/scripts/write_audit_outcomes.py +0 -182
  166. package/.agents/skills/_shared/pr-loop/scripts/write_fix_outcomes.py +0 -206
  167. package/.agents/skills/_shared/pr-loop/scripts/write_handoff.py +0 -309
  168. package/.agents/skills/_shared/pr-loop/state-schema.md +0 -5
  169. package/.agents/skills/_shared/pr-loop/worker-spawn.md +0 -5
  170. package/.agents/skills/autoconverge/.claude/CLAUDE.md +0 -1
  171. package/.agents/skills/autoconverge/AGENTS.md +0 -1
  172. package/.agents/skills/autoconverge/SKILL.md +0 -431
  173. package/.agents/skills/autoconverge/reference/.claude/CLAUDE.md +0 -1
  174. package/.agents/skills/autoconverge/reference/AGENTS.md +0 -1
  175. package/.agents/skills/autoconverge/reference/closing-report.md +0 -93
  176. package/.agents/skills/autoconverge/reference/convergence-gates.md +0 -31
  177. package/.agents/skills/autoconverge/reference/convergence.md +0 -219
  178. package/.agents/skills/autoconverge/reference/copilot-findings.md +0 -51
  179. package/.agents/skills/autoconverge/reference/gotchas.md +0 -66
  180. package/.agents/skills/autoconverge/reference/headless-safety.md +0 -44
  181. package/.agents/skills/autoconverge/reference/multi-pr.md +0 -128
  182. package/.agents/skills/autoconverge/reference/self-closing-loop.md +0 -84
  183. package/.agents/skills/autoconverge/reference/stop-conditions.md +0 -127
  184. package/.agents/skills/autoconverge/test_portable_pacer_gate.py +0 -54
  185. package/.agents/skills/autoconverge/workflow/.claude/CLAUDE.md +0 -1
  186. package/.agents/skills/autoconverge/workflow/AGENTS.md +0 -1
  187. package/.agents/skills/autoconverge/workflow/aggregate_runs.py +0 -371
  188. package/.agents/skills/autoconverge/workflow/autoconverge_report_constants/.claude/CLAUDE.md +0 -1
  189. package/.agents/skills/autoconverge/workflow/autoconverge_report_constants/AGENTS.md +0 -1
  190. package/.agents/skills/autoconverge/workflow/autoconverge_report_constants/__init__.py +0 -0
  191. package/.agents/skills/autoconverge/workflow/autoconverge_report_constants/render_report_constants.py +0 -250
  192. package/.agents/skills/autoconverge/workflow/converge.clean-audit.test.mjs +0 -665
  193. package/.agents/skills/autoconverge/workflow/converge.codex-gate.test.mjs +0 -472
  194. package/.agents/skills/autoconverge/workflow/converge.contract.test.mjs +0 -64
  195. package/.agents/skills/autoconverge/workflow/converge.copilot-gate.test.mjs +0 -1009
  196. package/.agents/skills/autoconverge/workflow/converge.fix-progress.test.mjs +0 -107
  197. package/.agents/skills/autoconverge/workflow/converge.fix-recovery.test.mjs +0 -33
  198. package/.agents/skills/autoconverge/workflow/converge.merge-conflict.test.mjs +0 -15
  199. package/.agents/skills/autoconverge/workflow/converge.mjs +0 -3132
  200. package/.agents/skills/autoconverge/workflow/converge.p2-advance.test.mjs +0 -202
  201. package/.agents/skills/autoconverge/workflow/converge.path-aware.test.mjs +0 -47
  202. package/.agents/skills/autoconverge/workflow/converge.precatch.test.mjs +0 -152
  203. package/.agents/skills/autoconverge/workflow/converge.run-input.test.mjs +0 -116
  204. package/.agents/skills/autoconverge/workflow/converge_multi.mjs +0 -169
  205. package/.agents/skills/autoconverge/workflow/converge_multi.run-input.test.mjs +0 -173
  206. package/.agents/skills/autoconverge/workflow/convergence_summary.py +0 -110
  207. package/.agents/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a11d903476b803493.jsonl +0 -2
  208. package/.agents/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a26213978adeef6fb.jsonl +0 -2
  209. package/.agents/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a3def0d15ed9d9110.jsonl +0 -2
  210. package/.agents/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a41f41b1b708ee3b7.jsonl +0 -2
  211. package/.agents/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a758b880abecc3ff7.jsonl +0 -2
  212. package/.agents/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a8897b89656b1bd16.jsonl +0 -2
  213. package/.agents/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-ab1c2d3e4f5a6b7c8.jsonl +0 -2
  214. package/.agents/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-abd463d744a1437bc.jsonl +0 -2
  215. package/.agents/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-ad19d027ae8ee1816.jsonl +0 -2
  216. package/.agents/skills/autoconverge/workflow/fixtures/wf_run/workflows/wf_881252e6-700.json +0 -266
  217. package/.agents/skills/autoconverge/workflow/render_report.py +0 -1024
  218. package/.agents/skills/autoconverge/workflow/test_aggregate_runs.py +0 -134
  219. package/.agents/skills/autoconverge/workflow/test_convergence_summary.py +0 -149
  220. package/.agents/skills/autoconverge/workflow/test_render_report.py +0 -812
  221. package/.agents/skills/hitl/SKILL.md +0 -45
  222. package/.agents/skills/pr-cleanup/SKILL.md +0 -140
  223. package/.agents/skills/pr-cleanup/reference/process-inventory.md +0 -17
  224. package/.agents/skills/pr-cleanup/reference/task-seeds.md +0 -22
  225. package/.agents/skills/pr-name-by-capability/SKILL.md +0 -73
  226. package/.agents/skills/pr-name-by-capability/reference/fetch-commands.md +0 -29
  227. package/.agents/skills/pr-name-by-capability/reference/offense-examples.md +0 -32
  228. package/.agents/skills/pr-name-by-capability/reference/report-template.md +0 -29
  229. package/.agents/skills/pr-name-by-capability/reference/rule-checklist.md +0 -38
  230. package/.agents/skills/pr-name-by-capability/reference/task-seeds.md +0 -10
  231. package/.agents/skills/pr-plain-language-cleanup/SKILL.md +0 -93
  232. package/.agents/skills/pr-refinement/SKILL.md +0 -31
  233. package/.agents/skills/pr-shared-extraction/SKILL.md +0 -177
  234. package/.agents/skills/pr-shared-extraction/reference/examples.md +0 -46
  235. package/.agents/skills/pr-shared-extraction/reference/offense-taxonomy.md +0 -100
  236. package/.agents/skills/pr-small-cl/SKILL.md +0 -52
  237. package/.agents/skills/pr-title-description/SKILL.md +0 -96
  238. package/.agents/skills/prototype/SKILL.md +0 -85
  239. package/.agents/skills/prototype/reference/honest-limitations.md +0 -23
  240. package/.agents/skills/prototype/reference/promotion-tasks.md +0 -23
  241. package/.agents/skills/prototype/scripts/build_sandbox_settings.py +0 -249
  242. package/.agents/skills/prototype/scripts/conftest.py +0 -15
  243. package/.agents/skills/prototype/scripts/launch_sandbox.py +0 -205
  244. package/.agents/skills/prototype/scripts/probe_sandbox_safety.py +0 -311
  245. package/.agents/skills/prototype/scripts/prototype_scripts_constants/__init__.py +0 -1
  246. package/.agents/skills/prototype/scripts/prototype_scripts_constants/config/__init__.py +0 -0
  247. package/.agents/skills/prototype/scripts/prototype_scripts_constants/config/build_sandbox_settings_constants.py +0 -41
  248. package/.agents/skills/prototype/scripts/prototype_scripts_constants/config/launch_sandbox_constants.py +0 -23
  249. package/.agents/skills/prototype/scripts/prototype_scripts_constants/config/probe_sandbox_safety_constants.py +0 -45
  250. package/.agents/skills/prototype/scripts/prototype_scripts_constants/config/prototype_common_constants.py +0 -10
  251. package/.agents/skills/prototype/scripts/test_build_sandbox_settings.py +0 -275
  252. package/.agents/skills/prototype/scripts/test_launch_sandbox.py +0 -303
  253. package/.agents/skills/prototype/scripts/test_probe_sandbox_safety.py +0 -312
  254. package/.agents/skills/prototype/workflows/promotion.md +0 -25
  255. package/.agents/skills/prototype/workflows/sandbox.md +0 -35
  256. package/.agents/skills/rebase/.claude/CLAUDE.md +0 -1
  257. package/.agents/skills/rebase/AGENTS.md +0 -1
  258. package/.agents/skills/rebase/SKILL.md +0 -178
  259. package/.agents/skills/review-router/SKILL.md +0 -51
  260. package/.agents/skills/review-router/reference/route-policy.json +0 -7
  261. package/.agents/skills/review-router/reference/task-seeds.md +0 -1
  262. package/.agents/skills/review-router/scripts/conftest.py +0 -4
  263. package/.agents/skills/review-router/scripts/review_router.py +0 -50
  264. package/.agents/skills/review-router/scripts/review_router_cli.py +0 -211
  265. package/.agents/skills/review-router/scripts/review_router_constants/__init__.py +0 -1
  266. package/.agents/skills/review-router/scripts/review_router_constants/config/__init__.py +0 -0
  267. package/.agents/skills/review-router/scripts/review_router_constants/config/constants.py +0 -13
  268. package/.agents/skills/review-router/scripts/test_review_router.py +0 -23
  269. package/.agents/skills/review-router/scripts/test_review_router_cli.py +0 -47
  270. package/.agents/skills/review-tier/SKILL.md +0 -56
  271. package/.agents/skills/review-tier/reference/task-seeds.md +0 -1
  272. package/.agents/skills/review-tier/reference/tier-policy.json +0 -9
  273. package/.agents/skills/review-tier/scripts/conftest.py +0 -4
  274. package/.agents/skills/review-tier/scripts/review_tier.py +0 -359
  275. package/.agents/skills/review-tier/scripts/review_tier_constants/__init__.py +0 -1
  276. package/.agents/skills/review-tier/scripts/review_tier_constants/config/__init__.py +0 -0
  277. package/.agents/skills/review-tier/scripts/review_tier_constants/config/constants.py +0 -29
  278. package/.agents/skills/review-tier/scripts/test_generation.py +0 -159
  279. package/.agents/skills/review-tier/scripts/test_review_tier.py +0 -33
  280. package/.agents/skills/run-claude-dev-env/SKILL.md +0 -84
  281. package/.agents/skills/session-log/.claude/CLAUDE.md +0 -1
  282. package/.agents/skills/session-log/AGENTS.md +0 -1
  283. package/.agents/skills/session-log/SKILL.md +0 -170
  284. package/.agents/skills/session-log/templates/frontmatter.md +0 -40
  285. package/.agents/skills/session-tidy/.claude/CLAUDE.md +0 -1
  286. package/.agents/skills/session-tidy/AGENTS.md +0 -1
  287. package/.agents/skills/session-tidy/SKILL.md +0 -191
  288. package/.agents/skills/skill-builder/references/.claude/CLAUDE.md +0 -1
  289. package/.agents/skills/skill-builder/references/AGENTS.md +0 -1
  290. package/.agents/skills/skill-builder/references/delegation-map.md +0 -130
  291. package/.agents/skills/skill-builder/references/description-field.md +0 -111
  292. package/.agents/skills/skill-builder/references/deterministic-elements.md +0 -218
  293. package/.agents/skills/skill-builder/references/progressive-disclosure.md +0 -122
  294. package/.agents/skills/skill-builder/references/self-audit-checklist.md +0 -126
  295. package/.agents/skills/skill-builder/references/skill-modularity.md +0 -111
  296. package/.agents/skills/skill-builder/references/skill-types.md +0 -232
  297. package/.agents/skills/skill-builder/references/thariq-x-post-skills.json +0 -33
  298. package/.agents/skills/skill-builder/templates/.claude/CLAUDE.md +0 -1
  299. package/.agents/skills/skill-builder/templates/AGENTS.md +0 -1
  300. package/.agents/skills/skill-builder/templates/gap-analysis.md +0 -87
  301. package/.agents/skills/skill-builder/workflows/.claude/CLAUDE.md +0 -1
  302. package/.agents/skills/skill-builder/workflows/AGENTS.md +0 -1
  303. package/.agents/skills/skill-builder/workflows/improve-skill.md +0 -136
  304. package/.agents/skills/skill-builder/workflows/new-skill.md +0 -179
  305. package/.agents/skills/skill-builder/workflows/polish-skill.md +0 -139
  306. package/.agents/skills/source-command-sr-loop/SKILL.md +0 -82
  307. package/.agents/skills/update/.claude/CLAUDE.md +0 -1
  308. package/.agents/skills/update/AGENTS.md +0 -1
  309. package/.agents/skills/update/SKILL.md +0 -190
  310. package/_shared/pr-loop/AGENTS.md +0 -1
  311. package/_shared/pr-loop/CLAUDE.md +0 -1
  312. package/_shared/pr-loop/audit-contract.md +0 -183
  313. package/_shared/pr-loop/audit-reply-template.md +0 -151
  314. package/_shared/pr-loop/code-rules-gate.md +0 -65
  315. package/_shared/pr-loop/fix-protocol.md +0 -60
  316. package/_shared/pr-loop/gh-payloads.md +0 -75
  317. package/_shared/pr-loop/post-audit-thread-contract.md +0 -51
  318. package/_shared/pr-loop/precatch-rubric.md +0 -66
  319. package/_shared/pr-loop/preflight-proposal.md +0 -56
  320. package/_shared/pr-loop/scripts/post_audit_thread.py +0 -1242
  321. package/_shared/pr-loop/scripts/pr_loop_shared_constants/post_audit_thread_constants.py +0 -199
  322. package/_shared/pr-loop/scripts/tests/test_post_audit_thread.py +0 -1115
  323. package/_shared/pr-loop/scripts/tests/test_post_audit_thread_constants.py +0 -129
  324. package/_shared/pr-loop/state-schema.md +0 -45
  325. package/_shared/pr-loop/worker-spawn.md +0 -189
  326. package/hooks/_gh_pr_author_swap_utils.py +0 -1225
  327. package/hooks/blocking/conventional_pr_title_gate.py +0 -443
  328. package/hooks/blocking/gh_body_arg_blocker.py +0 -176
  329. package/hooks/blocking/gh_pr_author_enforcer.py +0 -487
  330. package/hooks/blocking/gh_pr_author_restore.py +0 -105
  331. package/hooks/blocking/pr_description_writer_gate.py +0 -256
  332. package/hooks/blocking/test_conventional_pr_title_gate.py +0 -640
  333. package/hooks/blocking/test_gh_body_arg_blocker.py +0 -441
  334. package/hooks/blocking/test_gh_pr_author_enforcer.py +0 -1166
  335. package/hooks/blocking/test_gh_pr_author_restore.py +0 -513
  336. package/hooks/blocking/test_gh_pr_author_swap_utils.py +0 -910
  337. package/hooks/blocking/test_pr_description_writer_gate.py +0 -234
  338. package/hooks/blocking/test_preflight_check.py +0 -343
  339. package/hooks/blocking/test_test_preflight_check.py +0 -80
  340. package/hooks/blocking/test_volatile_path_in_post_blocker.py +0 -322
  341. package/hooks/blocking/volatile_path_in_post_blocker.py +0 -461
  342. package/hooks/hooks_constants/conventional_pr_title_gate_constants.py +0 -58
  343. package/hooks/hooks_constants/gh_pr_author_swap_constants.py +0 -76
  344. package/hooks/hooks_constants/pr_description_writer_gate_constants.py +0 -73
  345. package/hooks/hooks_constants/volatile_path_in_post_blocker_constants.py +0 -55
  346. package/hooks/observability/pr_description_writer_spawn_tracker.py +0 -113
  347. package/hooks/observability/test_pr_description_writer_spawn_tracker.py +0 -150
  348. package/hooks/session/gh_pr_author_session_cleanup.py +0 -175
  349. package/hooks/session/test_gh_pr_author_session_cleanup.py +0 -576
  350. package/hooks/test__gh_pr_author_swap_utils.py +0 -333
@@ -1,202 +0,0 @@
1
- import { test } from 'node:test';
2
- import { strict as assert } from 'node:assert';
3
- import { readFileSync } from 'node:fs';
4
- import { fileURLToPath } from 'node:url';
5
- import { dirname, join } from 'node:path';
6
-
7
- const workflowDirectory = dirname(fileURLToPath(import.meta.url));
8
- const convergeSource = readFileSync(join(workflowDirectory, 'converge.mjs'), 'utf8');
9
-
10
- function functionBody(functionName) {
11
- const functionStart = convergeSource.indexOf(`function ${functionName}(`);
12
- assert.notEqual(functionStart, -1, `expected ${functionName} to exist`);
13
- const nextFunctionStart = convergeSource.indexOf('\nfunction ', functionStart + 1);
14
- const functionEnd = nextFunctionStart === -1 ? convergeSource.length : nextFunctionStart;
15
- return convergeSource.slice(functionStart, functionEnd);
16
- }
17
-
18
- const productionModule = new Function(
19
- `const SHA_COMPARISON_PREFIX_LENGTH = 7;\n` +
20
- `${functionBody('normalizeShaForComparison')}\n` +
21
- `${functionBody('isP2OnlyFindings')}\n` +
22
- `${functionBody('nextPhaseAfterP2OnlyFix')}\n` +
23
- `${functionBody('routeAfterP2OnlyFix')}\n` +
24
- 'return { isP2OnlyFindings, nextPhaseAfterP2OnlyFix, routeAfterP2OnlyFix };',
25
- )();
26
-
27
- const { isP2OnlyFindings, nextPhaseAfterP2OnlyFix, routeAfterP2OnlyFix } = productionModule;
28
-
29
- function finding(overrides) {
30
- return {
31
- file: 'a.py',
32
- line: 1,
33
- severity: 'P2',
34
- category: 'bug',
35
- title: 't',
36
- detail: 'd',
37
- replyToCommentId: null,
38
- ...overrides,
39
- };
40
- }
41
-
42
- function phaseBranch(phaseMarker) {
43
- const phaseStart = convergeSource.indexOf(phaseMarker);
44
- assert.notEqual(phaseStart, -1, `expected ${phaseMarker} to exist`);
45
- const nextPhaseStart = convergeSource.indexOf('\n if (phase === ', phaseStart + 1);
46
- const phaseEnd = nextPhaseStart === -1 ? convergeSource.length : nextPhaseStart;
47
- return convergeSource.slice(phaseStart, phaseEnd);
48
- }
49
-
50
- test('isP2OnlyFindings is false for an empty findings list', () => {
51
- assert.equal(isP2OnlyFindings([]), false);
52
- });
53
-
54
- test('isP2OnlyFindings is true when every finding is severity P2', () => {
55
- assert.equal(isP2OnlyFindings([finding(), finding({ file: 'b.py', line: 2 })]), true);
56
- });
57
-
58
- test('isP2OnlyFindings is false when a P1 is mixed in with P2 findings', () => {
59
- assert.equal(isP2OnlyFindings([finding(), finding({ severity: 'P1' })]), false);
60
- });
61
-
62
- test('isP2OnlyFindings is false when every finding is severity P1', () => {
63
- assert.equal(isP2OnlyFindings([finding({ severity: 'P1' })]), false);
64
- });
65
-
66
- test('isP2OnlyFindings is false when a finding is missing severity', () => {
67
- assert.equal(isP2OnlyFindings([{ file: 'a.py', line: 1, category: 'bug' }]), false);
68
- });
69
-
70
- test('nextPhaseAfterP2OnlyFix advances CONVERGE to BUGBOT', () => {
71
- assert.equal(nextPhaseAfterP2OnlyFix('CONVERGE'), 'BUGBOT');
72
- });
73
-
74
- test('nextPhaseAfterP2OnlyFix advances BUGBOT to COPILOT', () => {
75
- assert.equal(nextPhaseAfterP2OnlyFix('BUGBOT'), 'COPILOT');
76
- });
77
-
78
- test('nextPhaseAfterP2OnlyFix advances COPILOT to CODEX', () => {
79
- assert.equal(nextPhaseAfterP2OnlyFix('COPILOT'), 'CODEX');
80
- });
81
-
82
- test('nextPhaseAfterP2OnlyFix advances CODEX to FINALIZE', () => {
83
- assert.equal(nextPhaseAfterP2OnlyFix('CODEX'), 'FINALIZE');
84
- });
85
-
86
- test('routeAfterP2OnlyFix re-converges when the fix moved HEAD', () => {
87
- const route = routeAfterP2OnlyFix('aaa111', { newSha: 'bbb222' }, 'COPILOT');
88
- assert.equal(route.didMoveHead, true);
89
- assert.equal(route.fixedHead, 'bbb222');
90
- assert.equal(route.nextPhase, 'CONVERGE');
91
- });
92
-
93
- test('routeAfterP2OnlyFix advances when HEAD is unchanged', () => {
94
- const route = routeAfterP2OnlyFix('aaa111', { newSha: 'aaa111' }, 'COPILOT');
95
- assert.equal(route.didMoveHead, false);
96
- assert.equal(route.fixedHead, 'aaa111');
97
- assert.equal(route.nextPhase, 'COPILOT');
98
- });
99
-
100
- test('nextPhaseAfterP2OnlyFix uses an in-function lookup map', () => {
101
- const body = functionBody('nextPhaseAfterP2OnlyFix');
102
- assert.match(body, /nextPhaseByCurrent/);
103
- assert.match(body, /CONVERGE:\s*'BUGBOT'/);
104
- assert.match(body, /BUGBOT:\s*'COPILOT'/);
105
- assert.match(body, /COPILOT:\s*'CODEX'/);
106
- });
107
-
108
- test('applyP2OnlyFix runs applyFixes then detectFixProgress in order', () => {
109
- const body = functionBody('applyP2OnlyFix');
110
- const applyIndex = body.indexOf('applyFixes(head, findings, sourceLabel)');
111
- const detectIndex = body.indexOf('detectFixProgress(fixResult, head, hadThreadBearingFinding)');
112
- assert.notEqual(applyIndex, -1, 'expected applyFixes in applyP2OnlyFix');
113
- assert.notEqual(detectIndex, -1, 'expected detectFixProgress in applyP2OnlyFix');
114
- assert.ok(applyIndex < detectIndex, 'applyFixes must precede detectFixProgress');
115
- assert.match(body, /collectFindingThreadIds/);
116
- });
117
-
118
- test('CONVERGE places the P2-only branch between standards-only and generic fix', () => {
119
- const convergeBranch = phaseBranch("if (phase === 'CONVERGE')");
120
- const standardsIndex = convergeBranch.indexOf('isStandardsOnlyRound(findings)');
121
- const p2OnlyIndex = convergeBranch.indexOf('isP2OnlyFindings(findings)');
122
- const genericFixIndex = convergeBranch.indexOf("finding(s) — applying fixes");
123
- assert.notEqual(standardsIndex, -1, 'expected the standards-only branch');
124
- assert.notEqual(p2OnlyIndex, -1, 'expected the P2-only branch');
125
- assert.notEqual(genericFixIndex, -1, 'expected the generic fix branch');
126
- assert.ok(standardsIndex < p2OnlyIndex, 'standards-only must precede P2-only');
127
- assert.ok(p2OnlyIndex < genericFixIndex, 'P2-only must precede generic fix');
128
- });
129
-
130
- test('CONVERGE P2-only branch fixes once and routes via routeAfterP2OnlyFix', () => {
131
- const convergeBranch = phaseBranch("if (phase === 'CONVERGE')");
132
- const p2Start = convergeBranch.indexOf('isP2OnlyFindings(findings)');
133
- const genericFixStart = convergeBranch.indexOf("finding(s) — applying fixes");
134
- const p2Branch = convergeBranch.slice(p2Start, genericFixStart);
135
- assert.match(p2Branch, /P2-only/);
136
- assert.match(p2Branch, /applyP2OnlyFix\(head, findings, 'converge-round'/);
137
- assert.match(p2Branch, /routeAfterP2OnlyFix\(head, p2Fix, advancePhase\)/);
138
- assert.match(p2Branch, /nextPhaseAfterP2OnlyFix\('CONVERGE'\)/);
139
- assert.match(p2Branch, /head = p2Route\.fixedHead/);
140
- assert.match(p2Branch, /phase = p2Route\.nextPhase/);
141
- assert.doesNotMatch(p2Branch, /head = null/);
142
- });
143
-
144
- test('BUGBOT P2-only branch routes through routeAfterP2OnlyFix', () => {
145
- const bugbotBranch = phaseBranch("if (phase === 'BUGBOT')");
146
- const standardsIndex = bugbotBranch.indexOf('isStandardsOnlyRound(bugbotOutcome.findings)');
147
- const p2OnlyIndex = bugbotBranch.indexOf('isP2OnlyFindings(bugbotOutcome.findings)');
148
- const genericFixIndex = bugbotBranch.indexOf('fixing and re-converging');
149
- assert.ok(standardsIndex < p2OnlyIndex, 'standards-only must precede P2-only on BUGBOT');
150
- assert.ok(p2OnlyIndex < genericFixIndex, 'P2-only must precede generic re-converge on BUGBOT');
151
- const p2Branch = bugbotBranch.slice(p2OnlyIndex, genericFixIndex);
152
- assert.match(p2Branch, /P2-only/);
153
- assert.match(p2Branch, /nextPhaseAfterP2OnlyFix\('BUGBOT'\)/);
154
- assert.match(p2Branch, /applyP2OnlyFix\(head, bugbotOutcome\.findings, 'bugbot'/);
155
- assert.match(p2Branch, /routeAfterP2OnlyFix\(head, p2Fix, advancePhase\)/);
156
- assert.match(p2Branch, /phase = p2Route\.nextPhase/);
157
- });
158
-
159
- test('COPILOT P2-only branch routes through routeAfterP2OnlyFix', () => {
160
- const copilotBranch = phaseBranch("if (phase === 'COPILOT')");
161
- const standardsIndex = copilotBranch.indexOf('isStandardsOnlyRound(roundFindings)');
162
- const p2OnlyIndex = copilotBranch.indexOf('isP2OnlyFindings(roundFindings)');
163
- const genericFixIndex = copilotBranch.indexOf('fixing and re-converging');
164
- assert.ok(standardsIndex < p2OnlyIndex, 'standards-only must precede P2-only on COPILOT');
165
- assert.ok(p2OnlyIndex < genericFixIndex, 'P2-only must precede generic re-converge on COPILOT');
166
- const p2Branch = copilotBranch.slice(p2OnlyIndex, genericFixIndex);
167
- assert.match(p2Branch, /P2-only/);
168
- assert.match(p2Branch, /nextPhaseAfterP2OnlyFix\('COPILOT'\)/);
169
- assert.match(p2Branch, /applyP2OnlyFix\(head, roundFindings, 'copilot'/);
170
- assert.match(p2Branch, /routeAfterP2OnlyFix\(head, p2Fix, advancePhase\)/);
171
- assert.match(p2Branch, /phase = p2Route\.nextPhase/);
172
- });
173
-
174
- test('CODEX P2-only branch routes through routeAfterP2OnlyFix and stamps codexCleanAt only when HEAD is stable', () => {
175
- const codexBranch = phaseBranch("if (phase === 'CODEX')");
176
- const standardsIndex = codexBranch.indexOf('isStandardsOnlyRound(codexOutcome.findings)');
177
- const p2OnlyIndex = codexBranch.indexOf('isP2OnlyFindings(codexOutcome.findings)');
178
- const genericFixIndex = codexBranch.indexOf('fixing and re-converging');
179
- assert.ok(standardsIndex < p2OnlyIndex, 'standards-only must precede P2-only on CODEX');
180
- assert.ok(p2OnlyIndex < genericFixIndex, 'P2-only must precede generic re-converge on CODEX');
181
- const p2Branch = codexBranch.slice(p2OnlyIndex, genericFixIndex);
182
- assert.match(p2Branch, /P2-only/);
183
- assert.match(p2Branch, /nextPhaseAfterP2OnlyFix\('CODEX'\)/);
184
- assert.match(p2Branch, /applyP2OnlyFix\(head, codexOutcome\.findings, 'codex'/);
185
- assert.match(p2Branch, /routeAfterP2OnlyFix\(head, p2Fix, advancePhase\)/);
186
- assert.match(p2Branch, /codexCleanAt = head/);
187
- assert.match(p2Branch, /didMoveHead/);
188
- });
189
-
190
- test('generic fix branches still re-converge for mixed or P0/P1 findings', () => {
191
- const bugbotBranch = phaseBranch("if (phase === 'BUGBOT')");
192
- const genericStart = bugbotBranch.indexOf('fixing and re-converging');
193
- const genericBranch = bugbotBranch.slice(genericStart);
194
- assert.match(genericBranch, /phase = 'CONVERGE'/);
195
- assert.match(genericBranch, /head = null/);
196
-
197
- const copilotBranch = phaseBranch("if (phase === 'COPILOT')");
198
- const copilotGenericStart = copilotBranch.indexOf('fixing and re-converging');
199
- const copilotGeneric = copilotBranch.slice(copilotGenericStart);
200
- assert.match(copilotGeneric, /phase = 'CONVERGE'/);
201
- assert.match(copilotGeneric, /head = null/);
202
- });
@@ -1,47 +0,0 @@
1
- import { test } from 'node:test';
2
- import { strict as assert } from 'node:assert';
3
- import { readFileSync } from 'node:fs';
4
- import { fileURLToPath } from 'node:url';
5
- import { dirname, join } from 'node:path';
6
-
7
- const workflowDirectory = dirname(fileURLToPath(import.meta.url));
8
- const convergeSource = readFileSync(join(workflowDirectory, 'converge.mjs'), 'utf8');
9
-
10
- function sliceBetween(startNeedle, endNeedle) {
11
- const sliceStart = convergeSource.indexOf(startNeedle);
12
- assert.notEqual(sliceStart, -1, `expected ${startNeedle} to exist`);
13
- const sliceEnd = convergeSource.indexOf(endNeedle, sliceStart + startNeedle.length);
14
- assert.notEqual(sliceEnd, -1, `expected ${endNeedle} to exist after ${startNeedle}`);
15
- return convergeSource.slice(sliceStart, sliceEnd);
16
- }
17
-
18
- const productionModule = new Function(
19
- `${sliceBetween('const worktreeDirective =', '\nconst convergeAgent =')}\n` +
20
- 'return { worktreeDirective };',
21
- )();
22
- const { worktreeDirective } = productionModule;
23
-
24
- test('a single-PR run (no repoPath) produces an empty worktree directive', () => {
25
- assert.equal(worktreeDirective(null), '');
26
- });
27
-
28
- test('a path-scoped run pins every agent to the PR worktree by absolute path', () => {
29
- const directive = worktreeDirective('/worktrees/pr-398');
30
- assert.match(directive, /\/worktrees\/pr-398/);
31
- assert.match(directive, /cd /);
32
- assert.match(directive, /git, gh, diff, edit, commit, push, and test/);
33
- });
34
-
35
- test('a path-scoped run defers to a step that names a different repository directory', () => {
36
- assert.match(worktreeDirective('/worktrees/pr-398'), /different repository directory/i);
37
- });
38
-
39
- test('convergeAgent prepends the worktree directive for the active repo path', () => {
40
- const agentDefinition = sliceBetween('const convergeAgent =', '\nconst PRE_COMMIT_GATE_STEP');
41
- assert.match(agentDefinition, /worktreeDirective\(activeRepoPath\)/);
42
- assert.match(agentDefinition, /HEADLESS_EDIT_PREAMBLE/);
43
- });
44
-
45
- test('the run binds activeRepoPath from input.repoPath after the input is parsed', () => {
46
- assert.match(convergeSource, /activeRepoPath = typeof input\.repoPath === 'string'/);
47
- });
@@ -1,152 +0,0 @@
1
- import { test } from 'node:test';
2
- import { strict as assert } from 'node:assert';
3
- import { readFileSync } from 'node:fs';
4
- import { fileURLToPath } from 'node:url';
5
- import { dirname, join } from 'node:path';
6
-
7
- const workflowDirectory = dirname(fileURLToPath(import.meta.url));
8
- const convergeSource = readFileSync(join(workflowDirectory, 'converge.mjs'), 'utf8');
9
-
10
- function functionSource(functionName) {
11
- const functionStart = convergeSource.indexOf(`function ${functionName}(`);
12
- assert.notEqual(functionStart, -1, `expected ${functionName} to exist`);
13
- const nextMatch = /\n(?:async )?function /.exec(convergeSource.slice(functionStart + 1));
14
- const functionEnd =
15
- nextMatch === null ? convergeSource.length : functionStart + 1 + nextMatch.index;
16
- return convergeSource.slice(functionStart, functionEnd);
17
- }
18
-
19
- function sliceBetween(startNeedle, endNeedle) {
20
- const sliceStart = convergeSource.indexOf(startNeedle);
21
- assert.notEqual(sliceStart, -1, `expected ${startNeedle} to exist`);
22
- const sliceEnd = convergeSource.indexOf(endNeedle, sliceStart + startNeedle.length);
23
- assert.notEqual(sliceEnd, -1, `expected ${endNeedle} to exist after ${startNeedle}`);
24
- return convergeSource.slice(sliceStart, sliceEnd);
25
- }
26
-
27
- test('runStaticSweep exists and runs after the preflight-git no-SHA guard and before the parallel lenses', () => {
28
- assert.match(convergeSource, /function runStaticSweep\(/, 'expected the static-sweep lens builder to exist');
29
- const sweepCallIndex = convergeSource.indexOf('await runStaticSweep(');
30
- assert.notEqual(sweepCallIndex, -1, 'expected the CONVERGE round to invoke runStaticSweep');
31
- const noShaGuardIndex = convergeSource.indexOf('preflight-git agent returned no SHA');
32
- const parallelIndex = convergeSource.indexOf('const lenses = await parallel(');
33
- assert.ok(
34
- noShaGuardIndex !== -1 && noShaGuardIndex < sweepCallIndex,
35
- 'expected the static sweep to run after the no-SHA guard',
36
- );
37
- assert.ok(
38
- sweepCallIndex < parallelIndex,
39
- 'expected the static sweep to run before the opus reading lenses so they review sweep-clean code',
40
- );
41
- });
42
-
43
- test('the static-sweep prompt names the deterministic gates and never invokes the gh CLI', () => {
44
- const body = functionSource('runStaticSweep');
45
- assert.match(body, /code_rules_gate\.py/, 'expected the CODE_RULES gate to be named');
46
- assert.match(body, /--base/, 'expected the gate to run against the origin/main base');
47
- assert.match(body, /\bruff\b/, 'expected ruff to be named');
48
- assert.match(body, /\bmypy\b/, 'expected mypy to be named');
49
- assert.match(body, /\bpytest\b/, 'expected stem-matched pytest to be named');
50
- assert.doesNotMatch(body, /\bgh\b/, 'expected the sweep to use only local commands so it runs in a cloud session');
51
- });
52
-
53
- test('the static-sweep runs on the sonnetMedium tier via convergeReadOnlyAgent with the Explore agent type', () => {
54
- const body = functionSource('runStaticSweep');
55
- assert.match(body, /convergeReadOnlyAgent\(/, 'expected the sweep to spawn through the read-only preamble');
56
- assert.match(body, /renderLensDiffContext\(preflightResult\)/, 'expected the sweep to inject the preflight changed-file context');
57
- assert.match(body, /label: 'lens:static-sweep'/);
58
- assert.match(body, /agentType: 'Explore'/);
59
- assert.match(body, /\.\.\.TIERS\.sonnetMedium/, 'expected the deterministic sweep to run on the cheaper sonnet tier');
60
- });
61
-
62
- test('a static-sweep finding routes through applyFixes with the static-sweep label and nulls head before continue', () => {
63
- const sweepBranch = sliceBetween('await runStaticSweep(', "const lenses = await parallel(");
64
- assert.match(sweepBranch, /applyFixes\(head, sweep\.findings, 'static-sweep'\)/, 'expected sweep findings to route through applyFixes');
65
- assert.match(sweepBranch, /detectFixProgress\(sweepFix, head, false\)/, 'expected the sweep fix to check fix progress with no thread-bearing finding');
66
- const headNullIndex = sweepBranch.indexOf('head = null');
67
- const continueIndex = sweepBranch.indexOf('continue');
68
- assert.notEqual(headNullIndex, -1, 'expected the sweep-findings branch to null head so the next round reviews the fixed code');
69
- assert.ok(headNullIndex < continueIndex, 'expected head to be invalidated before the sweep branch continues');
70
- });
71
-
72
- test('runAuditLens carries the adversarial second pass and points at the pre-catch rubric', () => {
73
- const body = functionSource('runAuditLens');
74
- assert.match(body, /missed at least 3 P1/, 'expected the mandatory adversarial second pass');
75
- assert.match(body, /CONFIG\.precatchRubric/, 'expected the audit lens to point at the pre-catch rubric for the doc-parity/test/PR-description lanes');
76
- assert.doesNotMatch(body, /nothing new is an acceptable/i, 'expected a bare "nothing new" to be rejected');
77
- });
78
-
79
- test('runSelfReviewLens exists on opusMedium via convergeReadOnlyAgent and covers the three semantic lanes', () => {
80
- const body = functionSource('runSelfReviewLens');
81
- assert.match(body, /convergeReadOnlyAgent\(/, 'expected the self-review lens to spawn through the read-only preamble');
82
- assert.match(body, /renderLensDiffContext\(preflightResult\)/, 'expected the self-review lens to inject the preflight changed-file context');
83
- assert.match(body, /CONFIG\.precatchRubric/, 'expected the self-review lens to read the pre-catch rubric');
84
- assert.match(body, /pr-consistency-audit/, 'expected the self-review lens to reuse the pr-consistency-audit method');
85
- assert.match(body, /category-o-docstring-vs-impl-drift/, 'expected the self-review lens to cite the category-o drift rubric');
86
- assert.match(body, /parity/i, 'expected the doc-vs-code parity lane');
87
- assert.match(body, /Test-assertion completeness/i, 'expected the test-assertion completeness lane');
88
- assert.match(body, /PR-description-vs-diff/i, 'expected the PR-description parity lane');
89
- assert.match(body, /label: 'lens:self-review'/);
90
- assert.match(body, /\.\.\.TIERS\.opusMedium/, 'expected the semantic lens to stay on opus');
91
- });
92
-
93
- test('the round parallel array holds exactly the three internal lenses and no Bugbot slot', () => {
94
- const parallelArray = sliceBetween('const lenses = await parallel([', '])');
95
- assert.match(parallelArray, /runCodeReviewLens\(head, reviewerAvailability\)/);
96
- assert.match(parallelArray, /runAuditLens\(head, reviewerAvailability\)/);
97
- assert.match(parallelArray, /runSelfReviewLens\(head, reviewerAvailability\)/);
98
- assert.doesNotMatch(parallelArray, /runBugbotLens/, 'expected Bugbot to leave the per-round parallel and become a terminal gate');
99
- assert.doesNotMatch(parallelArray, /isBugbotDownPreSpawn/, 'expected the pre-spawn Bugbot-down decision to be gone from the round');
100
- assert.doesNotMatch(convergeSource, /const isBugbotDownPreSpawn/, 'expected no pre-spawn Bugbot-down decision anywhere in the round');
101
- });
102
-
103
- test('both the CONVERGE clean branch and the standards-only branch route to the terminal BUGBOT phase', () => {
104
- const convergeBranch = sliceBetween("if (phase === 'CONVERGE') {", "if (phase === 'BUGBOT') {");
105
- const toBugbot = convergeBranch.match(/phase = 'BUGBOT'/g) || [];
106
- assert.equal(toBugbot.length, 2, 'expected the standards-only and all-clean branches to both set phase = BUGBOT');
107
- assert.doesNotMatch(convergeBranch, /phase = 'COPILOT'/, 'expected the CONVERGE block to route to BUGBOT, not straight to COPILOT');
108
- });
109
-
110
- test('the terminal BUGBOT phase skips runBugbotLens when the reviewer-availability gate reports Bugbot down', () => {
111
- const bugbotPhase = sliceBetween("if (phase === 'BUGBOT') {", "if (phase === 'COPILOT') {");
112
- const availabilityGateIndex = bugbotPhase.indexOf('resolveReviewerDown(reviewerAvailability?.bugbot, input.bugbotDisabled || false)');
113
- const gateCallIndex = bugbotPhase.indexOf('await runBugbotLens(head, reviewerAvailability)');
114
- assert.notEqual(availabilityGateIndex, -1, 'expected the terminal gate to consult resolveReviewerDown before spawning the Bugbot lens');
115
- assert.notEqual(gateCallIndex, -1, 'expected the terminal gate to call runBugbotLens when Bugbot is enabled');
116
- assert.ok(availabilityGateIndex < gateCallIndex, 'expected the availability gate to short-circuit before any Bugbot agent spawns');
117
- const beforeGate = bugbotPhase.slice(availabilityGateIndex, gateCallIndex);
118
- assert.match(beforeGate, /bugbotDown = true/, 'expected the availability-down path to mark bugbotDown');
119
- assert.match(beforeGate, /phase = 'COPILOT'/, 'expected the availability-down path to advance to the Copilot gate with no agent');
120
- });
121
-
122
- test('the terminal BUGBOT phase classifies via the shared reviewer-gate classifier and routes each outcome', () => {
123
- const bugbotPhase = sliceBetween("if (phase === 'BUGBOT') {", "if (phase === 'COPILOT') {");
124
- assert.match(bugbotPhase, /classifyReviewerGateOutcome\(bugbot\)/, 'expected the terminal gate to reuse the shared reviewer-gate classifier');
125
- assert.match(bugbotPhase, /applyFixes\(head, bugbotOutcome\.findings, 'bugbot'\)/, 'expected a Bugbot fix outcome to route through applyFixes');
126
- assert.match(bugbotPhase, /head = null\n\s*phase = 'CONVERGE'/, 'expected a Bugbot fix to invalidate head and re-enter CONVERGE');
127
- assert.match(bugbotPhase, /phase = 'COPILOT'/, 'expected a clean or down Bugbot verdict to advance to the Copilot gate');
128
- });
129
-
130
- test('convergeReadOnlyAgent exists and the read-only preamble omits the rm-shape paragraph the edit preamble keeps', () => {
131
- assert.match(convergeSource, /const convergeReadOnlyAgent = \(prompt, options\) =>/, 'expected the read-only agent spawner to exist');
132
- const preambleRegion = convergeSource.slice(
133
- convergeSource.indexOf('const HEADLESS_EDIT_PREAMBLE ='),
134
- convergeSource.indexOf('\nlet activeRepoPath'),
135
- );
136
- const preambleModule = new Function(
137
- `${preambleRegion}\nreturn { HEADLESS_EDIT_PREAMBLE, HEADLESS_READONLY_PREAMBLE };`,
138
- )();
139
- assert.match(preambleModule.HEADLESS_EDIT_PREAMBLE, /rm shape rules/, 'expected the edit preamble to retain the rm-shape rules');
140
- assert.doesNotMatch(preambleModule.HEADLESS_READONLY_PREAMBLE, /rm shape rules/, 'expected the read-only preamble to drop the rm-shape paragraph');
141
- assert.ok(
142
- preambleModule.HEADLESS_READONLY_PREAMBLE.length < preambleModule.HEADLESS_EDIT_PREAMBLE.length,
143
- 'expected the read-only preamble to be shorter than the edit preamble',
144
- );
145
- });
146
-
147
- test('COMMIT_RECOVERY_MAX_ATTEMPTS is one and bounds the commitWithRecovery loop', () => {
148
- assert.match(convergeSource, /const COMMIT_RECOVERY_MAX_ATTEMPTS = 1/, 'expected a dedicated commit-recovery cap of one');
149
- assert.match(convergeSource, /const FIX_RECOVERY_MAX_ATTEMPTS = 2/, 'expected the wider verify-recovery cap to stay at two');
150
- const commitBody = functionSource('commitWithRecovery');
151
- assert.match(commitBody, /attempt <= COMMIT_RECOVERY_MAX_ATTEMPTS/, 'expected commitWithRecovery to bound its loop by the dedicated cap');
152
- });
@@ -1,116 +0,0 @@
1
- import { test } from 'node:test';
2
- import { strict as assert } from 'node:assert';
3
- import { readFileSync } from 'node:fs';
4
- import { fileURLToPath } from 'node:url';
5
- import { dirname, join } from 'node:path';
6
-
7
- const workflowDirectory = dirname(fileURLToPath(import.meta.url));
8
- const convergeSource = readFileSync(join(workflowDirectory, 'converge.mjs'), 'utf8');
9
-
10
- function sourceSliceBetween(startNeedle, endNeedle) {
11
- const sliceStart = convergeSource.indexOf(startNeedle);
12
- assert.notEqual(sliceStart, -1, `expected ${startNeedle} to exist`);
13
- const sliceEnd = convergeSource.indexOf(endNeedle, sliceStart + startNeedle.length);
14
- assert.notEqual(sliceEnd, -1, `expected ${endNeedle} to exist after ${startNeedle}`);
15
- return convergeSource.slice(sliceStart, sliceEnd);
16
- }
17
-
18
- const productionModule = new Function(
19
- `${sourceSliceBetween('function normalizeRunInput(', '\nconst runInput =')}\n` +
20
- 'return { normalizeRunInput, classifyRunInput, githubTransportDirective };',
21
- )();
22
-
23
- const { normalizeRunInput, classifyRunInput, githubTransportDirective } = productionModule;
24
-
25
- const VALID_COORDINATES = { owner: 'jl-cmd', repo: 'claude-dev-env', prNumber: 543 };
26
-
27
- test('an object payload passes through unchanged', () => {
28
- assert.deepEqual(normalizeRunInput(VALID_COORDINATES), VALID_COORDINATES);
29
- });
30
-
31
- test('a JSON-encoded string payload is parsed into coordinates', () => {
32
- assert.deepEqual(normalizeRunInput(JSON.stringify(VALID_COORDINATES)), VALID_COORDINATES);
33
- });
34
-
35
- test('a non-JSON string returns null rather than throwing', () => {
36
- assert.equal(normalizeRunInput('not json at all'), null);
37
- });
38
-
39
- test('an empty string returns null rather than throwing', () => {
40
- assert.equal(normalizeRunInput(''), null);
41
- });
42
-
43
- test('classifyRunInput accepts coordinates carrying owner, repo, and prNumber', () => {
44
- const classified = classifyRunInput(VALID_COORDINATES);
45
- assert.deepEqual(classified.input, VALID_COORDINATES);
46
- assert.equal(classified.blocker, null);
47
- });
48
-
49
- test('classifyRunInput accepts the cloud transport without changing the input shape', () => {
50
- const cloudInput = { ...VALID_COORDINATES, transport: 'cloud' };
51
- const classified = classifyRunInput(cloudInput);
52
- assert.deepEqual(classified.input, cloudInput);
53
- assert.equal(classified.blocker, null);
54
- });
55
-
56
- test('classifyRunInput blocks an unknown transport before any GitHub work starts', () => {
57
- const classified = classifyRunInput({ ...VALID_COORDINATES, transport: 'proxy' });
58
- assert.equal(classified.input, null);
59
- assert.match(classified.blocker, /transport/i);
60
- });
61
-
62
- test('classifyRunInput blocks a failed parse with a structured blocker and no input', () => {
63
- const classified = classifyRunInput('not json at all');
64
- assert.equal(classified.input, null);
65
- assert.match(classified.blocker, /coordinates/i);
66
- });
67
-
68
- test('classifyRunInput blocks a null payload with a structured blocker', () => {
69
- const classified = classifyRunInput(null);
70
- assert.equal(classified.input, null);
71
- assert.match(classified.blocker, /coordinates/i);
72
- });
73
-
74
- test('classifyRunInput blocks a payload missing owner', () => {
75
- const classified = classifyRunInput({ repo: 'claude-dev-env', prNumber: 543 });
76
- assert.equal(classified.input, null);
77
- assert.match(classified.blocker, /coordinates/i);
78
- });
79
-
80
- test('classifyRunInput blocks a payload missing prNumber', () => {
81
- const classified = classifyRunInput({ owner: 'jl-cmd', repo: 'claude-dev-env' });
82
- assert.equal(classified.input, null);
83
- assert.match(classified.blocker, /coordinates/i);
84
- });
85
-
86
- test('the top-level run guards an unusable input into a structured blocker before reading input.owner', () => {
87
- const guardBlock = convergeSource.slice(
88
- convergeSource.indexOf('const runInput = classifyRunInput('),
89
- convergeSource.indexOf('const prCoordinates ='),
90
- );
91
- assert.match(guardBlock, /runInput\.blocker/);
92
- assert.match(guardBlock, /converged: false/);
93
- assert.match(guardBlock, /return/);
94
- });
95
-
96
- test('classifyRunInput passes copilotDisabled through alongside the coordinates', () => {
97
- const classified = classifyRunInput({ ...VALID_COORDINATES, copilotDisabled: true });
98
- assert.equal(classified.blocker, null);
99
- assert.equal(classified.input.copilotDisabled, true);
100
- });
101
-
102
- test('classifyRunInput leaves copilotDisabled undefined when the input omits it', () => {
103
- const classified = classifyRunInput(VALID_COORDINATES);
104
- assert.equal(classified.input.copilotDisabled, undefined);
105
- });
106
-
107
- test('the cloud transport directive selects MCP and contains no local CLI auth command', () => {
108
- const cloudDirective = githubTransportDirective('cloud');
109
- assert.match(cloudDirective, /mcp__github__/);
110
- assert.match(cloudDirective, /credentialed push path/);
111
- assert.doesNotMatch(cloudDirective, /gh auth/);
112
- });
113
-
114
- test('the local transport directive keeps the local CLI path', () => {
115
- assert.match(githubTransportDirective('local'), /authenticated local GitHub CLI/);
116
- });