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
@@ -0,0 +1,87 @@
1
+ """Exercise the native Git commit boundary in disposable repositories."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import json
6
+ import shlex
7
+ import subprocess
8
+ import sys
9
+ from pathlib import Path
10
+
11
+ import pre_commit
12
+ import pytest
13
+ from test_pre_commit import _git, _stage
14
+ from test_pre_commit import repository_root as repository_root
15
+
16
+
17
+ @pytest.fixture()
18
+ def installed_native_hook(
19
+ repository_root: Path,
20
+ monkeypatch: pytest.MonkeyPatch,
21
+ ) -> Path:
22
+ """Install a native fixture shim pointing to the actual pre-commit owner."""
23
+ hook_directory = repository_root / ".git" / "fixture-native-hooks"
24
+ hook_directory.mkdir()
25
+ hook_path = hook_directory / "pre-commit"
26
+ command = " ".join(
27
+ shlex.quote(each_argument)
28
+ for each_argument in (sys.executable, str(Path(pre_commit.__file__).resolve()))
29
+ )
30
+ hook_path.write_text(f"#!/bin/sh\nexec {command}\n", encoding="utf-8")
31
+ hook_path.chmod(0o755)
32
+ _git(repository_root, "config", "core.hooksPath", str(hook_directory))
33
+ monkeypatch.setenv("CODE_RULES_GATE_PATH", str(repository_root / "missing-legacy-gate.py"))
34
+ return repository_root
35
+
36
+
37
+ def test_valid_commit_passes_the_installed_native_hook(installed_native_hook: Path) -> None:
38
+ before = _git(installed_native_hook, "rev-parse", "HEAD")
39
+ _stage(installed_native_hook, "docs/config.md", "The API uses port 8080.\n")
40
+ _git(installed_native_hook, "commit", "-m", "valid fixture")
41
+ assert _git(installed_native_hook, "rev-parse", "HEAD") != before
42
+
43
+
44
+ def _assert_write_proceeds(repository_root: Path, relative_path: str, content: str) -> None:
45
+ """Exercise the actual dispatcher before attempting the staged commit."""
46
+ hooks_root = Path(pre_commit.__file__).resolve().parent.parent
47
+ payload = {
48
+ "tool_name": "Write",
49
+ "cwd": str(repository_root),
50
+ "tool_input": {
51
+ "file_path": str(repository_root / relative_path),
52
+ "content": content,
53
+ },
54
+ }
55
+ edit_result = subprocess.run(
56
+ [sys.executable, str(hooks_root / "blocking/pre_tool_use_dispatcher.py")],
57
+ cwd=repository_root,
58
+ input=json.dumps(payload),
59
+ capture_output=True,
60
+ text=True,
61
+ check=False,
62
+ timeout=90,
63
+ )
64
+ assert edit_result.returncode == 0, edit_result.stderr
65
+ edit_output = json.loads(edit_result.stdout or "{}")
66
+ assert edit_output.get("hookSpecificOutput", {}).get("permissionDecision") != "deny"
67
+
68
+
69
+ def test_retired_write_check_allows_edit_but_local_commit_catches_violation(
70
+ installed_native_hook: Path,
71
+ ) -> None:
72
+ relative_path = "docs/config.md"
73
+ content = "Previously set via env var.\n"
74
+ _assert_write_proceeds(installed_native_hook, relative_path, content)
75
+ before = _git(installed_native_hook, "rev-parse", "HEAD")
76
+ _stage(installed_native_hook, relative_path, content)
77
+ commit_result = subprocess.run(
78
+ ["git", "commit", "-m", "invalid fixture"],
79
+ cwd=installed_native_hook,
80
+ capture_output=True,
81
+ text=True,
82
+ check=False,
83
+ timeout=240,
84
+ )
85
+ assert commit_result.returncode != 0
86
+ assert "state-description" in commit_result.stdout + commit_result.stderr
87
+ assert _git(installed_native_hook, "rev-parse", "HEAD") == before
@@ -1,10 +1,16 @@
1
1
  from __future__ import annotations
2
2
 
3
+ import json
4
+ import os
5
+ import subprocess
6
+ import sys
3
7
  from pathlib import Path
4
8
 
5
9
  import pre_commit
6
10
  import pytest
7
11
 
12
+ from git_hooks_constants.staged_policy_lint import POLICY_LINT_TIMEOUT_SECONDS
13
+
8
14
 
9
15
  def make_gate_script_returning(exit_code: int, target_path: Path) -> Path:
10
16
  target_path.write_text(
@@ -170,3 +176,243 @@ def test_invoke_gate_uses_resolved_path(
170
176
  assert exit_code == 0
171
177
  executed_path = recorded_path_file.read_text(encoding="utf-8")
172
178
  assert executed_path == str(resolved_path)
179
+
180
+
181
+ RMTREE_FIXTURE_KEYWORD = "ignore_errors"
182
+ ALL_RULE_FIXTURES = (
183
+ (
184
+ "code-rules",
185
+ "src/worker.py",
186
+ "from typing import Any\n\ndef worker() -> Any:\n return None\n",
187
+ ),
188
+ (
189
+ "test-pairing",
190
+ "src/feature.py",
191
+ "def work() -> None:\n pass\n",
192
+ ),
193
+ (
194
+ "rmtree-safety",
195
+ "src/cleanup.py",
196
+ f"import shutil\nshutil.rmtree('fixture', {RMTREE_FIXTURE_KEYWORD}=True)\n",
197
+ ),
198
+ (
199
+ "state-description",
200
+ "docs/config.md",
201
+ "# Config\n\nPreviously set via env var.\n",
202
+ ),
203
+ (
204
+ "subprocess-budget",
205
+ "src/timing.py",
206
+ "import subprocess\n"
207
+ "PYTHON_FORMAT_TIMEOUT_SECONDS = 12\n"
208
+ "GIT_CHECK_TIMEOUT_SECONDS = 5\n"
209
+ "def worst_case_python_format_seconds() -> int:\n"
210
+ " fix_phase_seconds = PYTHON_FORMAT_TIMEOUT_SECONDS\n"
211
+ " format_phase_seconds = PYTHON_FORMAT_TIMEOUT_SECONDS\n"
212
+ " return fix_phase_seconds + format_phase_seconds\n"
213
+ "def is_untracked_in_git(file_path: str) -> bool:\n"
214
+ " git_check = subprocess.run(['git', 'ls-files', file_path], "
215
+ "timeout=GIT_CHECK_TIMEOUT_SECONDS)\n"
216
+ " return git_check.returncode != 0\n"
217
+ "def run_format(file_path: str) -> None:\n"
218
+ " subprocess.run(['ruff', 'format', file_path], "
219
+ "timeout=PYTHON_FORMAT_TIMEOUT_SECONDS)\n"
220
+ "def main(file_path: str) -> None:\n"
221
+ " if is_untracked_in_git(file_path):\n"
222
+ " return\n"
223
+ " run_format(file_path)\n",
224
+ ),
225
+ (
226
+ "hook-prose-consistency",
227
+ "hooks/hooks_constants/probe_constants.py",
228
+ 'CORRECTIVE_MESSAGE = "appears as a path or output-key segment"\n',
229
+ ),
230
+ (
231
+ "workflow-substitution",
232
+ "scripts/sample.workflow.js",
233
+ "For EACH candidate i, build a bible dir cand_i per the contract.\n"
234
+ " & ${PY} compose.py --out ${args.work_dir}\\\\cand_i\\\\sample.png "
235
+ "--glow <candidate glow_hex>\n"
236
+ 'Return: {key: "cand_i", name, sample_png}\n',
237
+ ),
238
+ )
239
+
240
+
241
+ def _git(repository_root: Path, *all_arguments: str) -> str:
242
+ completed = subprocess.run(
243
+ ["git", *all_arguments],
244
+ cwd=repository_root,
245
+ check=True,
246
+ capture_output=True,
247
+ text=True,
248
+ timeout=30,
249
+ )
250
+ return completed.stdout.strip()
251
+
252
+
253
+ @pytest.fixture()
254
+ def repository_root(
255
+ tmp_path_factory: pytest.TempPathFactory, monkeypatch: pytest.MonkeyPatch,
256
+ ) -> Path:
257
+ """Create a repository with private Git configuration and no inherited hooks."""
258
+ tmp_path = tmp_path_factory.mktemp("policy-fixture")
259
+ home_directory = tmp_path / "home"
260
+ home_directory.mkdir()
261
+ monkeypatch.setenv("HOME", str(home_directory))
262
+ monkeypatch.setenv("USERPROFILE", str(home_directory))
263
+ monkeypatch.setenv("GIT_CONFIG_GLOBAL", os.devnull)
264
+ monkeypatch.setenv("GIT_CONFIG_NOSYSTEM", "1")
265
+ monkeypatch.delenv("GIT_INDEX_FILE", raising=False)
266
+ monkeypatch.delenv("GIT_DIR", raising=False)
267
+ monkeypatch.delenv("GIT_WORK_TREE", raising=False)
268
+ root = tmp_path / "repository"
269
+ root.mkdir()
270
+ _git(root, "init")
271
+ _git(root, "config", "core.hooksPath", str(tmp_path / "disabled-fixture-hooks"))
272
+ _git(root, "config", "user.name", "Fixture")
273
+ _git(root, "config", "user.email", "fixture@example.com")
274
+ _git(root, "commit", "--allow-empty", "-m", "fixture base")
275
+ monkeypatch.chdir(root)
276
+ return root
277
+
278
+
279
+ def _stage(repository_root: Path, relative_path: str, content: str) -> Path:
280
+ file_path = repository_root / relative_path
281
+ file_path.parent.mkdir(parents=True, exist_ok=True)
282
+ file_path.write_text(content, encoding="utf-8")
283
+ _git(repository_root, "add", "--", relative_path)
284
+ return file_path
285
+
286
+
287
+ def _lint_report(repository_root: Path) -> tuple[int, dict[str, object]]:
288
+ completed = subprocess.run(
289
+ [
290
+ sys.executable,
291
+ str(pre_commit.resolve_policy_lint_script_path()),
292
+ "--staged",
293
+ "--format",
294
+ "json",
295
+ ],
296
+ cwd=repository_root,
297
+ check=False,
298
+ capture_output=True,
299
+ text=True,
300
+ timeout=POLICY_LINT_TIMEOUT_SECONDS,
301
+ )
302
+ assert completed.stderr == "", completed.stderr
303
+ return completed.returncode, json.loads(completed.stdout)
304
+
305
+
306
+ @pytest.mark.parametrize(("rule_id", "relative_path", "content"), ALL_RULE_FIXTURES)
307
+ def test_real_staged_linter_catches_each_replaced_rule(
308
+ repository_root: Path,
309
+ rule_id: str,
310
+ relative_path: str,
311
+ content: str,
312
+ ) -> None:
313
+ _stage(repository_root, relative_path, content)
314
+ exit_code, report = _lint_report(repository_root)
315
+ assert exit_code == 1, report
316
+ assert report["failed_rules"] == [], report
317
+ all_diagnostics = report["diagnostics"]
318
+ assert isinstance(all_diagnostics, list)
319
+ assert rule_id in {each["rule_id"] for each in all_diagnostics}, report
320
+
321
+
322
+ def _stage_valid_pair(repository_root: Path, relative_path: str) -> None:
323
+ source_path = Path(relative_path)
324
+ clean_content = {
325
+ ".py": (
326
+ "def is_ready() -> bool:\n"
327
+ ' """Report readiness.\n\n'
328
+ " Returns:\n True for the fixture.\n"
329
+ ' """\n'
330
+ " return True\n"
331
+ ),
332
+ ".js": "export const isEnabled = true;\n",
333
+ ".md": "# Config\n\nThe API uses port 8080.\n",
334
+ }[source_path.suffix]
335
+ _stage(repository_root, relative_path, clean_content)
336
+ paired_name = (
337
+ f"test_{source_path.stem}.py"
338
+ if source_path.suffix == ".py"
339
+ else f"{source_path.stem}.test{source_path.suffix}"
340
+ )
341
+ paired_content = (
342
+ f"from {source_path.stem} import is_ready\n\n"
343
+ "def test_is_ready() -> None:\n assert is_ready()\n"
344
+ if source_path.suffix == ".py"
345
+ else ""
346
+ )
347
+ _stage(repository_root, (source_path.parent / paired_name).as_posix(), paired_content)
348
+
349
+
350
+ @pytest.mark.parametrize(("rule_id", "relative_path", "content"), ALL_RULE_FIXTURES)
351
+ def test_valid_paired_content_passes_the_real_local_commit_linter(
352
+ repository_root: Path,
353
+ rule_id: str,
354
+ relative_path: str,
355
+ content: str,
356
+ ) -> None:
357
+ _stage_valid_pair(repository_root, relative_path)
358
+ assert pre_commit.run_staged_policy_lint() == 0
359
+
360
+
361
+ def test_unstaged_fix_does_not_hide_staged_violation(repository_root: Path) -> None:
362
+ target = _stage(repository_root, "docs/config.md", "Previously set via env var.\n")
363
+ target.write_text("The API uses port 8080.\n", encoding="utf-8")
364
+ assert pre_commit.run_staged_policy_lint() == 1
365
+
366
+
367
+ def test_alternate_git_index_is_checked(
368
+ repository_root: Path,
369
+ monkeypatch: pytest.MonkeyPatch,
370
+ ) -> None:
371
+ alternate_index = repository_root / ".git" / "alternate-index"
372
+ monkeypatch.setenv("GIT_INDEX_FILE", str(alternate_index))
373
+ _git(repository_root, "read-tree", "HEAD")
374
+ _stage(repository_root, "docs/config.md", "Previously set via env var.\n")
375
+ assert pre_commit.run_staged_policy_lint() == 1
376
+ monkeypatch.delenv("GIT_INDEX_FILE")
377
+ assert pre_commit.run_staged_policy_lint() == 0
378
+
379
+
380
+ def test_missing_linter_does_not_allow_commit(
381
+ tmp_path: Path,
382
+ monkeypatch: pytest.MonkeyPatch,
383
+ ) -> None:
384
+ monkeypatch.setattr(
385
+ pre_commit, "resolve_policy_lint_script_path", lambda: tmp_path / "missing.py"
386
+ )
387
+ assert pre_commit.main() == 2
388
+
389
+
390
+ @pytest.mark.parametrize("exit_code", (1, 2, 3))
391
+ def test_linter_failure_reaches_git_before_legacy_gate(
392
+ monkeypatch: pytest.MonkeyPatch,
393
+ exit_code: int,
394
+ ) -> None:
395
+ monkeypatch.setattr(pre_commit, "run_staged_policy_lint", lambda: exit_code)
396
+ all_gate_calls: list[object] = []
397
+ monkeypatch.setattr(
398
+ pre_commit,
399
+ "resolve_gate_script_path",
400
+ lambda: all_gate_calls.append("unexpected gate"),
401
+ )
402
+ assert pre_commit.main() == exit_code
403
+ assert all_gate_calls == []
404
+
405
+
406
+ def test_timeout_is_an_infrastructure_failure(
407
+ tmp_path: Path,
408
+ monkeypatch: pytest.MonkeyPatch,
409
+ ) -> None:
410
+ script_path = tmp_path / "lint.py"
411
+ script_path.write_text("", encoding="utf-8")
412
+ monkeypatch.setattr(pre_commit, "resolve_policy_lint_script_path", lambda: script_path)
413
+
414
+ def timed_out(*all_arguments: object, **all_options: object) -> object:
415
+ raise subprocess.TimeoutExpired("lint fixture", POLICY_LINT_TIMEOUT_SECONDS)
416
+
417
+ monkeypatch.setattr(pre_commit.subprocess, "run", timed_out)
418
+ assert pre_commit.run_staged_policy_lint() == 2
package/hooks/hooks.json CHANGED
@@ -45,11 +45,6 @@
45
45
  {
46
46
  "matcher": "mcp__plugin_github_github__.*",
47
47
  "hooks": [
48
- {
49
- "type": "command",
50
- "command": "python3 ${CLAUDE_PLUGIN_ROOT}/hooks/blocking/volatile_path_in_post_blocker.py",
51
- "timeout": 10
52
- },
53
48
  {
54
49
  "type": "command",
55
50
  "command": "python3 ${CLAUDE_PLUGIN_ROOT}/hooks/blocking/pii_prevention_blocker.py",
@@ -149,11 +144,6 @@
149
144
  "command": "python3 ${CLAUDE_PLUGIN_ROOT}/hooks/session/session_env_cleanup.py",
150
145
  "timeout": 10
151
146
  },
152
- {
153
- "type": "command",
154
- "command": "python3 ${CLAUDE_PLUGIN_ROOT}/hooks/session/gh_pr_author_session_cleanup.py",
155
- "timeout": 30
156
- },
157
147
  {
158
148
  "type": "command",
159
149
  "command": "python3 ${CLAUDE_PLUGIN_ROOT}/hooks/session/session_edit_tracker_cleanup.py",
@@ -251,16 +241,11 @@
251
241
  "type": "command",
252
242
  "command": "python3 ${CLAUDE_PLUGIN_ROOT}/hooks/workflow/investigation_tracker_reset.py",
253
243
  "timeout": 30
254
- },
255
- {
256
- "type": "command",
257
- "command": "python3 ${CLAUDE_PLUGIN_ROOT}/hooks/observability/pr_description_writer_spawn_tracker.py",
258
- "timeout": 30
259
244
  }
260
245
  ]
261
246
  },
262
247
  {
263
- "matcher": "Bash",
248
+ "matcher": "Bash|PowerShell",
264
249
  "hooks": [
265
250
  {
266
251
  "type": "command",
@@ -10,13 +10,25 @@ no second copy of either.
10
10
  from __future__ import annotations
11
11
 
12
12
  from hooks_constants.bash_pre_tool_use_dispatcher_constants import (
13
+ ALL_BASH_AND_POWERSHELL_TOOL_NAMES,
13
14
  ALL_BASH_ONLY_TOOL_NAMES,
14
15
  BashHostedHookEntry,
15
16
  )
16
17
 
17
- __all__ = ["ALL_BASH_POST_TOOL_USE_HOSTED_HOOK_ENTRIES"]
18
+ __all__ = [
19
+ "ALL_BASH_POST_TOOL_USE_HOSTED_HOOK_ENTRIES",
20
+ "POST_TOOL_USE_HOOK_EVENT_NAME",
21
+ "HOOK_SPECIFIC_OUTPUT_KEY",
22
+ "ADDITIONAL_CONTEXT_KEY",
23
+ "ADDITIONAL_CONTEXT_JOIN_SEPARATOR",
24
+ ]
18
25
 
19
26
  ALL_BASH_POST_TOOL_USE_HOSTED_HOOK_ENTRIES: tuple[BashHostedHookEntry, ...] = (
20
- BashHostedHookEntry("blocking/gh_pr_author_restore.py", ALL_BASH_ONLY_TOOL_NAMES),
21
27
  BashHostedHookEntry("observability/test_failure_recorder.py", ALL_BASH_ONLY_TOOL_NAMES),
28
+ BashHostedHookEntry("advisory/pr_done_reminder.py", ALL_BASH_AND_POWERSHELL_TOOL_NAMES),
22
29
  )
30
+
31
+ POST_TOOL_USE_HOOK_EVENT_NAME: str = "PostToolUse"
32
+ HOOK_SPECIFIC_OUTPUT_KEY: str = "hookSpecificOutput"
33
+ ADDITIONAL_CONTEXT_KEY: str = "additionalContext"
34
+ ADDITIONAL_CONTEXT_JOIN_SEPARATOR: str = "\n\n"
@@ -56,7 +56,6 @@ class BashHostedHookEntry:
56
56
 
57
57
  ALL_BASH_HOSTED_HOOK_ENTRIES: tuple[BashHostedHookEntry, ...] = (
58
58
  BashHostedHookEntry("blocking/destructive_command_blocker.py", ALL_BASH_ONLY_TOOL_NAMES),
59
- BashHostedHookEntry("blocking/gh_body_arg_blocker.py", ALL_BASH_ONLY_TOOL_NAMES),
60
59
  BashHostedHookEntry("blocking/shell_substitution_blocker.py", ALL_BASH_ONLY_TOOL_NAMES),
61
60
  BashHostedHookEntry("blocking/piped_pytest_blocker.py", ALL_BASH_ONLY_TOOL_NAMES),
62
61
  BashHostedHookEntry(
@@ -65,15 +64,8 @@ ALL_BASH_HOSTED_HOOK_ENTRIES: tuple[BashHostedHookEntry, ...] = (
65
64
  ),
66
65
  BashHostedHookEntry("blocking/unscoped_search_blocker.py", ALL_BASH_AND_POWERSHELL_TOOL_NAMES),
67
66
  BashHostedHookEntry("blocking/nas_ssh_binary_enforcer.py", ALL_BASH_ONLY_TOOL_NAMES),
68
- BashHostedHookEntry("blocking/volatile_path_in_post_blocker.py", ALL_BASH_ONLY_TOOL_NAMES),
69
67
  BashHostedHookEntry("blocking/pii_prevention_blocker.py", ALL_BASH_AND_POWERSHELL_TOOL_NAMES),
70
- BashHostedHookEntry("blocking/conventional_pr_title_gate.py", ALL_BASH_ONLY_TOOL_NAMES),
71
68
  BashHostedHookEntry("blocking/block_main_commit.py", ALL_BASH_ONLY_TOOL_NAMES),
72
69
  BashHostedHookEntry("blocking/session_edit_stage_gate.py", ALL_BASH_ONLY_TOOL_NAMES),
73
- BashHostedHookEntry("blocking/test_preflight_check.py", ALL_BASH_ONLY_TOOL_NAMES),
74
70
  BashHostedHookEntry("blocking/windows_rmtree_blocker.py", ALL_BASH_ONLY_TOOL_NAMES),
75
- BashHostedHookEntry("blocking/gh_pr_author_enforcer.py", ALL_BASH_ONLY_TOOL_NAMES),
76
- BashHostedHookEntry(
77
- "blocking/pr_description_writer_gate.py", ALL_BASH_AND_POWERSHELL_TOOL_NAMES
78
- ),
79
71
  )
@@ -0,0 +1,12 @@
1
+ """Configuration constants for GitHub post body extraction."""
2
+
3
+ ALL_GH_POST_SUBCOMMANDS: dict[str, frozenset[str]] = {
4
+ "issue": frozenset({"comment", "create", "edit"}),
5
+ "pr": frozenset({"comment", "create", "edit", "review"}),
6
+ }
7
+ ALL_MCP_BODY_PARAM_NAMES: tuple[str, ...] = ("body", "comment")
8
+ BODY_FILE_ENCODING = "utf-8"
9
+ BODY_FLAG_WITH_VALUE_STEP = 2
10
+ GH_COMMAND_NAME = "gh"
11
+ MINIMUM_POST_SUBCOMMAND_TOKEN_COUNT = 2
12
+ TOKEN_JOIN_SEPARATOR = " "
@@ -0,0 +1,98 @@
1
+ """Constants for the PR done-checklist context reminder.
2
+
3
+ The reminder is a PostToolUse observer on Bash. It never blocks. After a
4
+ successful ``git push`` or ``gh pr create`` it probes the branch's pull request
5
+ through ``gh`` and adds one loud checklist to the agent's context.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ __all__ = [
11
+ "GIT_PROGRAM_NAME",
12
+ "GIT_PUSH_SUBCOMMAND",
13
+ "GH_PROGRAM_NAME",
14
+ "GH_PR_SUBCOMMAND",
15
+ "GH_PR_CREATE_ACTION",
16
+ "ALL_GIT_OPTIONS_WITH_VALUE",
17
+ "ALL_POWERSHELL_PROGRAM_NAMES",
18
+ "ALL_POWERSHELL_COMMAND_FLAGS",
19
+ "ALL_GH_PR_VIEW_ARGUMENTS",
20
+ "GH_PR_VIEW_TIMEOUT_SECONDS",
21
+ "NO_PULL_REQUEST_MARKER",
22
+ "EXIT_CODE_ERROR_PREFIX",
23
+ "DONE_LABEL_NAME",
24
+ "MERGEABLE_CLEAN_VALUE",
25
+ "MERGEABLE_CONFLICTING_VALUE",
26
+ "MERGEABLE_UNKNOWN_VALUE",
27
+ "ALL_FAILING_CHECK_CONCLUSIONS",
28
+ "ALL_PASSING_CHECK_CONCLUSIONS",
29
+ "CHECK_COMPLETED_STATUS",
30
+ "STATUS_CONTEXT_STATE_KEY",
31
+ "REMINDER_HEADER",
32
+ "REMINDER_FOOTER",
33
+ "REMINDER_LINE_SEPARATOR",
34
+ "ALL_REMINDER_HINTS_BY_MERGEABLE",
35
+ "VERDICT_DONE",
36
+ "VERDICT_NOT_DONE",
37
+ "NO_PULL_REQUEST_REMINDER",
38
+ "RECHECK_COMMAND_TEMPLATE",
39
+ "ADD_LABEL_COMMAND_TEMPLATE",
40
+ ]
41
+
42
+ GIT_PROGRAM_NAME: str = "git"
43
+ GIT_PUSH_SUBCOMMAND: str = "push"
44
+ GH_PROGRAM_NAME: str = "gh"
45
+ GH_PR_SUBCOMMAND: str = "pr"
46
+ GH_PR_CREATE_ACTION: str = "create"
47
+ ALL_GIT_OPTIONS_WITH_VALUE: frozenset[str] = frozenset({"-C", "-c"})
48
+ ALL_POWERSHELL_PROGRAM_NAMES: frozenset[str] = frozenset(
49
+ {"pwsh", "pwsh.exe", "powershell", "powershell.exe"}
50
+ )
51
+ ALL_POWERSHELL_COMMAND_FLAGS: frozenset[str] = frozenset({"-command", "-c"})
52
+
53
+ ALL_GH_PR_VIEW_ARGUMENTS: tuple[str, ...] = (
54
+ "gh",
55
+ "pr",
56
+ "view",
57
+ "--json",
58
+ "number,url,isDraft,mergeable,mergeStateStatus,statusCheckRollup,labels",
59
+ )
60
+ GH_PR_VIEW_TIMEOUT_SECONDS: int = 20
61
+ NO_PULL_REQUEST_MARKER: str = "no pull requests found"
62
+ EXIT_CODE_ERROR_PREFIX: str = "Error: Exit code "
63
+
64
+ DONE_LABEL_NAME: str = "done"
65
+
66
+ MERGEABLE_CLEAN_VALUE: str = "MERGEABLE"
67
+ MERGEABLE_CONFLICTING_VALUE: str = "CONFLICTING"
68
+ MERGEABLE_UNKNOWN_VALUE: str = "UNKNOWN"
69
+
70
+ ALL_FAILING_CHECK_CONCLUSIONS: frozenset[str] = frozenset(
71
+ {"FAILURE", "ERROR", "CANCELLED", "TIMED_OUT", "ACTION_REQUIRED", "STARTUP_FAILURE"}
72
+ )
73
+ ALL_PASSING_CHECK_CONCLUSIONS: frozenset[str] = frozenset({"SUCCESS", "NEUTRAL", "SKIPPED"})
74
+ CHECK_COMPLETED_STATUS: str = "COMPLETED"
75
+ STATUS_CONTEXT_STATE_KEY: str = "state"
76
+
77
+ REMINDER_HEADER: str = "=== PR DONE CHECKLIST (context reminder, never a block) ==="
78
+ REMINDER_FOOTER: str = "A PR is done only when every line above is clean."
79
+ REMINDER_LINE_SEPARATOR: str = "\n"
80
+ ALL_REMINDER_HINTS_BY_MERGEABLE: dict[str, str] = {
81
+ MERGEABLE_CLEAN_VALUE: "no conflicts with the base branch",
82
+ MERGEABLE_CONFLICTING_VALUE: (
83
+ "CONFLICTS with the base branch. Merge origin/main into this branch, "
84
+ "resolve every conflict, run the tests, push again."
85
+ ),
86
+ MERGEABLE_UNKNOWN_VALUE: "GitHub is still computing. Re-run the re-check command in a minute.",
87
+ }
88
+ VERDICT_DONE: str = "DONE. Add the label now:"
89
+ VERDICT_NOT_DONE: str = "NOT DONE. Do not add the done label yet."
90
+ NO_PULL_REQUEST_REMINDER: str = (
91
+ "=== PR DONE CHECKLIST (context reminder, never a block) ===\n"
92
+ "No open pull request found for this branch. Open a draft PR with gh pr create --draft.\n"
93
+ "A branch is done only when its PR has clean CI, no merge conflicts, and the done label."
94
+ )
95
+ RECHECK_COMMAND_TEMPLATE: str = (
96
+ "gh pr view {number} --json mergeable,mergeStateStatus,statusCheckRollup,labels"
97
+ )
98
+ ADD_LABEL_COMMAND_TEMPLATE: str = "gh pr edit {number} --add-label {label}"
@@ -1,8 +1,9 @@
1
1
  """Constants for the PreToolUse dispatcher that hosts Write/Edit/MultiEdit hooks.
2
2
 
3
- Holds the ordered hosted-hook list with per-hook applicable-tool sets, the
4
- special exit codes, the deny decision string, and the hook-event name. The
5
- dispatcher imports each of these by name.
3
+ The roster keeps action-boundary checks, repository checks, and checks without
4
+ a proven local replacement. File-policy rules with a staged replacement run
5
+ through cde lint in native pre-commit. Their detectors stay importable for that
6
+ linter. Bash cleanup protection uses its own roster.
6
7
  """
7
8
 
8
9
  from __future__ import annotations
@@ -55,14 +56,10 @@ ALL_WRITE_EDIT_MULTI_EDIT_APPLY_PATCH_TOOL_NAMES: frozenset[str] = frozenset(
55
56
  ALL_WRITE_EDIT_MULTI_EDIT_TOOL_NAMES | {APPLY_PATCH_TOOL_NAME}
56
57
  )
57
58
 
58
- # apply_patch reaches this narrower roster: the gates whose miss causes immediate
59
- # harm, plus the TDD gate and the edit tracker. It stays off the full lint surface.
60
59
  ALL_IMMEDIATE_HARM_SCRIPT_PATHS: tuple[str, ...] = (
61
60
  "blocking/pii_prevention_blocker.py",
62
61
  "blocking/sensitive_file_protector.py",
63
62
  "blocking/write_existing_file_blocker.py",
64
- "blocking/code_rules_enforcer.py",
65
- "blocking/tdd_enforcer.py",
66
63
  )
67
64
 
68
65
 
@@ -71,19 +68,18 @@ STATE_DESCRIPTION_BLOCKER_MODULE_NAME = "state_description_blocker"
71
68
 
72
69
  @dataclass(frozen=True)
73
70
  class HostedHookEntry:
74
- """A single hosted hook with its applicable-tools constraint and blocking flag.
71
+ """One hosted hook, the tools it applies to, and whether a crash blocks.
75
72
 
76
73
  Attributes:
77
74
  script_relative_path: Hook path relative to the hooks/ directory.
78
75
  applicable_tool_names: Tool names this hook applies to. The dispatcher
79
76
  skips the hook when the payload's tool is not in this set.
80
- is_blocking: True when a crash surfaces a blocking signal; False when the
77
+ is_blocking: True when a crash is a blocking signal. False when the
81
78
  hook is advisory and a crash stays silent.
82
- native_module_name: The importable module name whose evaluate function
83
- the dispatcher calls in-process for this hook, or None when the hook
84
- runs via runpy under __main__. The named module exposes a function
85
- named `evaluate` taking the payload dict and returning a deny-reason
86
- string or None.
79
+ native_module_name: Importable module whose evaluate function the
80
+ dispatcher calls in-process, or None when the hook runs via runpy
81
+ under __main__. evaluate takes the payload dict and returns a
82
+ deny-reason string or None.
87
83
  """
88
84
 
89
85
  script_relative_path: str
@@ -109,39 +105,10 @@ ALL_HOSTED_HOOK_ENTRIES: tuple[HostedHookEntry, ...] = (
109
105
  script_relative_path="validation/hook_format_validator.py",
110
106
  applicable_tool_names=ALL_WRITE_EDIT_MULTI_EDIT_TOOL_NAMES,
111
107
  ),
112
- HostedHookEntry(
113
- script_relative_path="blocking/code_rules_enforcer.py",
114
- applicable_tool_names=ALL_WRITE_EDIT_MULTI_EDIT_APPLY_PATCH_TOOL_NAMES,
115
- ),
116
- HostedHookEntry(
117
- script_relative_path="blocking/tdd_enforcer.py",
118
- applicable_tool_names=ALL_WRITE_EDIT_MULTI_EDIT_APPLY_PATCH_TOOL_NAMES,
119
- ),
120
- HostedHookEntry(
121
- script_relative_path="blocking/windows_rmtree_blocker.py",
122
- applicable_tool_names=ALL_WRITE_EDIT_MULTI_EDIT_TOOL_NAMES,
123
- ),
124
108
  HostedHookEntry(
125
109
  script_relative_path="blocking/duplicate_rmtree_helper_blocker.py",
126
110
  applicable_tool_names=ALL_WRITE_EDIT_MULTI_EDIT_TOOL_NAMES,
127
111
  ),
128
- HostedHookEntry(
129
- script_relative_path="blocking/state_description_blocker.py",
130
- applicable_tool_names=ALL_WRITE_EDIT_MULTI_EDIT_TOOL_NAMES,
131
- native_module_name=STATE_DESCRIPTION_BLOCKER_MODULE_NAME,
132
- ),
133
- HostedHookEntry(
134
- script_relative_path="blocking/subprocess_budget_completeness.py",
135
- applicable_tool_names=ALL_WRITE_EDIT_MULTI_EDIT_TOOL_NAMES,
136
- ),
137
- HostedHookEntry(
138
- script_relative_path="blocking/hook_prose_detector_consistency.py",
139
- applicable_tool_names=ALL_WRITE_EDIT_MULTI_EDIT_TOOL_NAMES,
140
- ),
141
- HostedHookEntry(
142
- script_relative_path="blocking/workflow_substitution_slot_blocker.py",
143
- applicable_tool_names=ALL_WRITE_EDIT_MULTI_EDIT_TOOL_NAMES,
144
- ),
145
112
  HostedHookEntry(
146
113
  script_relative_path="blocking/claude_md_orphan_file_blocker.py",
147
114
  applicable_tool_names=ALL_WRITE_EDIT_MULTI_EDIT_TOOL_NAMES,