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,29 +1,4 @@
1
1
  #!/usr/bin/env node
2
- /**
3
- * Smoke driver for the claude-dev-env installer.
4
- *
5
- * The installer (bin/install.mjs) writes into os.homedir()/.claude and
6
- * os.homedir()/.agents and has
7
- * three global side effects: it copies files under ~/.claude/ and ~/.agents/, sets
8
- * `git config --global core.hooksPath`, and writes ~/.mypy.ini. There is no
9
- * flag to redirect the target, so this driver isolates every side effect by
10
- * spawning the installer with HOME, USERPROFILE, and GIT_CONFIG_GLOBAL all
11
- * pointed at a throwaway sandbox directory. Node's os.homedir() follows
12
- * USERPROFILE on Windows and HOME on POSIX, so setting both redirects the
13
- * install target on either platform without touching the real ~/.claude/.
14
- *
15
- * The isolated GIT_CONFIG_GLOBAL is seeded with `safe.directory = *` so the
16
- * installer's `git status` source-conflict guard runs even when the checkout
17
- * lives somewhere git flags as dubious ownership (for example a UNC network
18
- * share), while the installer's `git config --global core.hooksPath` write
19
- * still lands only in the sandbox config.
20
- *
21
- * It runs the three lifecycle commands an agent cares about — `--help`, a full
22
- * install, and `--uninstall` — and asserts the observable result of each
23
- * against the sandbox tree. Exit code 0 means every assertion held.
24
- *
25
- * Usage: node .claude/skills/run-claude-dev-env/driver.mjs
26
- */
27
2
 
28
3
  import { spawnSync } from 'node:child_process';
29
4
  import {
@@ -41,7 +16,7 @@ import { tmpdir } from 'node:os';
41
16
  import { fileURLToPath } from 'node:url';
42
17
 
43
18
  const DRIVER_DIRECTORY = dirname(fileURLToPath(import.meta.url));
44
- const PACKAGE_ROOT = resolve(DRIVER_DIRECTORY, '..', '..', '..');
19
+ const PACKAGE_ROOT = resolve(DRIVER_DIRECTORY, '..', '..');
45
20
  const INSTALL_ENTRY = join(PACKAGE_ROOT, 'bin', 'install.mjs');
46
21
 
47
22
  const checks = [];
@@ -68,7 +43,7 @@ function collectFilesRecursive(directory) {
68
43
 
69
44
  function runInstaller(sandboxHome, installerArguments) {
70
45
  const gitConfigGlobal = join(sandboxHome, '.gitconfig-sandbox');
71
- const result = spawnSync(process.execPath, [INSTALL_ENTRY, ...installerArguments], {
46
+ const installerProcess = spawnSync(process.execPath, [INSTALL_ENTRY, ...installerArguments], {
72
47
  cwd: PACKAGE_ROOT,
73
48
  encoding: 'utf8',
74
49
  env: {
@@ -78,7 +53,7 @@ function runInstaller(sandboxHome, installerArguments) {
78
53
  GIT_CONFIG_GLOBAL: gitConfigGlobal,
79
54
  },
80
55
  });
81
- return result;
56
+ return installerProcess;
82
57
  }
83
58
 
84
59
  function main() {
@@ -0,0 +1,26 @@
1
+ import assert from 'node:assert/strict';
2
+ import { spawnSync } from 'node:child_process';
3
+ import { readFileSync } from 'node:fs';
4
+ import { dirname, join } from 'node:path';
5
+ import test from 'node:test';
6
+ import { fileURLToPath } from 'node:url';
7
+
8
+ const CI_DIRECTORY = dirname(fileURLToPath(import.meta.url));
9
+ const DRIVER_PATH = join(CI_DIRECTORY, 'installer-lifecycle.mjs');
10
+ const DRIVER_TIMEOUT_MILLISECONDS = 60_000;
11
+
12
+ test('the installer lifecycle driver completes in an isolated home', () => {
13
+ const lifecycleProcess = spawnSync(process.execPath, [DRIVER_PATH], {
14
+ encoding: 'utf8',
15
+ timeout: DRIVER_TIMEOUT_MILLISECONDS,
16
+ });
17
+ assert.equal(lifecycleProcess.status, 0, `${lifecycleProcess.stdout}\n${lifecycleProcess.stderr}`);
18
+ assert.match(lifecycleProcess.stdout, /ALL CHECKS PASSED/);
19
+ assert.match(lifecycleProcess.stdout, /Sandbox removed:/);
20
+ });
21
+
22
+ test('the Windows adapter invokes the CI-owned lifecycle driver', () => {
23
+ const adapterSource = readFileSync(join(CI_DIRECTORY, 'windows-installer-lifecycle.ps1'), 'utf8');
24
+ assert.match(adapterSource, /\$driverPath = Join-Path \$PSScriptRoot 'installer-lifecycle\.mjs'/);
25
+ assert.doesNotMatch(adapterSource, /skills\\run-claude-dev-env/);
26
+ });
@@ -1,13 +1,3 @@
1
- # Windows CI adapter for the Node installer lifecycle driver.
2
- #
3
- # The driver already redirects HOME, USERPROFILE, and GIT_CONFIG_GLOBAL into a
4
- # throwaway sandbox. This adapter records that isolation contract, runs the
5
- # 16-check driver, and writes bounded evidence under -EvidenceRoot so a failed
6
- # Windows runner leaves an actionable artifact.
7
- #
8
- # Usage (from packages/claude-dev-env):
9
- # pwsh -NoProfile -File scripts/ci/windows-installer-lifecycle.ps1 -EvidenceRoot <dir>
10
-
11
1
  [CmdletBinding()]
12
2
  param(
13
3
  [Parameter(Mandatory = $true)]
@@ -17,7 +7,7 @@ param(
17
7
  $ErrorActionPreference = 'Stop'
18
8
 
19
9
  $packageRoot = (Resolve-Path (Join-Path $PSScriptRoot '..\..')).Path
20
- $driverPath = Join-Path $packageRoot '.claude\skills\run-claude-dev-env\driver.mjs'
10
+ $driverPath = Join-Path $PSScriptRoot 'installer-lifecycle.mjs'
21
11
  $allIsolationEnvNames = @(
22
12
  'HOME',
23
13
  'USERPROFILE',
@@ -615,7 +615,7 @@ def _resolved_codex_enforcer_command(config: MaterializerConfig) -> str:
615
615
 
616
616
  def _source_codex_enforcer_hook(
617
617
  all_source_manifest: dict[str, object], command: str
618
- ) -> dict[str, object]:
618
+ ) -> dict[str, object] | None:
619
619
  """Read the source enforcer hook shape and resolve its target command."""
620
620
  all_events = all_source_manifest.get("hooks")
621
621
  if not isinstance(all_events, dict):
@@ -637,11 +637,7 @@ def _source_codex_enforcer_hook(
637
637
  resolved_hook = dict(each_hook)
638
638
  resolved_hook[codex_hook_command_field_name] = command
639
639
  return resolved_hook
640
- return {
641
- "type": "command",
642
- codex_hook_command_field_name: command,
643
- "timeout": codex_hook_timeout_seconds,
644
- }
640
+ return None
645
641
 
646
642
 
647
643
  def _hook_records(raw_hooks: object) -> list[dict[str, object]]:
@@ -668,6 +664,72 @@ def _is_code_rules_enforcer_hook(all_hook_record: dict[str, object]) -> bool:
668
664
  )
669
665
 
670
666
 
667
+ def _is_managed_codex_enforcer_hook(
668
+ all_hook_record: dict[str, object], managed_command: str
669
+ ) -> bool:
670
+ """Report whether a hook record is the materializer's target command."""
671
+ command = all_hook_record.get(codex_hook_command_field_name)
672
+ if not isinstance(command, str):
673
+ return False
674
+ normalized_command = command.replace("\\", path_separator)
675
+ normalized_managed_command = managed_command.replace("\\", path_separator)
676
+ if os.name == "nt":
677
+ return normalized_command.casefold() == normalized_managed_command.casefold()
678
+ return normalized_command == normalized_managed_command
679
+
680
+
681
+ def _without_managed_codex_enforcer(
682
+ entry: object, managed_command: str
683
+ ) -> object | None:
684
+ """Remove the managed enforcer while preserving every other hook record."""
685
+ if not isinstance(entry, dict):
686
+ return entry
687
+ if entry.get("matcher") != codex_hook_matcher:
688
+ return entry
689
+ copied_entry = dict(entry)
690
+ all_hook_records = copied_entry.get(codex_hook_records_field_name)
691
+ if not isinstance(all_hook_records, list):
692
+ return copied_entry
693
+ all_retained_hooks = [
694
+ each_hook
695
+ for each_hook in all_hook_records
696
+ if not isinstance(each_hook, dict)
697
+ or not _is_managed_codex_enforcer_hook(each_hook, managed_command)
698
+ ]
699
+ if all_retained_hooks == all_hook_records:
700
+ return copied_entry
701
+ if not all_retained_hooks:
702
+ return None
703
+ copied_entry[codex_hook_records_field_name] = all_retained_hooks
704
+ return copied_entry
705
+
706
+
707
+ def _remove_managed_codex_enforcer(
708
+ all_target_manifest: dict[str, object], managed_command: str
709
+ ) -> dict[str, object]:
710
+ """Remove the retired managed enforcer from the target manifest."""
711
+ all_events = all_target_manifest.get(codex_hook_records_field_name, {})
712
+ if not isinstance(all_events, dict):
713
+ raise MaterializerError("Codex hook manifest requires a hooks object")
714
+ all_pre_tool_use = all_events.get(codex_hook_event_name)
715
+ if all_pre_tool_use is None:
716
+ return _prune_retired_codex_hooks(all_target_manifest)
717
+ if not isinstance(all_pre_tool_use, list):
718
+ raise MaterializerError("Codex hook manifest requires a PreToolUse list")
719
+ all_retained_entries: list[object] = []
720
+ for each_entry in all_pre_tool_use:
721
+ maybe_retained_entry = _without_managed_codex_enforcer(
722
+ each_entry, managed_command
723
+ )
724
+ if maybe_retained_entry is not None:
725
+ all_retained_entries.append(maybe_retained_entry)
726
+ merged_events = dict(all_events)
727
+ merged_events[codex_hook_event_name] = all_retained_entries
728
+ merged_manifest = dict(all_target_manifest)
729
+ merged_manifest[codex_hook_records_field_name] = merged_events
730
+ return _prune_retired_codex_hooks(merged_manifest)
731
+
732
+
671
733
  def _is_retired_codex_hook_command(command: object) -> bool:
672
734
  """Report whether a command names a known retired hook path."""
673
735
  if not isinstance(command, str):
@@ -764,13 +826,20 @@ def _has_modified_codex_enforcer_hook(
764
826
  current_hooks = _codex_enforcer_hooks(current_manifest)
765
827
  if not current_hooks:
766
828
  return False
767
- return current_hooks != _codex_enforcer_hooks(planned_manifest)
829
+ planned_hooks = _codex_enforcer_hooks(planned_manifest)
830
+ if all(each_hook in current_hooks for each_hook in planned_hooks):
831
+ return False
832
+ return current_hooks != planned_hooks
768
833
 
769
834
 
770
835
  def _merge_codex_hook_manifest(
771
- all_target_manifest: dict[str, object], all_focused_hook: dict[str, object]
836
+ all_target_manifest: dict[str, object],
837
+ all_focused_hook: dict[str, object] | None,
838
+ managed_command: str,
772
839
  ) -> dict[str, object]:
773
840
  """Preserve target hook order while merging one deterministic enforcer entry."""
841
+ if all_focused_hook is None:
842
+ return _remove_managed_codex_enforcer(all_target_manifest, managed_command)
774
843
  all_events = all_target_manifest.get(codex_hook_records_field_name, {})
775
844
  if not isinstance(all_events, dict):
776
845
  raise MaterializerError("Codex hook manifest requires a hooks object")
@@ -797,13 +866,17 @@ def _merge_codex_hook_manifest(
797
866
  if merged_apply_patch_entry is None:
798
867
  merged_apply_patch_entry = copied_entry
799
868
  merged_hooks = [
800
- each_hook for each_hook in all_hook_records if not _is_code_rules_enforcer_hook(each_hook)
869
+ each_hook
870
+ for each_hook in all_hook_records
871
+ if not _is_managed_codex_enforcer_hook(each_hook, managed_command)
801
872
  ]
802
873
  merged_apply_patch_entry[codex_hook_records_field_name] = merged_hooks
803
874
  merged_pre_tool_use.append(merged_apply_patch_entry)
804
875
  else:
805
876
  merged_hooks.extend(
806
- each_hook for each_hook in all_hook_records if not _is_code_rules_enforcer_hook(each_hook)
877
+ each_hook
878
+ for each_hook in all_hook_records
879
+ if not _is_managed_codex_enforcer_hook(each_hook, managed_command)
807
880
  )
808
881
  if merged_apply_patch_entry is None:
809
882
  merged_apply_patch_entry = {
@@ -831,10 +904,11 @@ def _build_codex_hook_projection(config: MaterializerConfig) -> PlannedFile | No
831
904
  if target_path.is_file()
832
905
  else {"hooks": {}}
833
906
  )
834
- focused_hook = _source_codex_enforcer_hook(
835
- source_manifest, _resolved_codex_enforcer_command(config)
907
+ managed_command = _resolved_codex_enforcer_command(config)
908
+ focused_hook = _source_codex_enforcer_hook(source_manifest, managed_command)
909
+ projected_manifest = _merge_codex_hook_manifest(
910
+ target_manifest, focused_hook, managed_command
836
911
  )
837
- projected_manifest = _merge_codex_hook_manifest(target_manifest, focused_hook)
838
912
  projected_content = json.dumps(projected_manifest, ensure_ascii=False, indent=manifest_indentation_width) + line_separator
839
913
  return PlannedFile(
840
914
  codex_hook_manifest_source_path,
@@ -849,6 +923,8 @@ def _build_codex_hook_dependency_projection(
849
923
  config: MaterializerConfig,
850
924
  ) -> list[PlannedFile]:
851
925
  """Build the reviewed source files required by the target enforcer."""
926
+ if not _has_source_codex_enforcer(config):
927
+ return []
852
928
  all_dependencies: list[PlannedFile] = []
853
929
  for each_relative_path in codex_hook_dependency_manifest:
854
930
  source_path = _validated_source_file(
@@ -871,6 +947,16 @@ def _build_codex_hook_dependency_projection(
871
947
  return all_dependencies
872
948
 
873
949
 
950
+ def _has_source_codex_enforcer(config: MaterializerConfig) -> bool:
951
+ """Report whether hooks.json registers the enforcer."""
952
+ source_path = _find_codex_hook_source(config)
953
+ if source_path is None:
954
+ return False
955
+ source_manifest = _read_json_object(source_path, "source Codex hook manifest")
956
+ managed_command = _resolved_codex_enforcer_command(config)
957
+ return _source_codex_enforcer_hook(source_manifest, managed_command) is not None
958
+
959
+
874
960
  def discover_agents(config: MaterializerConfig) -> list[ClaudeAgent]:
875
961
  """Discover and parse Markdown agents below the source root.
876
962
 
@@ -1,8 +1,4 @@
1
- """Constants for resolving directories inside the installed shared tree.
2
-
3
- These name the shape of the installed tree itself, not any one worker or
4
- skill that reads it, so every caller of shared_tree_paths shares them.
5
- """
1
+ """Directory names for the installed shared tree."""
6
2
 
7
3
  from __future__ import annotations
8
4
 
@@ -15,3 +11,6 @@ SCRIPTS_DIRECTORY_NAME: str = "scripts"
15
11
  PROCESS_TREE_DIRECTORY_NAME: str = "process-tree"
16
12
 
17
13
  PROCESS_TREE_KILL_MODULE_FILENAME: str = "process_tree_kill.py"
14
+
15
+ AGENTS_DIRECTORY_SUFFIX: str = ".agents"
16
+ DEFAULT_MANAGED_ROOT_NAME: str = ".claude"
@@ -8,7 +8,7 @@ from collections.abc import Sequence
8
8
  from dataclasses import dataclass
9
9
  from pathlib import Path
10
10
 
11
- from skills_pr_loop_constants.durable_post_lint_constants import (
11
+ from durable_post_lint_config.config.constants import (
12
12
  ACTION_PR_CREATE,
13
13
  ACTION_PR_EDIT,
14
14
  ALL_BARE_VOLATILE_PATH_MARKERS,
@@ -16,6 +16,7 @@ from skills_pr_loop_constants.durable_post_lint_constants import (
16
16
  ALL_PATH_ANCHORED_VOLATILE_PATH_MARKERS,
17
17
  ALL_POST_ACTIONS,
18
18
  ALL_PR_DESCRIPTION_ACTIONS,
19
+ ALL_RELEASE_BODY_MARKERS,
19
20
  ALL_REQUIRED_PR_DESCRIPTION_HEADINGS,
20
21
  ALL_TITLE_ACTIONS,
21
22
  BODY_FILE_ENCODING,
@@ -35,6 +36,9 @@ from skills_pr_loop_constants.durable_post_lint_constants import (
35
36
  MISSING_HEADING_MESSAGE_TEMPLATE,
36
37
  PATH_ANCHOR_CHARACTER,
37
38
  PATH_SEGMENT_START_CHARACTERS,
39
+ RELEASE_BRANCH_PREFIX,
40
+ REWRITTEN_RELEASE_BODY_CODE,
41
+ REWRITTEN_RELEASE_BODY_MESSAGE,
38
42
  TITLE_NOT_ALLOWED_MESSAGE,
39
43
  TITLE_REQUIRED_MESSAGE,
40
44
  VOLATILE_PATH_CODE,
@@ -82,14 +86,7 @@ def _text_has_anchored_marker(normalized_text: str, marker: str) -> bool:
82
86
 
83
87
 
84
88
  def find_volatile_path_marker(body_text: str) -> str | None:
85
- """Return the first volatile path marker in a GitHub post body.
86
-
87
- Args:
88
- body_text: Post body text to scan.
89
-
90
- Returns:
91
- The matched marker, or None when the body names no volatile path.
92
- """
89
+ """Return the first volatile path marker in a GitHub post body."""
93
90
  normalized_text = body_text.replace("\\", PATH_ANCHOR_CHARACTER).lower()
94
91
  for each_marker in ALL_PATH_ANCHORED_VOLATILE_PATH_MARKERS:
95
92
  if _text_has_anchored_marker(normalized_text, each_marker):
@@ -101,17 +98,7 @@ def find_volatile_path_marker(body_text: str) -> str | None:
101
98
 
102
99
 
103
100
  def read_body_file(body_file: Path) -> str:
104
- """Read one UTF-8 body file without exposing its contents on failure.
105
-
106
- Args:
107
- body_file: Local post body file.
108
-
109
- Returns:
110
- Decoded body text.
111
-
112
- Raises:
113
- DurablePostInputError: The file is missing, unreadable, or invalid UTF-8.
114
- """
101
+ """Read one UTF-8 body file without exposing its contents on failure."""
115
102
  try:
116
103
  return body_file.read_text(encoding=BODY_FILE_ENCODING)
117
104
  except (OSError, UnicodeError) as error:
@@ -153,9 +140,25 @@ def _title_findings(title: str | None) -> list[DurablePostFinding]:
153
140
  return [DurablePostFinding(code=INVALID_TITLE_CODE, message=INVALID_TITLE_MESSAGE)]
154
141
 
155
142
 
143
+ def _is_release_automation_branch(head_branch: str | None) -> bool:
144
+ return head_branch is not None and head_branch.startswith(RELEASE_BRANCH_PREFIX)
145
+
146
+
147
+ def _release_body_findings(body_text: str) -> list[DurablePostFinding]:
148
+ if all(each_marker in body_text for each_marker in ALL_RELEASE_BODY_MARKERS):
149
+ return []
150
+ return [
151
+ DurablePostFinding(
152
+ code=REWRITTEN_RELEASE_BODY_CODE,
153
+ message=REWRITTEN_RELEASE_BODY_MESSAGE,
154
+ )
155
+ ]
156
+
157
+
156
158
  def _body_findings(
157
159
  action: str,
158
160
  body_text: str | None,
161
+ head_branch: str | None = None,
159
162
  ) -> list[DurablePostFinding]:
160
163
  if body_text is None:
161
164
  return []
@@ -167,7 +170,9 @@ def _body_findings(
167
170
  message=BODY_MUST_NOT_BE_EMPTY_MESSAGE,
168
171
  )
169
172
  )
170
- if action in ALL_PR_DESCRIPTION_ACTIONS:
173
+ if _is_release_automation_branch(head_branch):
174
+ all_findings.extend(_release_body_findings(body_text))
175
+ elif action in ALL_PR_DESCRIPTION_ACTIONS:
171
176
  all_findings.extend(_description_heading_findings(body_text))
172
177
  if find_volatile_path_marker(body_text) is not None:
173
178
  all_findings.append(
@@ -183,22 +188,14 @@ def lint_durable_post(
183
188
  action: str,
184
189
  title: str | None,
185
190
  body_text: str | None,
191
+ head_branch: str | None = None,
186
192
  ) -> tuple[DurablePostFinding, ...]:
187
- """Return content findings for one locally valid GitHub post request.
188
-
189
- Args:
190
- action: GitHub post action name.
191
- title: Pull request title when the action accepts one.
192
- body_text: Decoded body text when the action accepts a body.
193
-
194
- Returns:
195
- Content findings in stable rule order.
196
-
197
- Raises:
198
- DurablePostUsageError: The action and supplied fields are not a valid request.
199
- """
193
+ """Return content findings for one locally valid GitHub post request."""
200
194
  _validate_request_shape(action, title, body_text)
201
- return (*_title_findings(title), *_body_findings(action, body_text))
195
+ return (
196
+ *_title_findings(title),
197
+ *_body_findings(action, body_text, head_branch),
198
+ )
202
199
 
203
200
 
204
201
  def _parse_arguments(all_arguments: Sequence[str]) -> argparse.Namespace:
@@ -206,18 +203,12 @@ def _parse_arguments(all_arguments: Sequence[str]) -> argparse.Namespace:
206
203
  parser.add_argument("--action", required=True)
207
204
  parser.add_argument("--title")
208
205
  parser.add_argument("--body-file", type=Path)
206
+ parser.add_argument("--head-branch")
209
207
  return parser.parse_args(list(all_arguments))
210
208
 
211
209
 
212
210
  def main(all_arguments: Sequence[str]) -> int:
213
- """Validate one GitHub post and return its result status.
214
-
215
- Args:
216
- all_arguments: Command arguments after the script name.
217
-
218
- Returns:
219
- Zero when clean, one for content findings, or two for invalid input.
220
- """
211
+ """Validate one GitHub post and return its result status."""
221
212
  arguments = _parse_arguments(all_arguments)
222
213
  try:
223
214
  body_text = (
@@ -229,6 +220,7 @@ def main(all_arguments: Sequence[str]) -> int:
229
220
  action=arguments.action,
230
221
  title=arguments.title,
231
222
  body_text=body_text,
223
+ head_branch=arguments.head_branch,
232
224
  )
233
225
  except (DurablePostInputError, DurablePostUsageError) as error:
234
226
  sys.stderr.write(f"{error}\n")
@@ -23,7 +23,6 @@ ALL_POST_ACTIONS: frozenset[str] = frozenset(
23
23
  ACTION_PR_REVIEW,
24
24
  }
25
25
  )
26
-
27
26
  ALL_BODY_REQUIRED_ACTIONS: frozenset[str] = frozenset(
28
27
  {
29
28
  ACTION_GITHUB_MCP_POST,
@@ -35,13 +34,10 @@ ALL_BODY_REQUIRED_ACTIONS: frozenset[str] = frozenset(
35
34
  ACTION_PR_REVIEW,
36
35
  }
37
36
  )
38
-
39
37
  ALL_PR_DESCRIPTION_ACTIONS: frozenset[str] = frozenset(
40
38
  {ACTION_PR_CREATE, ACTION_PR_EDIT}
41
39
  )
42
-
43
40
  ALL_TITLE_ACTIONS: frozenset[str] = frozenset({ACTION_PR_CREATE, ACTION_PR_EDIT})
44
-
45
41
  ALL_CONVENTIONAL_TITLE_TYPES: tuple[str, ...] = (
46
42
  "build",
47
43
  "chore",
@@ -55,11 +51,9 @@ ALL_CONVENTIONAL_TITLE_TYPES: tuple[str, ...] = (
55
51
  "style",
56
52
  "test",
57
53
  )
58
-
59
54
  CONVENTIONAL_TITLE_PATTERN: re.Pattern[str] = re.compile(
60
55
  rf"^(?:{'|'.join(ALL_CONVENTIONAL_TITLE_TYPES)})(?:\([^)\r\n]+\))?!?: [^\s].*$"
61
56
  )
62
-
63
57
  ALL_REQUIRED_PR_DESCRIPTION_HEADINGS: tuple[str, ...] = (
64
58
  "Summary",
65
59
  "Description",
@@ -67,12 +61,10 @@ ALL_REQUIRED_PR_DESCRIPTION_HEADINGS: tuple[str, ...] = (
67
61
  "How",
68
62
  "Verification",
69
63
  )
70
-
71
64
  ALL_PATH_ANCHORED_VOLATILE_PATH_MARKERS: tuple[str, ...] = (
72
65
  ".claude-profile-a/jobs/",
73
66
  ".claude/worktrees/",
74
67
  )
75
-
76
68
  ALL_BARE_VOLATILE_PATH_MARKERS: tuple[str, ...] = (
77
69
  "appdata/local/temp",
78
70
  "/tmp/",
@@ -80,7 +72,6 @@ ALL_BARE_VOLATILE_PATH_MARKERS: tuple[str, ...] = (
80
72
  "$env:temp",
81
73
  "$claude_job_dir",
82
74
  )
83
-
84
75
  BODY_FILE_ENCODING = "utf-8"
85
76
  CLEAN_EXIT_CODE = 0
86
77
  CONTENT_FINDING_EXIT_CODE = 1
@@ -88,7 +79,6 @@ EMPTY_BODY_CODE = "empty-body"
88
79
  INPUT_ERROR_EXIT_CODE = 2
89
80
  PATH_ANCHOR_CHARACTER = "/"
90
81
  PATH_SEGMENT_START_CHARACTERS = "_-"
91
-
92
82
  BODY_FILE_UNREADABLE_MESSAGE = "body file is not readable UTF-8 text"
93
83
  BODY_REQUIRED_MESSAGE = "this action requires a body file"
94
84
  BODY_MUST_NOT_BE_EMPTY_MESSAGE = "body file must contain text"
@@ -104,3 +94,13 @@ TITLE_NOT_ALLOWED_MESSAGE = "this action does not accept a title"
104
94
  TITLE_REQUIRED_MESSAGE = "pr-create requires a title"
105
95
  VOLATILE_PATH_CODE = "volatile-local-path"
106
96
  VOLATILE_PATH_MESSAGE = "body contains a volatile local artifact path"
97
+ RELEASE_BRANCH_PREFIX = "release-please--branches--"
98
+ ALL_RELEASE_BODY_MARKERS: tuple[str, ...] = (
99
+ ":robot: I have created a release",
100
+ "This PR was generated with [Release Please]",
101
+ )
102
+ REWRITTEN_RELEASE_BODY_CODE = "rewritten-release-body"
103
+ REWRITTEN_RELEASE_BODY_MESSAGE = (
104
+ "release automation reads this body back to recognize its own merge; "
105
+ "keep the generated text whole"
106
+ )
@@ -1,9 +1,11 @@
1
1
  """Tests for durable GitHub post linter constants."""
2
2
 
3
- from skills_pr_loop_constants.durable_post_lint_constants import (
3
+ from durable_post_lint_config.config.constants import (
4
4
  ALL_CONVENTIONAL_TITLE_TYPES,
5
5
  ALL_POST_ACTIONS,
6
+ ALL_RELEASE_BODY_MARKERS,
6
7
  CONVENTIONAL_TITLE_PATTERN,
8
+ RELEASE_BRANCH_PREFIX,
7
9
  )
8
10
 
9
11
 
@@ -23,3 +25,14 @@ def test_action_inventory_covers_pull_request_issue_and_tool_posts() -> None:
23
25
  def test_title_pattern_uses_every_configured_type() -> None:
24
26
  for each_title_type in ALL_CONVENTIONAL_TITLE_TYPES:
25
27
  assert CONVENTIONAL_TITLE_PATTERN.fullmatch(f"{each_title_type}: one change")
28
+
29
+
30
+ def should_carry_both_markers_release_automation_writes() -> None:
31
+ assert ALL_RELEASE_BODY_MARKERS == (
32
+ ":robot: I have created a release",
33
+ "This PR was generated with [Release Please]",
34
+ )
35
+
36
+
37
+ def should_name_the_branch_prefix_release_automation_pushes() -> None:
38
+ assert RELEASE_BRANCH_PREFIX == "release-please--branches--"