claude-dev-env 4.3.0 → 7.1.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 (480) 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 +5 -4
  12. package/.agents/skills/pull-request/SKILL.md +11 -13
  13. package/.agents/skills/pull-request/reference/publication-tasks.md +3 -3
  14. package/.agents/skills/pull-request/scripts/github_pr_command_constants/config/constants.py +9 -1
  15. package/.agents/skills/pull-request/scripts/pull_request.py +35 -44
  16. package/.agents/skills/pull-request/scripts/test_github_pr_command_constants.py +9 -0
  17. package/.agents/skills/pull-request/scripts/test_pull_request.py +35 -3
  18. package/.agents/skills/session-continuity/README.md +189 -0
  19. package/.agents/skills/session-continuity/SKILL.md +114 -0
  20. package/.agents/skills/session-continuity/continuity.mjs +375 -0
  21. package/.agents/skills/session-continuity/continuity.test.mjs +303 -0
  22. package/.agents/skills/skill-builder/SKILL.md +3 -196
  23. package/.agents/skills/syncing-submodules/scripts/test_sync_parent_pointer.py +0 -7
  24. package/.agents/skills/windows-scheduled-task/SKILL.md +153 -0
  25. package/_shared/pr-loop/scripts/pr_loop_shared_constants/terminology_sweep_constants.py +6 -0
  26. package/_shared/pr-loop/scripts/terminology_sweep.py +64 -19
  27. package/_shared/pr-loop/scripts/tests/test_terminology_sweep.py +59 -0
  28. package/bin/cde.mjs +36 -8
  29. package/bin/cde.test.mjs +48 -0
  30. package/bin/ever-shipped-skills.mjs +2 -20
  31. package/bin/ever-shipped-skills.test.mjs +8 -0
  32. package/bin/expand_home_directory_tokens.mjs +4 -5
  33. package/bin/expand_home_directory_tokens.test.mjs +128 -0
  34. package/bin/git_hooks_installer.mjs +22 -3
  35. package/bin/git_hooks_installer.test.mjs +159 -5
  36. package/bin/install-session-continuity.mjs +78 -0
  37. package/bin/install-session-continuity.test.mjs +42 -0
  38. package/bin/install.agents-home.test.mjs +15 -13
  39. package/bin/install.codex-rules.test.mjs +5 -2
  40. package/bin/install.cursor-rules.test.mjs +5 -2
  41. package/bin/install.mjs +506 -63
  42. package/bin/install.policy-lint.test.mjs +130 -0
  43. package/bin/install.profiles.test.mjs +10 -0
  44. package/bin/install.prune.test.mjs +286 -37
  45. package/bin/install.pstack-plugin.test.mjs +114 -0
  46. package/bin/install.test.mjs +537 -120
  47. package/bin/install.transaction.test.mjs +3 -3
  48. package/bin/refresh-pstack-plugin-skills.test.mjs +211 -0
  49. package/docs/CODE_RULES.md +1 -1
  50. package/hooks/advisory/pr_done_reminder.py +342 -0
  51. package/hooks/advisory/test_pr_done_reminder.py +249 -0
  52. package/hooks/blocking/bash_post_call_dispatcher.py +53 -6
  53. package/hooks/blocking/code_rules_banned_identifiers.py +3 -0
  54. package/hooks/blocking/code_rules_paired_test.py +22 -15
  55. package/hooks/blocking/precommit_code_rules_gate.py +5 -8
  56. package/hooks/blocking/test_bash_dispatcher_interpreter_starts.py +7 -52
  57. package/hooks/blocking/test_bash_post_call_dispatcher.py +65 -4
  58. package/hooks/blocking/test_bash_pre_tool_use_dispatcher.py +0 -69
  59. package/hooks/blocking/test_code_rules_banned_identifiers.py +64 -0
  60. package/hooks/blocking/test_code_rules_enforcer_paired_test.py +36 -29
  61. package/hooks/blocking/test_code_rules_js_resume_task_enumeration.py +4 -4
  62. package/hooks/blocking/test_code_rules_js_returns_object_schemaless.py +5 -5
  63. package/hooks/blocking/test_pre_tool_use_dispatcher.py +43 -342
  64. package/hooks/blocking/test_pre_tool_use_dispatcher_native.py +20 -51
  65. package/hooks/blocking/test_shared_stdin_adoption.py +1 -47
  66. package/hooks/git-hooks/git_hooks_constants/staged_policy_lint.py +12 -0
  67. package/hooks/git-hooks/git_hooks_constants/verification_notice_constants.py +116 -0
  68. package/hooks/git-hooks/post_commit.py +33 -0
  69. package/hooks/git-hooks/pre_commit.py +18 -49
  70. package/hooks/git-hooks/pre_push.py +45 -541
  71. package/hooks/git-hooks/test_installed_policy_lint.py +208 -0
  72. package/hooks/git-hooks/test_native_hook_support.py +129 -0
  73. package/hooks/git-hooks/test_native_policy_commit.py +120 -0
  74. package/hooks/git-hooks/test_post_commit.py +43 -0
  75. package/hooks/git-hooks/test_pre_commit.py +38 -148
  76. package/hooks/git-hooks/test_pre_push.py +48 -1631
  77. package/hooks/git-hooks/test_verification_notice.py +60 -0
  78. package/hooks/git-hooks/test_verification_start.py +173 -0
  79. package/hooks/git-hooks/verification_notice.py +192 -0
  80. package/hooks/git-hooks/verification_notice_context.py +253 -0
  81. package/hooks/git-hooks/verification_notice_state.py +237 -0
  82. package/hooks/git-hooks/verification_start.py +100 -0
  83. package/hooks/hooks.json +1 -120
  84. package/hooks/hooks_constants/banned_identifiers_constants.py +4 -0
  85. package/hooks/hooks_constants/bash_post_call_dispatcher_constants.py +14 -1
  86. package/hooks/hooks_constants/bash_pre_tool_use_dispatcher_constants.py +1 -15
  87. package/hooks/hooks_constants/post_tool_use_dispatcher_constants.py +0 -4
  88. package/hooks/hooks_constants/pr_done_reminder_constants.py +98 -0
  89. package/hooks/hooks_constants/pre_tool_use_dispatcher_constants.py +10 -93
  90. package/hooks/hooks_constants/stop_dispatcher_constants.py +1 -4
  91. package/hooks/hooks_constants/test_bash_post_call_dispatcher_constants.py +19 -2
  92. package/hooks/hooks_constants/test_bash_pre_tool_use_dispatcher_constants.py +3 -66
  93. package/hooks/hooks_constants/test_pr_done_reminder_constants.py +40 -0
  94. package/hooks/hooks_constants/test_pre_tool_use_dispatcher_constants.py +46 -201
  95. package/hooks/hooks_constants/test_stop_dispatcher_constants.py +3 -25
  96. package/hooks/validation/test_post_tool_use_dispatcher.py +35 -298
  97. package/hooks/validators/run_all_validators.py +5 -1
  98. package/hooks/validators/security_checks.py +57 -2
  99. package/hooks/validators/test_hook_timing_harness.py +2 -5
  100. package/hooks/validators/test_run_all_validators_mutation_tool_parity.py +3 -11
  101. package/hooks/validators/test_run_all_validators_policy_lint.py +36 -0
  102. package/hooks/validators/test_security_checks.py +57 -0
  103. package/package.json +2 -2
  104. package/rules/confirm-implementation-forks.md +2 -0
  105. package/rules/durable-post-artifacts.md +2 -1
  106. package/rules/git-workflow.md +18 -6
  107. package/rules/pstack-host-mapping.md +48 -0
  108. package/rules/vault-context.md +3 -5
  109. package/rules/verify-runtime-state.md +7 -0
  110. package/scripts/audit-hooks-cli.mjs +5 -0
  111. package/scripts/audit-hooks.mjs +72 -16
  112. package/scripts/automatic_advisory/__init__.py +1 -0
  113. package/scripts/automatic_advisory/checkout.py +51 -0
  114. package/scripts/automatic_advisory/cli.py +334 -0
  115. package/scripts/automatic_advisory/config/__init__.py +1 -0
  116. package/scripts/automatic_advisory/config/constants.py +93 -0
  117. package/scripts/automatic_advisory/config/timing.py +4 -0
  118. package/scripts/automatic_advisory/configuration.py +197 -0
  119. package/scripts/automatic_advisory/execution.py +350 -0
  120. package/scripts/automatic_advisory/git.py +69 -0
  121. package/scripts/automatic_advisory/model.py +107 -0
  122. package/scripts/automatic_advisory/process_host.py +32 -0
  123. package/scripts/automatic_advisory/publisher.py +84 -0
  124. package/scripts/automatic_advisory/runner.py +399 -0
  125. package/scripts/automatic_advisory/state.py +116 -0
  126. package/scripts/automatic_advisory/window_flags.py +41 -0
  127. package/scripts/automatic_advisory/windows_job.py +122 -0
  128. package/scripts/check.ps1 +0 -1
  129. package/{.agents/skills/run-claude-dev-env/driver.mjs → scripts/ci/installer-lifecycle.mjs} +3 -28
  130. package/scripts/ci/installer-lifecycle.test.mjs +26 -0
  131. package/scripts/ci/windows-installer-lifecycle.ps1 +1 -11
  132. package/scripts/codex_compat_materializer.py +99 -13
  133. package/scripts/dev_env_scripts_constants/shared_tree_constants.py +4 -5
  134. package/{.agents/skills/_shared/pr-loop/scripts → scripts}/durable_post_lint.py +35 -43
  135. package/{.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/durable_post_lint_constants.py → scripts/durable_post_lint_config/config/constants.py} +10 -10
  136. package/{.agents/skills/_shared/pr-loop/scripts/test_durable_post_lint_constants.py → scripts/durable_post_lint_config/config/test_constants.py} +14 -1
  137. package/scripts/local_report_cli.py +184 -0
  138. package/scripts/local_report_core.py +247 -0
  139. package/scripts/local_report_publisher.py +12 -0
  140. package/scripts/local_report_validation.py +357 -0
  141. package/scripts/local_verification/__init__.py +23 -0
  142. package/scripts/local_verification/check_runner.py +364 -0
  143. package/scripts/local_verification/check_support.py +99 -0
  144. package/scripts/local_verification/cli.py +158 -0
  145. package/scripts/local_verification/command_runner.py +84 -0
  146. package/scripts/local_verification/config/__init__.py +1 -0
  147. package/scripts/local_verification/config/constants.py +89 -0
  148. package/scripts/local_verification/config/timing.py +1 -0
  149. package/scripts/local_verification/git_state.py +146 -0
  150. package/scripts/local_verification/manifest.py +224 -0
  151. package/scripts/local_verification/model.py +174 -0
  152. package/scripts/local_verification/runner.py +234 -0
  153. package/scripts/policy_lint/adapter_detectors.py +13 -6
  154. package/scripts/policy_lint/adapter_pairing.py +58 -3
  155. package/scripts/policy_lint/adapters.py +7 -4
  156. package/scripts/policy_lint/config/approved_test_pairs.py +323 -0
  157. package/scripts/policy_lint/config/constants.py +5 -0
  158. package/scripts/policy_lint/engine.py +48 -4
  159. package/scripts/policy_lint/model.py +1 -0
  160. package/scripts/policy_lint/registry.py +1 -1
  161. package/scripts/policy_lint/selection.py +2 -1
  162. package/scripts/policy_lint/selection_git.py +2 -0
  163. package/scripts/pr_verification/__init__.py +1 -0
  164. package/scripts/pr_verification/branch_refs.py +114 -0
  165. package/scripts/pr_verification/config/__init__.py +1 -0
  166. package/scripts/pr_verification/config/constants.py +84 -0
  167. package/scripts/pr_verification/config/timing.py +5 -0
  168. package/scripts/pr_verification/github.py +137 -0
  169. package/scripts/pr_verification/github_api.py +376 -0
  170. package/scripts/pr_verification/github_labels.py +88 -0
  171. package/scripts/pr_verification/github_parsing.py +182 -0
  172. package/scripts/pr_verification/github_transport.py +91 -0
  173. package/scripts/pr_verification/lock.py +122 -0
  174. package/scripts/pr_verification/model.py +43 -0
  175. package/scripts/pr_verification/requirements.txt +1 -0
  176. package/scripts/refresh_pstack_plugin_skills.mjs +200 -0
  177. package/scripts/shared_tree_paths.py +32 -3
  178. package/{.agents/skills/_shared/pr-loop/scripts → scripts}/test_durable_post_lint.py +97 -0
  179. package/scripts/test_shared_tree_paths.py +33 -0
  180. package/scripts/tests/test-audit-hooks-cli.mjs +150 -0
  181. package/scripts/tests/test-audit-hooks.mjs +94 -2
  182. package/scripts/tests/test_automatic_advisory.py +376 -0
  183. package/scripts/tests/test_automatic_advisory_job_cleanup.py +71 -0
  184. package/scripts/tests/test_automatic_advisory_polling.py +216 -0
  185. package/scripts/tests/test_automatic_advisory_recovery.py +320 -0
  186. package/scripts/tests/test_automatic_advisory_repairs.py +400 -0
  187. package/scripts/tests/test_automatic_advisory_settings.py +48 -0
  188. package/scripts/tests/test_automatic_advisory_window_flags.py +163 -0
  189. package/scripts/tests/test_closed_pr_label.py +157 -0
  190. package/scripts/tests/test_codex_compat_materializer.py +189 -6
  191. package/scripts/tests/test_github_labels.py +101 -0
  192. package/scripts/tests/test_github_transport.py +125 -0
  193. package/scripts/tests/test_local_report_publisher.py +396 -0
  194. package/scripts/tests/test_local_report_publisher_cli.py +85 -0
  195. package/scripts/tests/test_local_verification.py +348 -0
  196. package/scripts/tests/test_local_verification_cli.py +98 -0
  197. package/scripts/tests/test_policy_lint_rules_archive.py +120 -0
  198. package/scripts/tests/test_policy_lint_rules_engine.py +25 -4
  199. package/scripts/tests/test_policy_lint_rules_installed_loader.py +29 -0
  200. package/scripts/tests/test_policy_lint_rules_pairing.py +163 -0
  201. package/scripts/tests/test_policy_lint_rules_registry.py +227 -13
  202. package/scripts/tests/test_policy_lint_selection.py +25 -2
  203. package/scripts/tests/test_policy_lint_selection_native_index.py +30 -0
  204. package/scripts/tests/test_pr_verification_github.py +392 -0
  205. package/scripts/tests/test_pr_verification_lock.py +168 -0
  206. package/scripts/tests/test_rules.py +3 -7
  207. package/scripts/tests/test_verification_notice.py +347 -0
  208. package/.agents/skills/_shared/pr-loop/.claude/CLAUDE.md +0 -1
  209. package/.agents/skills/_shared/pr-loop/audit-contract.md +0 -5
  210. package/.agents/skills/_shared/pr-loop/audit-reply-template.md +0 -5
  211. package/.agents/skills/_shared/pr-loop/code-rules-gate.md +0 -5
  212. package/.agents/skills/_shared/pr-loop/fix-protocol.md +0 -5
  213. package/.agents/skills/_shared/pr-loop/gh-payloads.md +0 -5
  214. package/.agents/skills/_shared/pr-loop/portable-driver.md +0 -149
  215. package/.agents/skills/_shared/pr-loop/post-audit-thread-contract.md +0 -5
  216. package/.agents/skills/_shared/pr-loop/precatch-rubric.md +0 -5
  217. package/.agents/skills/_shared/pr-loop/preflight-proposal.contract.test.mjs +0 -119
  218. package/.agents/skills/_shared/pr-loop/preflight-proposal.md +0 -5
  219. package/.agents/skills/_shared/pr-loop/prompts/.claude/CLAUDE.md +0 -1
  220. package/.agents/skills/_shared/pr-loop/prompts/AGENTS.md +0 -1
  221. package/.agents/skills/_shared/pr-loop/prompts/pr-consistency-audit.xml +0 -324
  222. package/.agents/skills/_shared/pr-loop/scripts/.claude/CLAUDE.md +0 -1
  223. package/.agents/skills/_shared/pr-loop/scripts/AGENTS.md +0 -1
  224. package/.agents/skills/_shared/pr-loop/scripts/RUNTIME_SCRIPTS.md +0 -29
  225. package/.agents/skills/_shared/pr-loop/scripts/_cli_utils.py +0 -22
  226. package/.agents/skills/_shared/pr-loop/scripts/_path_resolver.py +0 -186
  227. package/.agents/skills/_shared/pr-loop/scripts/_xml_utils.py +0 -20
  228. package/.agents/skills/_shared/pr-loop/scripts/audit_category_schema.py +0 -355
  229. package/.agents/skills/_shared/pr-loop/scripts/build_audit_prompt.py +0 -289
  230. package/.agents/skills/_shared/pr-loop/scripts/build_converge_task_list.py +0 -310
  231. package/.agents/skills/_shared/pr-loop/scripts/build_fix_prompt.py +0 -292
  232. package/.agents/skills/_shared/pr-loop/scripts/init_loop_state.py +0 -134
  233. package/.agents/skills/_shared/pr-loop/scripts/portable_converge_driver.py +0 -1646
  234. package/.agents/skills/_shared/pr-loop/scripts/preflight_worktree.py +0 -392
  235. package/.agents/skills/_shared/pr-loop/scripts/select_converge_pacer.py +0 -215
  236. package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/.claude/CLAUDE.md +0 -1
  237. package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/AGENTS.md +0 -1
  238. package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/__init__.py +0 -0
  239. package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/audit_category_schema_constants.py +0 -37
  240. package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/converge_task_list_constants.py +0 -56
  241. package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/handoff_constants.py +0 -45
  242. package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/pacer_constants.py +0 -47
  243. package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/path_resolver_constants.py +0 -157
  244. package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/portable_driver_constants.py +0 -177
  245. package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/preflight_constants.py +0 -70
  246. package/.agents/skills/_shared/pr-loop/scripts/teardown_worktrees.py +0 -172
  247. package/.agents/skills/_shared/pr-loop/scripts/test__path_resolver.py +0 -106
  248. package/.agents/skills/_shared/pr-loop/scripts/test_audit_category_schema.py +0 -94
  249. package/.agents/skills/_shared/pr-loop/scripts/test_build_audit_prompt.py +0 -499
  250. package/.agents/skills/_shared/pr-loop/scripts/test_build_converge_task_list.py +0 -140
  251. package/.agents/skills/_shared/pr-loop/scripts/test_build_fix_prompt.py +0 -262
  252. package/.agents/skills/_shared/pr-loop/scripts/test_init_loop_state.py +0 -71
  253. package/.agents/skills/_shared/pr-loop/scripts/test_portable_converge_driver.py +0 -1119
  254. package/.agents/skills/_shared/pr-loop/scripts/test_preflight_worktree.py +0 -287
  255. package/.agents/skills/_shared/pr-loop/scripts/test_select_converge_pacer.py +0 -207
  256. package/.agents/skills/_shared/pr-loop/scripts/test_teardown_worktrees.py +0 -59
  257. package/.agents/skills/_shared/pr-loop/scripts/test_write_handoff.py +0 -201
  258. package/.agents/skills/_shared/pr-loop/scripts/write_audit_outcomes.py +0 -182
  259. package/.agents/skills/_shared/pr-loop/scripts/write_fix_outcomes.py +0 -206
  260. package/.agents/skills/_shared/pr-loop/scripts/write_handoff.py +0 -309
  261. package/.agents/skills/_shared/pr-loop/state-schema.md +0 -5
  262. package/.agents/skills/_shared/pr-loop/worker-spawn.md +0 -5
  263. package/.agents/skills/autoconverge/.claude/CLAUDE.md +0 -1
  264. package/.agents/skills/autoconverge/AGENTS.md +0 -1
  265. package/.agents/skills/autoconverge/SKILL.md +0 -431
  266. package/.agents/skills/autoconverge/reference/.claude/CLAUDE.md +0 -1
  267. package/.agents/skills/autoconverge/reference/AGENTS.md +0 -1
  268. package/.agents/skills/autoconverge/reference/closing-report.md +0 -93
  269. package/.agents/skills/autoconverge/reference/convergence-gates.md +0 -31
  270. package/.agents/skills/autoconverge/reference/convergence.md +0 -219
  271. package/.agents/skills/autoconverge/reference/copilot-findings.md +0 -51
  272. package/.agents/skills/autoconverge/reference/gotchas.md +0 -66
  273. package/.agents/skills/autoconverge/reference/headless-safety.md +0 -44
  274. package/.agents/skills/autoconverge/reference/multi-pr.md +0 -128
  275. package/.agents/skills/autoconverge/reference/self-closing-loop.md +0 -84
  276. package/.agents/skills/autoconverge/reference/stop-conditions.md +0 -127
  277. package/.agents/skills/autoconverge/test_portable_pacer_gate.py +0 -54
  278. package/.agents/skills/autoconverge/workflow/.claude/CLAUDE.md +0 -1
  279. package/.agents/skills/autoconverge/workflow/AGENTS.md +0 -1
  280. package/.agents/skills/autoconverge/workflow/aggregate_runs.py +0 -371
  281. package/.agents/skills/autoconverge/workflow/autoconverge_report_constants/.claude/CLAUDE.md +0 -1
  282. package/.agents/skills/autoconverge/workflow/autoconverge_report_constants/AGENTS.md +0 -1
  283. package/.agents/skills/autoconverge/workflow/autoconverge_report_constants/__init__.py +0 -0
  284. package/.agents/skills/autoconverge/workflow/autoconverge_report_constants/render_report_constants.py +0 -250
  285. package/.agents/skills/autoconverge/workflow/converge.clean-audit.test.mjs +0 -665
  286. package/.agents/skills/autoconverge/workflow/converge.codex-gate.test.mjs +0 -472
  287. package/.agents/skills/autoconverge/workflow/converge.contract.test.mjs +0 -64
  288. package/.agents/skills/autoconverge/workflow/converge.copilot-gate.test.mjs +0 -1009
  289. package/.agents/skills/autoconverge/workflow/converge.fix-progress.test.mjs +0 -107
  290. package/.agents/skills/autoconverge/workflow/converge.fix-recovery.test.mjs +0 -33
  291. package/.agents/skills/autoconverge/workflow/converge.merge-conflict.test.mjs +0 -15
  292. package/.agents/skills/autoconverge/workflow/converge.mjs +0 -3132
  293. package/.agents/skills/autoconverge/workflow/converge.p2-advance.test.mjs +0 -202
  294. package/.agents/skills/autoconverge/workflow/converge.path-aware.test.mjs +0 -47
  295. package/.agents/skills/autoconverge/workflow/converge.precatch.test.mjs +0 -152
  296. package/.agents/skills/autoconverge/workflow/converge.run-input.test.mjs +0 -116
  297. package/.agents/skills/autoconverge/workflow/converge_multi.mjs +0 -169
  298. package/.agents/skills/autoconverge/workflow/converge_multi.run-input.test.mjs +0 -173
  299. package/.agents/skills/autoconverge/workflow/convergence_summary.py +0 -110
  300. package/.agents/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a11d903476b803493.jsonl +0 -2
  301. package/.agents/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a26213978adeef6fb.jsonl +0 -2
  302. package/.agents/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a3def0d15ed9d9110.jsonl +0 -2
  303. package/.agents/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a41f41b1b708ee3b7.jsonl +0 -2
  304. package/.agents/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a758b880abecc3ff7.jsonl +0 -2
  305. package/.agents/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a8897b89656b1bd16.jsonl +0 -2
  306. package/.agents/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-ab1c2d3e4f5a6b7c8.jsonl +0 -2
  307. package/.agents/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-abd463d744a1437bc.jsonl +0 -2
  308. package/.agents/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-ad19d027ae8ee1816.jsonl +0 -2
  309. package/.agents/skills/autoconverge/workflow/fixtures/wf_run/workflows/wf_881252e6-700.json +0 -266
  310. package/.agents/skills/autoconverge/workflow/render_report.py +0 -1024
  311. package/.agents/skills/autoconverge/workflow/test_aggregate_runs.py +0 -134
  312. package/.agents/skills/autoconverge/workflow/test_convergence_summary.py +0 -149
  313. package/.agents/skills/autoconverge/workflow/test_render_report.py +0 -812
  314. package/.agents/skills/hitl/SKILL.md +0 -45
  315. package/.agents/skills/pr-cleanup/SKILL.md +0 -140
  316. package/.agents/skills/pr-cleanup/reference/process-inventory.md +0 -17
  317. package/.agents/skills/pr-cleanup/reference/task-seeds.md +0 -22
  318. package/.agents/skills/pr-name-by-capability/SKILL.md +0 -73
  319. package/.agents/skills/pr-name-by-capability/reference/fetch-commands.md +0 -29
  320. package/.agents/skills/pr-name-by-capability/reference/offense-examples.md +0 -32
  321. package/.agents/skills/pr-name-by-capability/reference/report-template.md +0 -29
  322. package/.agents/skills/pr-name-by-capability/reference/rule-checklist.md +0 -38
  323. package/.agents/skills/pr-name-by-capability/reference/task-seeds.md +0 -10
  324. package/.agents/skills/pr-plain-language-cleanup/SKILL.md +0 -93
  325. package/.agents/skills/pr-refinement/SKILL.md +0 -31
  326. package/.agents/skills/pr-shared-extraction/SKILL.md +0 -177
  327. package/.agents/skills/pr-shared-extraction/reference/examples.md +0 -46
  328. package/.agents/skills/pr-shared-extraction/reference/offense-taxonomy.md +0 -100
  329. package/.agents/skills/pr-small-cl/SKILL.md +0 -52
  330. package/.agents/skills/pr-title-description/SKILL.md +0 -96
  331. package/.agents/skills/prototype/SKILL.md +0 -85
  332. package/.agents/skills/prototype/reference/honest-limitations.md +0 -23
  333. package/.agents/skills/prototype/reference/promotion-tasks.md +0 -23
  334. package/.agents/skills/prototype/scripts/build_sandbox_settings.py +0 -249
  335. package/.agents/skills/prototype/scripts/conftest.py +0 -15
  336. package/.agents/skills/prototype/scripts/launch_sandbox.py +0 -205
  337. package/.agents/skills/prototype/scripts/probe_sandbox_safety.py +0 -311
  338. package/.agents/skills/prototype/scripts/prototype_scripts_constants/__init__.py +0 -1
  339. package/.agents/skills/prototype/scripts/prototype_scripts_constants/config/__init__.py +0 -0
  340. package/.agents/skills/prototype/scripts/prototype_scripts_constants/config/build_sandbox_settings_constants.py +0 -41
  341. package/.agents/skills/prototype/scripts/prototype_scripts_constants/config/launch_sandbox_constants.py +0 -23
  342. package/.agents/skills/prototype/scripts/prototype_scripts_constants/config/probe_sandbox_safety_constants.py +0 -45
  343. package/.agents/skills/prototype/scripts/prototype_scripts_constants/config/prototype_common_constants.py +0 -10
  344. package/.agents/skills/prototype/scripts/test_build_sandbox_settings.py +0 -275
  345. package/.agents/skills/prototype/scripts/test_launch_sandbox.py +0 -303
  346. package/.agents/skills/prototype/scripts/test_probe_sandbox_safety.py +0 -312
  347. package/.agents/skills/prototype/workflows/promotion.md +0 -25
  348. package/.agents/skills/prototype/workflows/sandbox.md +0 -35
  349. package/.agents/skills/rebase/.claude/CLAUDE.md +0 -1
  350. package/.agents/skills/rebase/AGENTS.md +0 -1
  351. package/.agents/skills/rebase/SKILL.md +0 -178
  352. package/.agents/skills/review-router/SKILL.md +0 -51
  353. package/.agents/skills/review-router/reference/route-policy.json +0 -7
  354. package/.agents/skills/review-router/reference/task-seeds.md +0 -1
  355. package/.agents/skills/review-router/scripts/conftest.py +0 -4
  356. package/.agents/skills/review-router/scripts/review_router.py +0 -50
  357. package/.agents/skills/review-router/scripts/review_router_cli.py +0 -211
  358. package/.agents/skills/review-router/scripts/review_router_constants/__init__.py +0 -1
  359. package/.agents/skills/review-router/scripts/review_router_constants/config/__init__.py +0 -0
  360. package/.agents/skills/review-router/scripts/review_router_constants/config/constants.py +0 -13
  361. package/.agents/skills/review-router/scripts/test_review_router.py +0 -23
  362. package/.agents/skills/review-router/scripts/test_review_router_cli.py +0 -47
  363. package/.agents/skills/review-tier/SKILL.md +0 -56
  364. package/.agents/skills/review-tier/reference/task-seeds.md +0 -1
  365. package/.agents/skills/review-tier/reference/tier-policy.json +0 -9
  366. package/.agents/skills/review-tier/scripts/conftest.py +0 -4
  367. package/.agents/skills/review-tier/scripts/review_tier.py +0 -359
  368. package/.agents/skills/review-tier/scripts/review_tier_constants/__init__.py +0 -1
  369. package/.agents/skills/review-tier/scripts/review_tier_constants/config/__init__.py +0 -0
  370. package/.agents/skills/review-tier/scripts/review_tier_constants/config/constants.py +0 -29
  371. package/.agents/skills/review-tier/scripts/test_generation.py +0 -159
  372. package/.agents/skills/review-tier/scripts/test_review_tier.py +0 -33
  373. package/.agents/skills/run-claude-dev-env/SKILL.md +0 -84
  374. package/.agents/skills/session-log/.claude/CLAUDE.md +0 -1
  375. package/.agents/skills/session-log/AGENTS.md +0 -1
  376. package/.agents/skills/session-log/SKILL.md +0 -170
  377. package/.agents/skills/session-log/templates/frontmatter.md +0 -40
  378. package/.agents/skills/session-tidy/.claude/CLAUDE.md +0 -1
  379. package/.agents/skills/session-tidy/AGENTS.md +0 -1
  380. package/.agents/skills/session-tidy/SKILL.md +0 -191
  381. package/.agents/skills/skill-builder/references/.claude/CLAUDE.md +0 -1
  382. package/.agents/skills/skill-builder/references/AGENTS.md +0 -1
  383. package/.agents/skills/skill-builder/references/delegation-map.md +0 -130
  384. package/.agents/skills/skill-builder/references/description-field.md +0 -111
  385. package/.agents/skills/skill-builder/references/deterministic-elements.md +0 -218
  386. package/.agents/skills/skill-builder/references/progressive-disclosure.md +0 -122
  387. package/.agents/skills/skill-builder/references/self-audit-checklist.md +0 -126
  388. package/.agents/skills/skill-builder/references/skill-modularity.md +0 -111
  389. package/.agents/skills/skill-builder/references/skill-types.md +0 -232
  390. package/.agents/skills/skill-builder/references/thariq-x-post-skills.json +0 -33
  391. package/.agents/skills/skill-builder/templates/.claude/CLAUDE.md +0 -1
  392. package/.agents/skills/skill-builder/templates/AGENTS.md +0 -1
  393. package/.agents/skills/skill-builder/templates/gap-analysis.md +0 -87
  394. package/.agents/skills/skill-builder/workflows/.claude/CLAUDE.md +0 -1
  395. package/.agents/skills/skill-builder/workflows/AGENTS.md +0 -1
  396. package/.agents/skills/skill-builder/workflows/improve-skill.md +0 -136
  397. package/.agents/skills/skill-builder/workflows/new-skill.md +0 -179
  398. package/.agents/skills/skill-builder/workflows/polish-skill.md +0 -139
  399. package/.agents/skills/source-command-sr-loop/SKILL.md +0 -82
  400. package/.agents/skills/update/.claude/CLAUDE.md +0 -1
  401. package/.agents/skills/update/AGENTS.md +0 -1
  402. package/.agents/skills/update/SKILL.md +0 -190
  403. package/_shared/pr-loop/AGENTS.md +0 -1
  404. package/_shared/pr-loop/audit-contract.md +0 -183
  405. package/_shared/pr-loop/audit-reply-template.md +0 -151
  406. package/_shared/pr-loop/code-rules-gate.md +0 -65
  407. package/_shared/pr-loop/fix-protocol.md +0 -60
  408. package/_shared/pr-loop/gh-payloads.md +0 -75
  409. package/_shared/pr-loop/post-audit-thread-contract.md +0 -51
  410. package/_shared/pr-loop/precatch-rubric.md +0 -66
  411. package/_shared/pr-loop/preflight-proposal.md +0 -56
  412. package/_shared/pr-loop/scripts/post_audit_thread.py +0 -1242
  413. package/_shared/pr-loop/scripts/pr_loop_shared_constants/post_audit_thread_constants.py +0 -199
  414. package/_shared/pr-loop/scripts/tests/test_post_audit_thread.py +0 -1115
  415. package/_shared/pr-loop/scripts/tests/test_post_audit_thread_constants.py +0 -129
  416. package/_shared/pr-loop/state-schema.md +0 -45
  417. package/_shared/pr-loop/worker-spawn.md +0 -189
  418. package/hooks/blocking/ask_user_question_shape_blocker.py +0 -83
  419. package/hooks/blocking/bot_mention_comment_blocker.py +0 -76
  420. package/hooks/blocking/claude_md_orphan_file_blocker.py +0 -129
  421. package/hooks/blocking/cursor_cli_python_misfire_blocker.py +0 -108
  422. package/hooks/blocking/destructive_command_blocker.py +0 -2073
  423. package/hooks/blocking/fable_spawn_gate.py +0 -187
  424. package/hooks/blocking/luna_fast_mode_gate.py +0 -160
  425. package/hooks/blocking/nas_ssh_binary_enforcer.py +0 -163
  426. package/hooks/blocking/orchestrator_refresh_reschedule_gate.py +0 -260
  427. package/hooks/blocking/package_inventory_stale_blocker.py +0 -107
  428. package/hooks/blocking/pii_prevention_blocker.py +0 -365
  429. package/hooks/blocking/piped_pytest_blocker.py +0 -1223
  430. package/hooks/blocking/question_to_user_enforcer.py +0 -130
  431. package/hooks/blocking/send_user_file_open_locally_blocker.py +0 -71
  432. package/hooks/blocking/sensitive_file_protector.py +0 -167
  433. package/hooks/blocking/session_edit_stage_gate.py +0 -684
  434. package/hooks/blocking/session_handoff_blocker.py +0 -182
  435. package/hooks/blocking/shell_substitution_blocker.py +0 -350
  436. package/hooks/blocking/test_ask_user_question_shape.py +0 -69
  437. package/hooks/blocking/test_bot_mention_comment_blocker.py +0 -131
  438. package/hooks/blocking/test_claude_md_orphan_file_blocker.py +0 -1277
  439. package/hooks/blocking/test_cursor_cli_python_misfire_blocker.py +0 -208
  440. package/hooks/blocking/test_destructive_command_blocker.py +0 -2024
  441. package/hooks/blocking/test_destructive_command_blocker_deny_mode.py +0 -105
  442. package/hooks/blocking/test_destructive_command_blocker_no_verify.py +0 -122
  443. package/hooks/blocking/test_destructive_command_blocker_patterns.py +0 -133
  444. package/hooks/blocking/test_fable_spawn_gate.py +0 -381
  445. package/hooks/blocking/test_inventory_deadlock_resolution.py +0 -154
  446. package/hooks/blocking/test_luna_fast_mode_gate.py +0 -211
  447. package/hooks/blocking/test_nas_ssh_binary_enforcer.py +0 -225
  448. package/hooks/blocking/test_orchestrator_refresh_reschedule_gate.py +0 -231
  449. package/hooks/blocking/test_package_inventory_stale_blocker.py +0 -382
  450. package/hooks/blocking/test_pii_prevention_blocker.py +0 -1222
  451. package/hooks/blocking/test_pii_prevention_windows_git_path.py +0 -41
  452. package/hooks/blocking/test_pii_write_surface_ephemeral.py +0 -221
  453. package/hooks/blocking/test_piped_pytest_blocker.py +0 -587
  454. package/hooks/blocking/test_precommit_code_rules_gate_native_owner.py +0 -233
  455. package/hooks/blocking/test_question_to_user_enforcer.py +0 -169
  456. package/hooks/blocking/test_send_user_file_open_locally_blocker.py +0 -118
  457. package/hooks/blocking/test_sensitive_file_protector.py +0 -365
  458. package/hooks/blocking/test_session_edit_stage_gate.py +0 -537
  459. package/hooks/blocking/test_session_edit_stage_gate_staging.py +0 -64
  460. package/hooks/blocking/test_session_edit_stage_gate_support.py +0 -204
  461. package/hooks/blocking/test_session_edit_stage_gate_tracker.py +0 -116
  462. package/hooks/blocking/test_session_handoff_blocker.py +0 -318
  463. package/hooks/blocking/test_shell_substitution_blocker.py +0 -298
  464. package/hooks/blocking/test_unscoped_search_blocker.py +0 -102
  465. package/hooks/blocking/test_write_existing_file_blocker.py +0 -122
  466. package/hooks/blocking/tests/test_pii_prevention_blocker.py +0 -259
  467. package/hooks/blocking/unscoped_search_blocker.py +0 -391
  468. package/hooks/blocking/write_existing_file_blocker.py +0 -124
  469. package/hooks/hooks_constants/bot_mention_comment_blocker_constants.py +0 -19
  470. package/hooks/hooks_constants/cursor_cli_python_misfire_blocker_constants.py +0 -79
  471. package/hooks/hooks_constants/fable_spawn_gate_constants.py +0 -61
  472. package/hooks/hooks_constants/luna_fast_mode_gate_constants.py +0 -45
  473. package/hooks/hooks_constants/nas_ssh_binary_enforcer_constants.py +0 -20
  474. package/hooks/hooks_constants/orchestrator_refresh_reschedule_gate_constants.py +0 -57
  475. package/hooks/hooks_constants/send_user_file_open_locally_blocker_constants.py +0 -17
  476. package/hooks/hooks_constants/sensitive_file_protector_constants.py +0 -40
  477. package/hooks/hooks_constants/session_handoff_blocker_constants.py +0 -10
  478. package/hooks/hooks_constants/shell_substitution_blocker_constants.py +0 -80
  479. /package/.agents/skills/{_shared/pr-loop → session-continuity}/AGENTS.md +0 -0
  480. /package/{_shared/pr-loop → .agents/skills/session-continuity}/CLAUDE.md +0 -0
@@ -1,14 +1,8 @@
1
1
  """Golden differential and failure-mode tests for the PreToolUse dispatcher.
2
2
 
3
- Each golden differential test runs a payload through every applicable hosted
4
- hook as its own subprocess (the production path), records each hook's
5
- allow-or-deny and messages, computes the expected aggregate, then runs the
6
- dispatcher on the same payload and asserts equal decision and equal message
7
- union.
8
-
9
- The failure-mode tests cover one row each from spec/failure-modes.md:
10
- early-exit-then-later-deny, multi-deny, context-survival, blocking-hook crash,
11
- fail-open malformed input.
3
+ The live roster carries only nonblocking edit advisors. These tests keep the
4
+ aggregator contract and prove retired policy registrations fail open while
5
+ explicit standalone checks remain callable.
12
6
  """
13
7
 
14
8
  from __future__ import annotations
@@ -31,7 +25,6 @@ if str(_HOOKS_ROOT) not in sys.path:
31
25
 
32
26
  from hooks_constants.pre_tool_use_dispatcher_constants import ( # noqa: E402, I001
33
27
  ALL_HOSTED_HOOK_ENTRIES,
34
- ALL_IMMEDIATE_HARM_SCRIPT_PATHS,
35
28
  APPLY_PATCH_TOOL_NAME,
36
29
  BLOCKING_CRASH_DENY_REASON,
37
30
  BLOCKING_CRASH_EXIT_CODE,
@@ -407,67 +400,6 @@ def test_write_existing_file_blocker_allows_multi_edit_to_an_existing_path(
407
400
  _assert_dispatcher_matches_individual_hooks(payload_text, MULTI_EDIT_TOOL_NAME)
408
401
 
409
402
 
410
- def test_context_survives_alongside_deny_reason(
411
- monkeypatch: pytest.MonkeyPatch, tmp_path: Path
412
- ) -> None:
413
- """A non-denying hook's additional context survives in the dispatcher output.
414
-
415
- This tests that hooks whose output is additional-context (not a deny) still
416
- have their output preserved when another hook denies.
417
- """
418
- monkeypatch.setenv("HOME", str(tmp_path))
419
- monkeypatch.setenv("USERPROFILE", str(tmp_path))
420
- sensitive_path = str(Path.home() / ".env")
421
- payload_text = _write_payload(sensitive_path, "SECRET=abc")
422
- dispatcher_result = _run_dispatcher(payload_text)
423
- is_deny, _reason = _parse_hook_decision(dispatcher_result)
424
- assert is_deny, (
425
- "sensitive_file_protector should deny a write to .env — "
426
- "if it did not, check whether the path is on the sensitive list"
427
- )
428
- assert dispatcher_result.stdout.strip(), "Dispatcher must emit output when denying"
429
-
430
-
431
- def test_all_deny_reasons_present_when_multiple_hooks_deny() -> None:
432
- """When two or more hooks deny, all their reasons appear in the dispatcher output.
433
-
434
- Uses a Write to an existing markdown path with a historical phrase
435
- ("previously") so write_existing_file_blocker and state_description_blocker
436
- both deny.
437
- """
438
- existing_markdown_path = str(Path(__file__).resolve().parent / "CLAUDE.md")
439
- multi_deny_content = (
440
- "# Guide\n\n"
441
- "Previously the system used a different mechanism.\n"
442
- )
443
- payload_text = _write_payload(existing_markdown_path, multi_deny_content)
444
- _assert_dispatcher_matches_individual_hooks(payload_text, WRITE_TOOL_NAME)
445
-
446
- dispatcher_result = _run_dispatcher(payload_text)
447
- dispatcher_is_deny, dispatcher_reason = _parse_hook_decision(dispatcher_result)
448
- assert dispatcher_is_deny, "Dispatcher must deny when any hook denies"
449
-
450
- applicable_entries = _applicable_entries_for_tool(WRITE_TOOL_NAME)
451
- all_expected_deny_reasons: list[str] = []
452
- for each_entry in applicable_entries:
453
- completed_process = _run_hook_subprocess(each_entry.script_relative_path, payload_text)
454
- is_deny, reason_text = _parse_hook_decision(completed_process)
455
- if is_deny and reason_text:
456
- all_expected_deny_reasons.append(reason_text)
457
-
458
- assert len(all_expected_deny_reasons) >= 2, (
459
- f"Test payload must trip at least two hooks — got {len(all_expected_deny_reasons)}. "
460
- "Check that an existing path triggers write_existing_file_blocker and "
461
- "'previously' triggers state_description_blocker on a Write."
462
- )
463
- for each_reason in all_expected_deny_reasons:
464
- assert each_reason in dispatcher_reason, (
465
- f"Missing deny reason in dispatcher output.\n"
466
- f"Expected reason: {each_reason!r}\n"
467
- f"Dispatcher reason: {dispatcher_reason!r}"
468
- )
469
-
470
-
471
403
  def test_aggregate_exit_code_two_signals_deny() -> None:
472
404
  """A HostedHookResult with exit_code 2 and did_crash False signals deny.
473
405
 
@@ -686,87 +618,6 @@ def test_emit_allow_preserves_system_message_and_additional_context(
686
618
  assert parsed["systemMessage"] == "system-a\nsystem-b"
687
619
 
688
620
 
689
- def test_later_hook_deny_survives_early_hook_exit() -> None:
690
- """Dispatcher denies even when an earlier hook exits cleanly before a later hook denies.
691
-
692
- state_description_blocker denies a markdown write with a historical phrase.
693
- Earlier hooks exit 0 (allow). The dispatcher must catch each hook's
694
- SystemExit and continue, so the later denial reaches the aggregator.
695
- """
696
- payload_text = _write_payload(
697
- _MARKDOWN_FILE_PATH,
698
- "# Doc\n\nPreviously this section used a different mechanism.\n",
699
- )
700
- _assert_dispatcher_matches_individual_hooks(payload_text, WRITE_TOOL_NAME)
701
-
702
-
703
- def test_dispatcher_write_applies_both_groups() -> None:
704
- """Write tool triggers both Group A and Group B hooks through the dispatcher.
705
-
706
- Verifies that the set of applicable entries for Write includes entries from
707
- both ALL_WRITE_AND_EDIT_TOOL_NAMES (Group A) and ALL_WRITE_EDIT_MULTI_EDIT_TOOL_NAMES
708
- (Group B) in the constants.
709
- """
710
- all_write_entries = _applicable_entries_for_tool(WRITE_TOOL_NAME)
711
- all_write_script_paths = {each_entry.script_relative_path for each_entry in all_write_entries}
712
- assert "blocking/write_existing_file_blocker.py" in all_write_script_paths, (
713
- "write_existing_file_blocker (Group A) must be in Write applicable set"
714
- )
715
- assert len(all_write_entries) == 18, (
716
- f"Write tool must apply to all 18 hosted hooks, got {len(all_write_entries)}"
717
- )
718
-
719
-
720
- def test_dispatcher_edit_applies_both_groups() -> None:
721
- """Edit triggers Group A, Group B, and the Edit-scoped entry through the
722
- dispatcher.
723
- """
724
- all_edit_entries = _applicable_entries_for_tool(EDIT_TOOL_NAME)
725
- all_edit_script_paths = {each_entry.script_relative_path for each_entry in all_edit_entries}
726
- assert "blocking/stale_comment_reference_blocker.py" not in all_edit_script_paths
727
- assert "advisory/refactor_guard.py" in all_edit_script_paths, (
728
- "refactor_guard is Edit-scoped and hosted, so it belongs in the Edit applicable set"
729
- )
730
- assert len(all_edit_entries) == 20, (
731
- f"expected 20 Edit entries, got {len(all_edit_entries)}"
732
- )
733
-
734
-
735
- def test_dispatcher_multi_edit_reaches_the_sensitive_protector() -> None:
736
- """A MultiEdit onto a sensitive path meets the same gate a Write does.
737
-
738
- test_edit_and_multi_edit_applicable_sets_are_equal in the constants suite
739
- holds the Edit and MultiEdit rosters equal, so this pins the one hook whose
740
- absence would let a secret through a MultiEdit.
741
- """
742
- all_multi_edit_entries = _applicable_entries_for_tool(MULTI_EDIT_TOOL_NAME)
743
- all_multi_edit_script_paths = {
744
- each_entry.script_relative_path for each_entry in all_multi_edit_entries
745
- }
746
- assert "blocking/sensitive_file_protector.py" in all_multi_edit_script_paths, (
747
- "sensitive_file_protector belongs in the MultiEdit applicable set"
748
- )
749
-
750
-
751
- def test_dispatcher_apply_patch_applies_immediate_harm_hooks() -> None:
752
- """apply_patch applies to exactly the immediate-harm roster.
753
-
754
- apply_patch reaches only the immediate-harm-plus-TDD roster the constants
755
- module names, not the full Write/Edit/MultiEdit lint surface.
756
- """
757
- all_apply_patch_entries = _applicable_entries_for_tool(APPLY_PATCH_TOOL_NAME)
758
- all_apply_patch_script_paths = {
759
- each_entry.script_relative_path for each_entry in all_apply_patch_entries
760
- }
761
- assert "blocking/sensitive_file_protector.py" in all_apply_patch_script_paths, (
762
- "sensitive_file_protector belongs in the apply_patch applicable set"
763
- )
764
- assert all_apply_patch_script_paths == set(ALL_IMMEDIATE_HARM_SCRIPT_PATHS), (
765
- "apply_patch must apply to exactly the immediate-harm roster, got: "
766
- f"{sorted(all_apply_patch_script_paths)}"
767
- )
768
-
769
-
770
621
  def _assert_roster_names_no_run_all_validators_entry() -> None:
771
622
  """Assert no hosted-roster ``script_relative_path`` names run_all_validators."""
772
623
  all_roster_script_paths = {
@@ -829,40 +680,6 @@ def _orphan_claude_md_payload(tmp_path: Path) -> str:
829
680
  return _write_payload(claude_md_path, orphan_table)
830
681
 
831
682
 
832
- def test_runpy_deny_preserves_additional_context_and_suppress_output(tmp_path: Path) -> None:
833
- """A runpy-hosted deny carries its additionalContext and suppressOutput through the dispatcher.
834
-
835
- claude_md_orphan_file_blocker emits hookSpecificOutput.additionalContext and a
836
- top-level suppressOutput flag on a deny. The dispatcher must preserve both so
837
- the dispatched denial matches the standalone hook's deny shape.
838
-
839
- Args:
840
- tmp_path: Pytest temp directory hosting the throwaway CLAUDE.md.
841
- """
842
- payload_text = _orphan_claude_md_payload(tmp_path)
843
-
844
- standalone_result = _run_hook_subprocess(
845
- "blocking/claude_md_orphan_file_blocker.py", payload_text
846
- )
847
- standalone_payload = json.loads(standalone_result.stdout.strip())
848
- standalone_hook_specific = standalone_payload["hookSpecificOutput"]
849
- expected_additional_context = standalone_hook_specific["additionalContext"]
850
-
851
- dispatcher_result = _run_dispatcher(payload_text)
852
- dispatcher_payload = json.loads(dispatcher_result.stdout.strip())
853
- dispatcher_hook_specific = dispatcher_payload.get("hookSpecificOutput", {})
854
- assert isinstance(dispatcher_hook_specific, dict)
855
- assert dispatcher_hook_specific.get("additionalContext") == expected_additional_context, (
856
- "Dispatcher must preserve the runpy hook's additionalContext.\n"
857
- f"Expected: {expected_additional_context!r}\n"
858
- f"Got: {dispatcher_hook_specific.get('additionalContext')!r}"
859
- )
860
- assert dispatcher_payload.get("suppressOutput") is True, (
861
- "Dispatcher must preserve the runpy hook's suppressOutput flag.\n"
862
- f"Got: {dispatcher_payload.get('suppressOutput')!r}"
863
- )
864
-
865
-
866
683
  def _parse_hook_allow(completed_process: subprocess.CompletedProcess[str]) -> bool:
867
684
  """Parse one hook's subprocess result for an explicit permissionDecision allow.
868
685
 
@@ -885,45 +702,19 @@ def _parse_hook_allow(completed_process: subprocess.CompletedProcess[str]) -> bo
885
702
  return hook_specific.get("permissionDecision") == "allow"
886
703
 
887
704
 
888
- def test_dispatcher_reemits_explicit_allow_from_tdd_enforcer(tmp_path: Path) -> None:
889
- """The dispatcher re-emits an explicit allow when tdd_enforcer's allow branch fires.
890
-
891
- tdd_enforcer writes an explicit allow payload for a constants-only Python
892
- Write, which auto-approves the write standalone. Run against the dispatcher,
893
- the same payload must produce an explicit allow decision identical to the
894
- standalone tdd_enforcer output, rather than a silent fall-back to the default
895
- permission flow.
896
-
897
- Args:
898
- tmp_path: Pytest temp directory hosting the fresh config target path.
899
- """
705
+ def test_retired_tdd_hook_cannot_auto_approve_the_write(tmp_path: Path) -> None:
706
+ """Pairing belongs to staged lint; its edit-time auto-approval is absent."""
900
707
  config_target_path = str(tmp_path / "config" / "timing.py")
901
708
  constants_only_content = (
902
709
  '"""Timing constants."""\n\nMAXIMUM_RETRIES = 3\nRETRY_DELAY_SECONDS = 5\n'
903
710
  )
904
711
  payload_text = _write_payload(config_target_path, constants_only_content)
905
-
906
712
  standalone_result = _run_hook_subprocess("blocking/tdd_enforcer.py", payload_text)
907
- assert _parse_hook_allow(standalone_result), (
908
- "tdd_enforcer must emit an explicit allow for a constants-only Python Write — "
909
- "if it does not, this fixture no longer exercises the allow branch"
910
- )
911
-
713
+ assert _parse_hook_allow(standalone_result)
912
714
  dispatcher_result = _run_dispatcher(payload_text)
913
- dispatcher_is_deny, _reason = _parse_hook_decision(dispatcher_result)
914
- assert not dispatcher_is_deny, "dispatcher must not deny a payload tdd_enforcer allows"
915
- assert _parse_hook_allow(dispatcher_result), (
916
- "dispatcher must re-emit an explicit allow when a hosted hook allows explicitly "
917
- "and no hook denies, matching the standalone tdd_enforcer behavior — "
918
- f"got stdout {dispatcher_result.stdout.strip()!r}"
919
- )
920
- dispatcher_payload = json.loads(dispatcher_result.stdout.strip())
921
- standalone_payload = json.loads(standalone_result.stdout.strip())
922
- assert dispatcher_payload == standalone_payload, (
923
- "dispatcher allow payload must match the standalone tdd_enforcer allow payload.\n"
924
- f"Standalone: {standalone_payload!r}\n"
925
- f"Dispatcher: {dispatcher_payload!r}"
926
- )
715
+ dispatcher_is_deny, reason = _parse_hook_decision(dispatcher_result)
716
+ assert not dispatcher_is_deny, reason
717
+ assert not _parse_hook_allow(dispatcher_result)
927
718
 
928
719
 
929
720
  def test_runpy_hosted_hook_sees_its_own_argv_not_the_dispatchers(tmp_path: Path) -> None:
@@ -1007,13 +798,7 @@ def _dispatcher_matchers(all_pre_tool_use_groups: list[dict]) -> list[str]:
1007
798
 
1008
799
 
1009
800
  def test_apply_patch_has_no_standalone_code_rules_enforcer_hooks_json_entry() -> None:
1010
- """apply_patch's code_rules_enforcer coverage comes only from the dispatcher.
1011
-
1012
- hooks.json once registered a standalone apply_patch to code_rules_enforcer.py
1013
- PreToolUse command. That entry is now folded into the dispatcher's own
1014
- Write|Edit|MultiEdit|apply_patch matcher, so no separate command may still
1015
- spawn code_rules_enforcer.py for apply_patch on its own.
1016
- """
801
+ """The retired code-rules hook has no direct apply_patch registration."""
1017
802
  hooks_json_text = (_HOOKS_ROOT / "hooks.json").read_text(encoding="utf-8")
1018
803
  all_pre_tool_use_groups = json.loads(hooks_json_text)["hooks"]["PreToolUse"]
1019
804
 
@@ -1048,127 +833,43 @@ def _codex_add_patch(relative_file_path: str, file_body: str) -> str:
1048
833
  )
1049
834
 
1050
835
 
1051
- def test_dispatcher_denies_apply_patch_add_with_hardcoded_secret(
1052
- tmp_path: Path,
1053
- init_bare_git_repo: Callable[[Path], None],
1054
- synthetic_github_token: str,
1055
- ) -> None:
1056
- """The dispatcher denies an apply_patch "add" that writes a hardcoded token.
1057
-
1058
- Proves Done-when scenario 1 (hardcoded secret/PII denied) reaches apply_patch
1059
- through the real dispatcher subprocess, not only the standalone
1060
- pii_prevention_blocker test.
1061
- """
1062
- repository_root = tmp_path / "repo"
1063
- init_bare_git_repo(repository_root)
1064
- patch_command = _codex_add_patch("leaked.py", f"token is {synthetic_github_token}\n")
1065
- payload_text = _apply_patch_payload(str(repository_root), patch_command)
1066
-
1067
- dispatcher_result = _run_dispatcher(payload_text)
1068
- is_deny, reason_text = _parse_hook_decision(dispatcher_result)
1069
- assert is_deny, (
1070
- "dispatcher must deny an apply_patch add carrying a hardcoded secret, "
1071
- f"got stdout {dispatcher_result.stdout.strip()!r}"
1072
- )
1073
- assert reason_text, "a deny must carry a non-empty reason"
1074
-
1075
-
1076
- def test_dispatcher_denies_apply_patch_targeting_a_sensitive_path(tmp_path: Path) -> None:
1077
- """The dispatcher denies an apply_patch "add" that targets a sensitive file.
1078
-
1079
- Proves Done-when scenario 2 (sensitive path denied) reaches apply_patch
1080
- through the real dispatcher subprocess.
1081
- """
1082
- patch_command = _codex_add_patch(".env", "SECRET_KEY=irrelevant\n")
1083
- payload_text = _apply_patch_payload(str(tmp_path), patch_command)
1084
-
1085
- dispatcher_result = _run_dispatcher(payload_text)
1086
- is_deny, reason_text = _parse_hook_decision(dispatcher_result)
1087
- assert is_deny, (
1088
- "dispatcher must deny an apply_patch add targeting a sensitive path, "
1089
- f"got stdout {dispatcher_result.stdout.strip()!r}"
1090
- )
1091
- assert reason_text, "a deny must carry a non-empty reason"
1092
-
1093
-
1094
- def test_dispatcher_denies_apply_patch_add_onto_an_existing_path(tmp_path: Path) -> None:
1095
- """The dispatcher denies an apply_patch "add" that targets a path already on disk.
1096
-
1097
- Proves Done-when scenario 3 (overwrite-without-reading denied) reaches
1098
- apply_patch: a Codex "add" operation onto an existing path is caught by
1099
- code_rules_enforcer's codex-patch reading, blocking/codex_apply_patch.py's
1100
- _codex_read_patch_file, which raises CodexPatchError for an add already on
1101
- disk, reported through the dispatcher's aggregate.
1102
- """
1103
- existing_target = tmp_path / "already_here.py"
1104
- existing_target.write_text("value = 1\n", encoding="utf-8")
1105
- patch_command = _codex_add_patch("already_here.py", "value = 2\n")
1106
- payload_text = _apply_patch_payload(str(tmp_path), patch_command)
1107
-
1108
- dispatcher_result = _run_dispatcher(payload_text)
1109
- is_deny, reason_text = _parse_hook_decision(dispatcher_result)
1110
- assert is_deny, (
1111
- "dispatcher must deny an apply_patch add onto an already-existing path, "
1112
- f"got stdout {dispatcher_result.stdout.strip()!r}"
1113
- )
1114
- assert reason_text, "a deny must carry a non-empty reason"
1115
-
1116
-
1117
836
  def test_dispatcher_allows_clean_apply_patch_add(tmp_path: Path) -> None:
1118
- """The dispatcher allows an apply_patch "add" whose paired test already exists.
1119
-
1120
- tdd_enforcer now reaches apply_patch the same way it reaches Write: an
1121
- untested production file is exactly the immediate-harm case the apply_patch
1122
- boundary rule names, so "clean" here means test-first was honored before
1123
- the tool call, not that TDD is skipped for this tool. The paired test file
1124
- is written to disk first, matching how test_dispatcher_surfaces_migration_
1125
- warning_for_edit proves a fresh Edit passes tdd_enforcer.
1126
- """
1127
- (tmp_path / "test_services.py").write_text(
1128
- "def test_add_one():\n assert True\n", encoding="utf-8"
1129
- )
837
+ """A clean patch can proceed before the staged linter evaluates test pairing."""
1130
838
  patch_command = _codex_add_patch(
1131
- "services.py",
1132
- "def add_one(value: int) -> int:\n return value + 1\n",
839
+ "services.py", "def add_one(value: int) -> int:\n return value + 1\n",
1133
840
  )
1134
841
  payload_text = _apply_patch_payload(str(tmp_path), patch_command)
1135
-
1136
842
  dispatcher_result = _run_dispatcher(payload_text)
1137
843
  is_deny, reason_text = _parse_hook_decision(dispatcher_result)
1138
- assert not is_deny, (
1139
- f"dispatcher must allow an apply_patch add with a fresh paired test, "
1140
- f"got deny reason {reason_text!r}"
1141
- )
1142
-
1143
-
1144
- def test_hosted_hook_set_covers_all_write_edit_blocking_hooks() -> None:
1145
- """The hosted hook set covers all previously-registered Write/Edit blocking hooks.
1146
-
1147
- Verifies that removing the standalone gate entries from hooks.json did not
1148
- silently drop coverage: every script path that was registered as a blocking
1149
- PreToolUse hook for Write/Edit is present in the dispatcher's hosted set.
1150
- """
1151
- all_hosted_script_paths = frozenset(
844
+ assert not is_deny, reason_text
845
+
846
+
847
+ ALL_RETAINED_PATHS = {
848
+ "advisory/refactor_guard.py",
849
+ "advisory/migration_safety_advisor.py",
850
+ }
851
+ ALL_RETIRED_PATHS = {
852
+ "validation/hook_format_validator.py",
853
+ "blocking/code_rules_enforcer.py",
854
+ "blocking/tdd_enforcer.py",
855
+ "blocking/windows_rmtree_blocker.py",
856
+ "blocking/state_description_blocker.py",
857
+ "blocking/subprocess_budget_completeness.py",
858
+ "blocking/hook_prose_detector_consistency.py",
859
+ "blocking/workflow_substitution_slot_blocker.py",
860
+ "blocking/open_questions_in_plans_blocker.py",
861
+ "blocking/docstring_rule_gate_count_blocker.py",
862
+ "blocking/duplicate_rmtree_helper_blocker.py",
863
+ "blocking/env_var_table_code_drift_blocker.py",
864
+ "blocking/pytest_testpaths_orphan_blocker.py",
865
+ }
866
+
867
+ def test_hosted_hook_set_retains_boundaries_and_excludes_replaced_file_checks() -> None:
868
+ """Keep boundary controls and exclude every registry-backed policy hook."""
869
+ all_hosted_script_paths = {
1152
870
  each_entry.script_relative_path for each_entry in ALL_HOSTED_HOOK_ENTRIES
1153
- )
1154
- previously_registered_blocking_hooks: frozenset[str] = frozenset({
1155
- "blocking/write_existing_file_blocker.py",
1156
- "blocking/sensitive_file_protector.py",
1157
- "validation/hook_format_validator.py",
1158
- "blocking/code_rules_enforcer.py",
1159
- "blocking/tdd_enforcer.py",
1160
- "blocking/windows_rmtree_blocker.py",
1161
- "blocking/state_description_blocker.py",
1162
- "blocking/subprocess_budget_completeness.py",
1163
- "blocking/hook_prose_detector_consistency.py",
1164
- "blocking/workflow_substitution_slot_blocker.py",
1165
- "blocking/claude_md_orphan_file_blocker.py",
1166
- "blocking/pytest_testpaths_orphan_blocker.py",
1167
- "blocking/open_questions_in_plans_blocker.py",
1168
- })
1169
- for each_script_path in previously_registered_blocking_hooks:
1170
- assert each_script_path in all_hosted_script_paths, (
1171
- f"Previously-registered blocking hook {each_script_path!r} is missing "
1172
- "from the dispatcher's hosted hook set — coverage was lost when the "
1173
- "standalone entry was removed from hooks.json"
1174
- )
871
+ }
872
+ assert all_hosted_script_paths == ALL_RETAINED_PATHS
873
+ assert not all_hosted_script_paths.intersection(ALL_RETIRED_PATHS)
874
+ for each_relative_path in ALL_RETIRED_PATHS:
875
+ assert (_HOOKS_ROOT / each_relative_path).is_file()
@@ -1,16 +1,8 @@
1
- """Native-equivalence tests for the nativized PreToolUse hosted hooks.
2
-
3
- For the state_description_blocker hook the dispatcher runs natively. This suite
4
- asserts the native evaluate() call and the hook's standalone __main__ subprocess
5
- path decide identically on the same payload: same allow-or-deny, same deny-reason
6
- text. It also asserts the dispatcher reaches the same decision through its native
7
- path.
8
-
9
- The corpus pairs allowing payloads with denying payloads for each hook so the
10
- equivalence holds across both outcomes. Each payload names an absolute file
11
- under this repository and carries the repository root as its ``cwd``, so the
12
- decision belongs to this checkout rather than to the directory pytest runs
13
- from.
1
+ """Preserve detector equivalence while retiring its dispatcher registration.
2
+
3
+ The standalone state-description detector remains callable by the policy linter.
4
+ Its function and script agree on valid and invalid inputs; the write dispatcher
5
+ allows these policy findings to reach the staged linter.
14
6
  """
15
7
 
16
8
  from __future__ import annotations
@@ -195,28 +187,6 @@ def _deny_reason_from_dispatcher(payload_dictionary: dict[str, object]) -> str |
195
187
  )
196
188
  return _deny_reason_from_script_stdout(completed_process.stdout.strip())
197
189
 
198
- def _deny_payload_from_dispatcher(payload_dictionary: dict[str, object]) -> dict[str, object]:
199
- """Run the dispatcher as a subprocess and return its parsed deny payload.
200
-
201
- Args:
202
- payload_dictionary: The payload dict to send as JSON on stdin.
203
-
204
- Returns:
205
- The dispatcher's emitted deny JSON parsed into a dict.
206
- """
207
- completed_process = subprocess.run(
208
- [sys.executable, _DISPATCHER_SCRIPT],
209
- check=False,
210
- input=json.dumps(payload_dictionary),
211
- capture_output=True,
212
- text=True,
213
- encoding="utf-8",
214
- env=_subprocess_environment(),
215
- )
216
- parsed_payload = json.loads(completed_process.stdout.strip())
217
- assert isinstance(parsed_payload, dict)
218
- return parsed_payload
219
-
220
190
  def test_state_description_native_allows_match_script() -> None:
221
191
  """state_description_blocker native allow matches the script's allow."""
222
192
  payload_dictionary = _write_payload_dictionary(_MARKDOWN_PATH, _STATE_DESCRIPTION_ALLOW_CONTENT)
@@ -262,18 +232,17 @@ def test_state_description_native_multi_edit_deny_matches_script() -> None:
262
232
  assert native_reason == script_reason
263
233
 
264
234
 
265
- def test_dispatcher_native_path_denies_state_description() -> None:
266
- """The dispatcher's native path denies a state_description_blocker violation."""
235
+ def test_dispatcher_allows_the_retired_state_description_rule() -> None:
236
+ """The detector still finds the violation, but the write dispatcher allows it."""
267
237
  payload_dictionary = _write_payload_dictionary(_MARKDOWN_PATH, _STATE_DESCRIPTION_DENY_CONTENT)
268
238
  native_reason = _evaluate_with_prose_style_opt_in(state_description_blocker.evaluate, payload_dictionary)
269
239
  dispatcher_reason = _deny_reason_from_dispatcher(payload_dictionary)
270
240
  assert native_reason is not None
271
- assert dispatcher_reason is not None
272
- assert native_reason in dispatcher_reason
241
+ assert dispatcher_reason is None
273
242
 
274
243
 
275
- def test_dispatcher_native_state_description_carries_additional_context() -> None:
276
- """The dispatcher's state-description deny carries the standalone additionalContext."""
244
+ def test_standalone_state_description_retains_additional_context() -> None:
245
+ """The retained standalone interface still supplies its corrective context."""
277
246
  payload_dictionary = _write_payload_dictionary(_MARKDOWN_PATH, _STATE_DESCRIPTION_DENY_CONTENT)
278
247
  deny_reason = _evaluate_with_prose_style_opt_in(state_description_blocker.evaluate, payload_dictionary)
279
248
  assert deny_reason is not None
@@ -281,20 +250,20 @@ def test_dispatcher_native_state_description_carries_additional_context() -> Non
281
250
  standalone_hook_specific = standalone_payload["hookSpecificOutput"]
282
251
  assert isinstance(standalone_hook_specific, dict)
283
252
  expected_additional_context = standalone_hook_specific["additionalContext"]
284
- dispatcher_payload = _deny_payload_from_dispatcher(payload_dictionary)
285
- dispatcher_hook_specific = dispatcher_payload.get("hookSpecificOutput", {})
286
- assert isinstance(dispatcher_hook_specific, dict)
287
- assert dispatcher_hook_specific.get("additionalContext") == expected_additional_context
253
+ script_payload = json.loads(_run_script_subprocess(_STATE_DESCRIPTION_SCRIPT, payload_dictionary))
254
+ script_hook_specific = script_payload.get("hookSpecificOutput", {})
255
+ assert isinstance(script_hook_specific, dict)
256
+ assert script_hook_specific.get("additionalContext") == expected_additional_context
288
257
 
289
- def test_dispatcher_native_state_description_carries_system_message() -> None:
290
- """The dispatcher's state-description deny carries the standalone systemMessage."""
258
+ def test_standalone_state_description_retains_system_message() -> None:
259
+ """The retained standalone interface still supplies its system message."""
291
260
  payload_dictionary = _write_payload_dictionary(_MARKDOWN_PATH, _STATE_DESCRIPTION_DENY_CONTENT)
292
261
  deny_reason = _evaluate_with_prose_style_opt_in(state_description_blocker.evaluate, payload_dictionary)
293
262
  assert deny_reason is not None
294
263
  standalone_payload = state_description_blocker.build_deny_payload(deny_reason)
295
264
  expected_system_message = standalone_payload["systemMessage"]
296
265
  assert isinstance(expected_system_message, str)
297
- dispatcher_payload = _deny_payload_from_dispatcher(payload_dictionary)
298
- dispatcher_system_message = dispatcher_payload.get("systemMessage")
299
- assert isinstance(dispatcher_system_message, str)
300
- assert expected_system_message in dispatcher_system_message
266
+ script_payload = json.loads(_run_script_subprocess(_STATE_DESCRIPTION_SCRIPT, payload_dictionary))
267
+ script_system_message = script_payload.get("systemMessage")
268
+ assert isinstance(script_system_message, str)
269
+ assert expected_system_message in script_system_message
@@ -34,11 +34,7 @@ from test_hook_subprocess_support import ( # noqa: E402
34
34
  run_hook_as_subprocess,
35
35
  )
36
36
 
37
- ALL_CONVERTED_HOOK_FILENAMES = (
38
- "open_questions_in_plans_blocker.py",
39
- "claude_md_orphan_file_blocker.py",
40
- "package_inventory_stale_blocker.py",
41
- )
37
+ ALL_CONVERTED_HOOK_FILENAMES = ("open_questions_in_plans_blocker.py",)
42
38
 
43
39
  EMPTY_STDIN_PAYLOAD = ""
44
40
  WHITESPACE_STDIN_PAYLOAD = " \n\t "
@@ -126,48 +122,6 @@ def test_open_questions_blocker_still_allows_plan_without_open_questions(
126
122
  assert _decision_from_stdout(completed) is None
127
123
 
128
124
 
129
- def test_package_inventory_blocker_still_denies_uninventoried_new_file(
130
- tmp_path: Path,
131
- ) -> None:
132
- inventory_body = "# package\n\n| File | Role |\n|---|---|\n| `alpha.py` | A |\n| `beta.py` | B |\n"
133
- (tmp_path / "README.md").write_text(inventory_body, encoding="utf-8")
134
- (tmp_path / "alpha.py").write_text("x = 1\n", encoding="utf-8")
135
- (tmp_path / "beta.py").write_text("x = 1\n", encoding="utf-8")
136
- new_file_path = tmp_path / "gamma.py"
137
- payload = json.dumps(
138
- {
139
- "tool_name": "Write",
140
- "tool_input": {"file_path": str(new_file_path), "content": "x = 1\n"},
141
- }
142
- )
143
- completed = _run_hook_script("package_inventory_stale_blocker.py", payload, tmp_path)
144
- assert completed.returncode == 0, completed.stderr
145
- assert _decision_from_stdout(completed) == "deny"
146
- assert_hook_deny_log_contains(tmp_path, "package_inventory_stale_blocker.py")
147
-
148
-
149
- def test_package_inventory_blocker_still_allows_inventoried_new_file(
150
- tmp_path: Path,
151
- ) -> None:
152
- inventory_body = (
153
- "# package\n\n| File | Role |\n|---|---|\n"
154
- "| `alpha.py` | A |\n| `beta.py` | B |\n| `gamma.py` | G |\n"
155
- )
156
- (tmp_path / "README.md").write_text(inventory_body, encoding="utf-8")
157
- (tmp_path / "alpha.py").write_text("x = 1\n", encoding="utf-8")
158
- (tmp_path / "beta.py").write_text("x = 1\n", encoding="utf-8")
159
- new_file_path = tmp_path / "gamma.py"
160
- payload = json.dumps(
161
- {
162
- "tool_name": "Write",
163
- "tool_input": {"file_path": str(new_file_path), "content": "x = 1\n"},
164
- }
165
- )
166
- completed = _run_hook_script("package_inventory_stale_blocker.py", payload, tmp_path)
167
- assert completed.returncode == 0, completed.stderr
168
- assert _decision_from_stdout(completed) is None
169
-
170
-
171
125
  def test_converted_hooks_allow_unrelated_tool_name(tmp_path: Path) -> None:
172
126
  payload = json.dumps({"tool_name": "Bash", "tool_input": {"command": "ls"}})
173
127
  for each_hook_filename in ALL_CONVERTED_HOOK_FILENAMES:
@@ -0,0 +1,12 @@
1
+ """Constants for the native pre-commit policy-lint step."""
2
+
3
+ POLICY_LINT_PACKAGE_PARENT_INDEX = 2
4
+ POLICY_LINT_SCRIPT_RELATIVE_PATH = "scripts/cde_lint.py"
5
+ POLICY_LINT_STAGED_ARGUMENT = "--staged"
6
+ POLICY_LINT_TIMEOUT_SECONDS = 240
7
+ POLICY_LINT_INFRASTRUCTURE_EXIT_CODE = 2
8
+ POLICY_LINT_UNAVAILABLE_MESSAGE = (
9
+ "cde lint is missing from this hook installation; reinstall claude-dev-env "
10
+ "before committing"
11
+ )
12
+ POLICY_LINT_FAILED_MESSAGE = "cde lint could not complete: {error}"