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
@@ -11,7 +11,9 @@ from collections.abc import Mapping
11
11
  from pathlib import Path
12
12
 
13
13
  from dev_env_scripts_constants.shared_tree_constants import (
14
+ AGENTS_DIRECTORY_SUFFIX,
14
15
  CLAUDE_CONFIG_DIR_ENV_VAR,
16
+ DEFAULT_MANAGED_ROOT_NAME,
15
17
  PROCESS_TREE_DIRECTORY_NAME,
16
18
  PROCESS_TREE_KILL_MODULE_FILENAME,
17
19
  SCRIPTS_DIRECTORY_NAME,
@@ -29,6 +31,29 @@ def _shared_scripts_directory(from_root: Path, shared_subpackage_name: str) -> P
29
31
  )
30
32
 
31
33
 
34
+ def _linked_managed_root(module_path: Path, anchor_depth: int) -> Path | None:
35
+ """Resolve the managed root whose scripts pointer targets this installed tree.
36
+
37
+ Args:
38
+ module_path: The module path inside the managed scripts tree.
39
+ anchor_depth: Parent index of the package or agents root.
40
+
41
+ Returns:
42
+ The Claude managed root when its scripts pointer resolves to this tree.
43
+ """
44
+ package_root = module_path.resolve().parents[anchor_depth]
45
+ if not package_root.name.endswith(AGENTS_DIRECTORY_SUFFIX):
46
+ return None
47
+ managed_name = package_root.name.removesuffix(AGENTS_DIRECTORY_SUFFIX) or DEFAULT_MANAGED_ROOT_NAME
48
+ managed_root = package_root.parent / managed_name
49
+ linked_scripts = managed_root / SCRIPTS_DIRECTORY_NAME
50
+ if not linked_scripts.is_dir():
51
+ return None
52
+ if linked_scripts.resolve() != package_root / SCRIPTS_DIRECTORY_NAME:
53
+ return None
54
+ return managed_root
55
+
56
+
32
57
  def resolve_shared_scripts_directory(
33
58
  module_file: str | Path,
34
59
  all_environment: Mapping[str, str],
@@ -44,9 +69,10 @@ def resolve_shared_scripts_directory(
44
69
  ok: an un-resolved parent keeps the link side, where _shared sits
45
70
  flag: a resolved parent walks the link and misses _shared entirely
46
71
 
47
- Tries the un-resolved parent first, then the configured managed root,
48
- then the resolved parent. When none holds the marker, returns the
49
- un-resolved candidate, so an import failure names a readable path.
72
+ Tries the un-resolved parent first, then a verified installed scripts
73
+ pointer, then the configured managed root, then the resolved parent.
74
+ If none holds the marker, returns the un-resolved candidate so an
75
+ import failure names a readable path.
50
76
 
51
77
  Args:
52
78
  module_file: Path of the importing module (``__file__``).
@@ -63,6 +89,9 @@ def resolve_shared_scripts_directory(
63
89
  module_path.absolute().parents[anchor_depth], shared_subpackage_name
64
90
  )
65
91
  all_candidates = [un_resolved_candidate]
92
+ linked_root = _linked_managed_root(module_path, anchor_depth)
93
+ if linked_root is not None:
94
+ all_candidates.append(_shared_scripts_directory(linked_root, shared_subpackage_name))
66
95
  configured_root_text = all_environment.get(CLAUDE_CONFIG_DIR_ENV_VAR, "").strip()
67
96
  if configured_root_text:
68
97
  all_candidates.append(
@@ -330,3 +330,100 @@ def test_cli_has_no_inline_body_flag() -> None:
330
330
  )
331
331
  assert completed_process.returncode == 2
332
332
  assert "unrecognized arguments" in completed_process.stderr
333
+
334
+
335
+ RELEASE_BRANCH = "release-please--branches--main--components--claude-dev-env"
336
+ RELEASE_BODY = """:robot: I have created a release *beep* *boop*
337
+ ---
338
+
339
+
340
+ ## [7.0.0](https://example.invalid/compare/v6.0.0...v7.0.0) (2026-01-01)
341
+
342
+
343
+ ### Features
344
+
345
+ * a shipped change
346
+
347
+ ---
348
+ This PR was generated with [Release Please](https://example.invalid/release-please).
349
+ """
350
+
351
+
352
+ def should_accept_a_release_body_without_the_house_headings() -> None:
353
+ all_findings = durable_post_lint.lint_durable_post(
354
+ action="pr-edit",
355
+ title=None,
356
+ body_text=RELEASE_BODY,
357
+ head_branch=RELEASE_BRANCH,
358
+ )
359
+ assert all_findings == ()
360
+
361
+
362
+ @pytest.mark.parametrize(
363
+ "damaged_body",
364
+ [
365
+ RELEASE_BODY.replace(":robot: I have created a release *beep* *boop*", ""),
366
+ RELEASE_BODY.replace("This PR was generated with [Release Please]", ""),
367
+ ],
368
+ )
369
+ def should_report_a_release_body_that_lost_a_marker(damaged_body: str) -> None:
370
+ all_findings = durable_post_lint.lint_durable_post(
371
+ action="pr-edit",
372
+ title=None,
373
+ body_text=damaged_body,
374
+ head_branch=RELEASE_BRANCH,
375
+ )
376
+ assert [each_finding.code for each_finding in all_findings] == [
377
+ "rewritten-release-body"
378
+ ]
379
+
380
+
381
+ def should_report_a_release_body_rewritten_into_house_prose() -> None:
382
+ all_findings = durable_post_lint.lint_durable_post(
383
+ action="pr-edit",
384
+ title=None,
385
+ body_text="This pull request publishes claude-dev-env 2.37.0.",
386
+ head_branch=RELEASE_BRANCH,
387
+ )
388
+ assert [each_finding.code for each_finding in all_findings] == [
389
+ "rewritten-release-body"
390
+ ]
391
+
392
+
393
+ def should_keep_the_house_headings_for_an_ordinary_branch() -> None:
394
+ all_findings = durable_post_lint.lint_durable_post(
395
+ action="pr-create",
396
+ title="fix(cli): tighten input handling",
397
+ body_text="Body without the required headings.",
398
+ head_branch="fix/ordinary-branch",
399
+ )
400
+ assert MISSING_HEADING_CODE_NAME in {
401
+ each_finding.code for each_finding in all_findings
402
+ }
403
+
404
+
405
+ MISSING_HEADING_CODE_NAME = "missing-pr-description-heading"
406
+
407
+
408
+ def should_report_a_rewritten_release_body_through_the_command_line(
409
+ tmp_path: Path,
410
+ ) -> None:
411
+ body_path = tmp_path / "body.md"
412
+ body_path.write_text("This pull request publishes the package.", encoding="utf-8")
413
+ completed_process = subprocess.run(
414
+ [
415
+ sys.executable,
416
+ str(SCRIPT_PATH),
417
+ "--action",
418
+ "pr-edit",
419
+ "--body-file",
420
+ str(body_path),
421
+ "--head-branch",
422
+ RELEASE_BRANCH,
423
+ ],
424
+ check=False,
425
+ capture_output=True,
426
+ text=True,
427
+ )
428
+ assert completed_process.returncode == 1
429
+ assert "keep the generated text whole" in completed_process.stderr
@@ -171,3 +171,36 @@ def test_generalized_resolver_serves_a_deeper_anchor(tmp_path: Path) -> None:
171
171
  3,
172
172
  )
173
173
  assert resolved_scripts_directory == expected_scripts_directory
174
+
175
+
176
+ @pytest.mark.parametrize("managed_name", (".claude", "profile-a"))
177
+ def test_resolved_agents_scripts_find_the_verified_managed_root(
178
+ tmp_path: Path, managed_name: str,
179
+ ) -> None:
180
+ agents_name = ".agents" if managed_name == ".claude" else f"{managed_name}.agents"
181
+ agents_root = tmp_path / agents_name
182
+ scripts_directory = agents_root / "scripts"
183
+ scripts_directory.mkdir(parents=True)
184
+ module_file = scripts_directory / "runner.py"
185
+ module_file.write_text("", encoding="utf-8")
186
+ managed_root = tmp_path / managed_name
187
+ managed_root.mkdir()
188
+ _create_directory_link(from_link=managed_root / "scripts", to_target=scripts_directory)
189
+ expected = _write_process_tree_kill_stub(managed_root)
190
+ resolved_directory = shared_tree_paths.resolve_shared_process_tree_scripts_directory(module_file, {})
191
+ assert resolved_directory == expected
192
+
193
+
194
+ def test_neighboring_managed_root_cannot_supply_a_foreign_shared_tree(tmp_path: Path) -> None:
195
+ agents_root = tmp_path / ".agents"
196
+ scripts_directory = agents_root / "scripts"
197
+ scripts_directory.mkdir(parents=True)
198
+ module_file = scripts_directory / "runner.py"
199
+ module_file.write_text("", encoding="utf-8")
200
+ managed_root = tmp_path / ".claude"
201
+ foreign_scripts = managed_root / "scripts"
202
+ foreign_scripts.mkdir(parents=True)
203
+ _write_process_tree_kill_stub(managed_root)
204
+ resolved_directory = shared_tree_paths.resolve_shared_process_tree_scripts_directory(module_file, {})
205
+ expected = agents_root / "_shared" / "process-tree" / "scripts"
206
+ assert resolved_directory == expected
@@ -0,0 +1,150 @@
1
+ import assert from "node:assert/strict";
2
+ import { spawnSync } from "node:child_process";
3
+ import {
4
+ mkdirSync,
5
+ mkdtempSync,
6
+ readFileSync,
7
+ rmSync,
8
+ writeFileSync,
9
+ } from "node:fs";
10
+ import { tmpdir } from "node:os";
11
+ import path from "node:path";
12
+ import test from "node:test";
13
+ import { fileURLToPath } from "node:url";
14
+
15
+ const packageRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
16
+ const auditCliPath = path.join(packageRoot, "audit-hooks-cli.mjs");
17
+
18
+ function writeJson(filePath, jsonDocument) {
19
+ writeFileSync(filePath, JSON.stringify(jsonDocument), "utf8");
20
+ }
21
+
22
+ function createAuditFixture({
23
+ canonicalHooks = {},
24
+ claudeHooks = { hooks: {} },
25
+ codexHooks = { hooks: {} },
26
+ } = {}) {
27
+ const fixtureRoot = mkdtempSync(path.join(tmpdir(), "hook-audit-cli-"));
28
+ const canonicalHooksRoot = path.join(fixtureRoot, "packages", "claude-dev-env", "hooks");
29
+ const homeDirectory = path.join(fixtureRoot, "home");
30
+ mkdirSync(canonicalHooksRoot, { recursive: true });
31
+ mkdirSync(path.join(homeDirectory, ".claude", "hooks"), { recursive: true });
32
+ mkdirSync(path.join(homeDirectory, ".codex", "hooks"), { recursive: true });
33
+ writeJson(path.join(canonicalHooksRoot, "hooks.json"), { hooks: canonicalHooks });
34
+ writeJson(path.join(homeDirectory, ".claude", "settings.json"), claudeHooks);
35
+ writeJson(path.join(homeDirectory, ".codex", "hooks.json"), codexHooks);
36
+ return { fixtureRoot, homeDirectory };
37
+ }
38
+
39
+ function runAuditCli(allArguments) {
40
+ const childProcess = spawnSync(process.execPath, [auditCliPath, ...allArguments], {
41
+ cwd: packageRoot,
42
+ encoding: "utf8",
43
+ env: { ...process.env, HOME: path.join(tmpdir(), "unused-audit-cli-home") },
44
+ shell: false,
45
+ });
46
+ assert.equal(childProcess.error, undefined);
47
+ return childProcess;
48
+ }
49
+
50
+ test("writes a JSON audit report to stdout through the CLI", () => {
51
+ const fixture = createAuditFixture({
52
+ canonicalHooks: {
53
+ PreToolUse: [{
54
+ matcher: "Write",
55
+ hooks: [{
56
+ type: "command",
57
+ command: "python3 " + "$" + "{CLAUDE_PLUGIN_ROOT}/hooks/blocking/write_existing_file_blocker.py",
58
+ }],
59
+ }],
60
+ },
61
+ });
62
+ try {
63
+ const childProcess = runAuditCli([
64
+ "--format",
65
+ "json",
66
+ "--repository-root",
67
+ fixture.fixtureRoot,
68
+ ]);
69
+
70
+ assert.equal(childProcess.status, 0);
71
+ assert.equal(childProcess.stderr, "");
72
+ const report = JSON.parse(childProcess.stdout);
73
+ assert.equal(report.summary.directCount, 1);
74
+ assert.equal(report.registrationEligibility.status, "not_checked");
75
+ } finally {
76
+ rmSync(fixture.fixtureRoot, { force: true, recursive: true });
77
+ }
78
+ });
79
+
80
+ test("writes the JSON audit report to the requested file through the CLI", () => {
81
+ const fixture = createAuditFixture();
82
+ const reportPath = path.join(fixture.fixtureRoot, "audit-report.json");
83
+ try {
84
+ const childProcess = runAuditCli([
85
+ "--format",
86
+ "json",
87
+ "--output",
88
+ reportPath,
89
+ "--repository-root",
90
+ fixture.fixtureRoot,
91
+ ]);
92
+
93
+ assert.equal(childProcess.status, 0);
94
+ assert.equal(childProcess.stdout, "");
95
+ const report = JSON.parse(readFileSync(reportPath, "utf8"));
96
+ assert.equal(report.summary.directCount, 0);
97
+ assert.equal(report.summary.findingCount, 0);
98
+ } finally {
99
+ rmSync(fixture.fixtureRoot, { force: true, recursive: true });
100
+ }
101
+ });
102
+
103
+ test("returns a strict nonblocking failure through the CLI", () => {
104
+ const fixture = createAuditFixture({
105
+ claudeHooks: {
106
+ hooks: {
107
+ SessionStart: [{
108
+ hooks: [{ command: "node cleanup.mjs", type: "command" }],
109
+ }],
110
+ },
111
+ },
112
+ });
113
+ const catalogPath = path.join(fixture.fixtureRoot, "lifecycle.json");
114
+ writeJson(catalogPath, {
115
+ hooks: {
116
+ "external:cleanup.mjs": {
117
+ lifecycle: "delete",
118
+ reason: "The installed entry is retired.",
119
+ replacement: null,
120
+ },
121
+ },
122
+ });
123
+ try {
124
+ const childProcess = runAuditCli([
125
+ "--format",
126
+ "json",
127
+ "--catalog",
128
+ catalogPath,
129
+ "--home",
130
+ fixture.homeDirectory,
131
+ "--installed",
132
+ "--require-nonblocking",
133
+ "--repository-root",
134
+ fixture.fixtureRoot,
135
+ ]);
136
+
137
+ assert.equal(childProcess.status, 1);
138
+ assert.equal(childProcess.stderr, "");
139
+ const report = JSON.parse(childProcess.stdout);
140
+ assert.equal(report.registrationEligibility.status, "ineligible");
141
+ assert.equal(
142
+ report.findings.some(({ code, target }) =>
143
+ code === "NONBLOCKING_LIFECYCLE_MISMATCH" && target === "external:cleanup.mjs",
144
+ ),
145
+ true,
146
+ );
147
+ } finally {
148
+ rmSync(fixture.fixtureRoot, { force: true, recursive: true });
149
+ }
150
+ });
@@ -1,6 +1,6 @@
1
1
  import assert from "node:assert/strict";
2
2
  import { spawnSync } from "node:child_process";
3
- import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
3
+ import { existsSync, mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
4
4
  import { tmpdir } from "node:os";
5
5
  import path from "node:path";
6
6
  import test from "node:test";
@@ -73,6 +73,37 @@ test("renders deterministic private JSON", () => {
73
73
  assert.equal(first.includes("python3 ${CLAUDE_PLUGIN_ROOT}"), false);
74
74
  });
75
75
 
76
+ test("does not compare the live graph with retired baseline counts", () => {
77
+ const report = auditHooks({ repositoryRoot });
78
+ assert.equal(report.summary.directCount, report.directRegistrations.length);
79
+ assert.equal(report.summary.effectiveCount, report.hostedRegistrations.length);
80
+ assert.equal(report.summary.logicalAssociationCount, report.logicalRegistrations.length);
81
+ assert.ok(report.summary.directCount > 0);
82
+ assert.ok(report.summary.effectiveCount > 0);
83
+ assert.ok(report.summary.logicalAssociationCount > report.summary.directCount);
84
+ assert.equal(report.findings.some(({ code }) => code === "DIRECT_COUNT_DRIFT"), false);
85
+ assert.equal(report.findings.some(({ code }) => code === "HOSTED_COUNT_DRIFT"), false);
86
+ });
87
+
88
+ test("does not execute registered commands", () => {
89
+ const fixture = createAuditFixture({
90
+ canonicalHooks: {
91
+ PreToolUse: [{
92
+ hooks: [{
93
+ command: "node -e \"require('node:fs').writeFileSync('audit-executed', 'yes')\"",
94
+ type: "command",
95
+ }],
96
+ }],
97
+ },
98
+ });
99
+ try {
100
+ auditHooks({ repositoryRoot: fixture.fixtureRoot });
101
+ assert.equal(existsSync(path.join(fixture.fixtureRoot, "audit-executed")), false);
102
+ } finally {
103
+ rmSync(fixture.fixtureRoot, { force: true, recursive: true });
104
+ }
105
+ });
106
+
76
107
  test("reports every unclassified target", () => {
77
108
  const temporaryRoot = mkdtempSync(path.join(tmpdir(), "hook-audit-"));
78
109
  const catalogPath = path.join(temporaryRoot, "lifecycle.json");
@@ -86,6 +117,15 @@ test("reports every unclassified target", () => {
86
117
  }
87
118
  });
88
119
 
120
+ test("reports canonical native Git hooks from the installer registry", () => {
121
+ const report = auditHooks({ repositoryRoot });
122
+ assert.deepEqual(
123
+ report.knownGitRegistrations.map(({ target }) => target),
124
+ ["git:pre-commit", "git:pre-push", "git:post-commit"],
125
+ );
126
+ assert.equal(report.summary.knownGitHookCount, 3);
127
+ });
128
+
89
129
  test("keeps each hosted matcher as narrow as its roster", () => {
90
130
  const fixture = createAuditFixture({
91
131
  canonicalHooks: {
@@ -161,6 +201,7 @@ test("classifies installed-only targets", () => {
161
201
  catalogPath,
162
202
  homeDirectory: fixture.homeDirectory,
163
203
  includeInstalled: true,
204
+ requireNonblocking: true,
164
205
  repositoryRoot: temporaryRoot,
165
206
  });
166
207
  const missingTargets = new Set(
@@ -266,6 +307,46 @@ test("reports missing installed dispatcher targets", () => {
266
307
  }
267
308
  });
268
309
 
310
+ test("rejects an installed-only registration without nonblocking lifecycle", () => {
311
+ const fixture = createAuditFixture({
312
+ claudeHooks: {
313
+ hooks: {
314
+ SessionStart: [{
315
+ hooks: [{ command: "node cleanup.mjs", type: "command" }],
316
+ }],
317
+ },
318
+ },
319
+ });
320
+ const catalogPath = path.join(fixture.fixtureRoot, "lifecycle.json");
321
+ writeJson(catalogPath, {
322
+ hooks: {
323
+ "external:cleanup.mjs": {
324
+ lifecycle: "delete",
325
+ reason: "The installed entry is retired.",
326
+ replacement: null,
327
+ },
328
+ },
329
+ });
330
+ try {
331
+ const report = auditHooks({
332
+ catalogPath,
333
+ homeDirectory: fixture.homeDirectory,
334
+ includeInstalled: true,
335
+ requireNonblocking: true,
336
+ repositoryRoot: fixture.fixtureRoot,
337
+ });
338
+ assert.equal(report.registrationEligibility.status, "ineligible");
339
+ assert.equal(
340
+ report.findings.some(({ code, target }) =>
341
+ code === "NONBLOCKING_LIFECYCLE_MISMATCH" && target === "external:cleanup.mjs",
342
+ ),
343
+ true,
344
+ );
345
+ } finally {
346
+ rmSync(fixture.fixtureRoot, { force: true, recursive: true });
347
+ }
348
+ });
349
+
269
350
  test("checks canonical managed parity for Codex registrations", () => {
270
351
  const fixture = createAuditFixture({
271
352
  canonicalHooks: {
@@ -355,6 +436,7 @@ test("finds default Git hooks from a worktree", () => {
355
436
  runGit(sourceRoot, ["commit", "--quiet", "--allow-empty", "-m", "fixture"], environment);
356
437
  runGit(sourceRoot, ["worktree", "add", "--quiet", worktreeRoot, "HEAD"], environment);
357
438
  writeHookFile(path.join(sourceRoot, ".git", "hooks"), "pre-commit");
439
+ writeHookFile(path.join(sourceRoot, ".git", "hooks"), "post-commit");
358
440
  const canonicalHooksRoot = path.join(worktreeRoot, "packages", "claude-dev-env", "hooks");
359
441
  const homeDirectory = path.join(sourceRoot, "home");
360
442
  mkdirSync(canonicalHooksRoot, { recursive: true });
@@ -366,9 +448,19 @@ test("finds default Git hooks from a worktree", () => {
366
448
  const report = auditHooks({
367
449
  homeDirectory,
368
450
  includeInstalled: true,
451
+ requireNonblocking: true,
369
452
  repositoryRoot: worktreeRoot,
370
453
  });
371
- assert.deepEqual(report.gitRegistrations.map(({ target }) => target), ["git:pre-commit"]);
454
+ assert.deepEqual(report.gitRegistrations.map(({ target }) => target), [
455
+ "git:pre-commit",
456
+ "git:post-commit",
457
+ ]);
458
+ assert.equal(
459
+ report.findings.some(({ code, target }) =>
460
+ code === "NATIVE_GIT_BLOCKING_HOOK" && target === "git:pre-commit",
461
+ ),
462
+ true,
463
+ );
372
464
  } finally {
373
465
  if (previousGlobalConfig === undefined) delete process.env.GIT_CONFIG_GLOBAL;
374
466
  else process.env.GIT_CONFIG_GLOBAL = previousGlobalConfig;