claude-dev-env 2.4.0 → 2.7.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 (309) hide show
  1. package/CLAUDE.md +26 -59
  2. package/_shared/pr-loop/scripts/_claude_permissions_common.py +84 -0
  3. package/_shared/pr-loop/scripts/code_rules_gate.py +6 -3
  4. package/_shared/pr-loop/scripts/code_rules_gate_parts/CLAUDE.md +12 -2
  5. package/_shared/pr-loop/scripts/code_rules_gate_parts/baseline_import_isolation.py +309 -0
  6. package/_shared/pr-loop/scripts/code_rules_gate_parts/staged_test_regression.py +540 -0
  7. package/_shared/pr-loop/scripts/code_rules_gate_parts/staged_test_running.py +206 -70
  8. package/_shared/pr-loop/scripts/code_rules_gate_parts/tests/__init__.py +1 -0
  9. package/_shared/pr-loop/scripts/code_rules_gate_parts/tests/_repo_test_helpers.py +76 -0
  10. package/_shared/pr-loop/scripts/code_rules_gate_parts/tests/test_baseline_import_isolation.py +248 -0
  11. package/_shared/pr-loop/scripts/code_rules_gate_parts/tests/test_staged_test_regression.py +309 -0
  12. package/_shared/pr-loop/scripts/code_rules_gate_parts/tests/test_staged_test_running.py +91 -58
  13. package/_shared/pr-loop/scripts/grant_project_claude_permissions.py +306 -306
  14. package/_shared/pr-loop/scripts/pr_loop_shared_constants/claude_permissions_constants.py +44 -0
  15. package/_shared/pr-loop/scripts/pr_loop_shared_constants/code_rules_gate_constants.py +202 -0
  16. package/_shared/pr-loop/scripts/pr_loop_shared_constants/copilot_quota_constants.py +24 -24
  17. package/_shared/pr-loop/scripts/pr_loop_shared_constants/stale_worktree_rule_sweep_constants.py +107 -107
  18. package/_shared/pr-loop/scripts/revoke_project_claude_permissions.py +290 -48
  19. package/_shared/pr-loop/scripts/tests/test_claude_permissions_common.py +42 -2
  20. package/_shared/pr-loop/scripts/tests/test_claude_permissions_constants.py +36 -0
  21. package/_shared/pr-loop/scripts/tests/test_code_rules_gate.py +100 -1
  22. package/_shared/pr-loop/scripts/tests/test_fix_hookspath.py +497 -497
  23. package/_shared/pr-loop/scripts/tests/test_revoke_project_claude_permissions.py +311 -2
  24. package/_shared/pr-loop/scripts/tests/test_stale_worktree_rule_sweep.py +301 -301
  25. package/_shared/pr-loop/scripts/tests/test_stale_worktree_rule_sweep_constants.py +85 -85
  26. package/_shared/pr-loop/worker-spawn.md +1 -1
  27. package/agents/CLAUDE.md +3 -2
  28. package/agents/caveman.md +0 -1
  29. package/agents/clasp-deployment-orchestrator.md +0 -1
  30. package/agents/clean-coder.md +0 -1
  31. package/agents/code-advisor.md +0 -1
  32. package/agents/code-quality-agent.md +1 -2
  33. package/agents/code-verifier.md +36 -8
  34. package/agents/deep-research.md +0 -1
  35. package/agents/docs-agent.md +0 -1
  36. package/agents/git-commit-crafter.md +0 -1
  37. package/agents/issue-tracker.md +42 -0
  38. package/agents/plan-packet-validator.md +0 -1
  39. package/agents/pr-description-writer.md +0 -1
  40. package/agents/test_agent_frontmatter.py +67 -18
  41. package/audit-rubrics/category_rubrics/category-o-docstring-vs-impl-drift.md +143 -141
  42. package/bin/CLAUDE.md +68 -5
  43. package/bin/codex-compat.mjs +104 -0
  44. package/bin/codex-compat.test.mjs +51 -0
  45. package/bin/ever-shipped-skills.mjs +1 -0
  46. package/bin/install-constants.mjs +88 -0
  47. package/bin/install.mjs +1138 -114
  48. package/bin/install.prune.test.mjs +869 -19
  49. package/bin/install.test.mjs +906 -2
  50. package/codex-capability-map.json +13 -0
  51. package/commands/implement.md +1 -1
  52. package/commands/right-size.md +1 -1
  53. package/docs/CLAUDE.md +1 -0
  54. package/docs/CODE_RULES.md +2 -0
  55. package/docs/codex-compatibility.md +25 -0
  56. package/docs/host-pool-health-monitor.md +102 -0
  57. package/docs/nas-ssh-invocation.md +96 -12
  58. package/docs/references/CLAUDE.md +4 -2
  59. package/docs/references/advisor-tool.md +13 -0
  60. package/docs/references/code-review-enforcement.md +35 -0
  61. package/docs/references/team-advisor-skill.md +14 -0
  62. package/hooks/blocking/CLAUDE.md +4 -0
  63. package/hooks/blocking/code_review_pr_create_gate.py +7 -3
  64. package/hooks/blocking/code_review_push_gate.py +9 -4
  65. package/hooks/blocking/code_review_stamp_directory_write_blocker.py +8 -0
  66. package/hooks/blocking/config/__init__.py +5 -5
  67. package/hooks/blocking/config/code_review_enforcement_constants.py +40 -7
  68. package/hooks/blocking/config/test_code_review_enforcement_constants.py +58 -0
  69. package/hooks/blocking/config/verified_commit_constants.py +160 -159
  70. package/hooks/blocking/eli11_reply_enforcer.py +479 -0
  71. package/hooks/blocking/gh_body_arg_blocker.py +1 -1
  72. package/hooks/blocking/nas_ssh_binary_enforcer.py +8 -46
  73. package/hooks/blocking/orchestrator_refresh_reschedule_gate.py +256 -0
  74. package/hooks/blocking/pre_tool_use_dispatcher.py +24 -24
  75. package/hooks/blocking/shell_substitution_blocker.py +129 -0
  76. package/hooks/blocking/state_description_blocker.py +1 -1
  77. package/hooks/blocking/stop_dispatcher.py +1 -1
  78. package/hooks/blocking/test_bash_pre_tool_use_dispatcher.py +2 -3
  79. package/hooks/blocking/test_code_review_pr_create_gate.py +14 -0
  80. package/hooks/blocking/test_code_review_push_gate.py +16 -0
  81. package/hooks/blocking/test_code_review_stamp_directory_write_blocker.py +19 -0
  82. package/hooks/blocking/test_eli11_reply_enforcer.py +457 -0
  83. package/hooks/blocking/test_orchestrator_refresh_reschedule_gate.py +231 -0
  84. package/hooks/blocking/test_pre_tool_use_dispatcher.py +10 -1
  85. package/hooks/blocking/test_shell_substitution_blocker.py +124 -0
  86. package/hooks/blocking/test_stop_dispatcher.py +23 -0
  87. package/hooks/blocking/test_unscoped_search_blocker.py +102 -0
  88. package/hooks/blocking/test_verdict_directory_write_blocker.py +804 -808
  89. package/hooks/blocking/test_verification_verdict_store.py +54 -0
  90. package/hooks/blocking/test_verified_commit_gate.py +581 -581
  91. package/hooks/blocking/test_verified_commit_message_accuracy_blocker.py +131 -131
  92. package/hooks/blocking/unscoped_search_blocker.py +391 -0
  93. package/hooks/blocking/verdict_directory_write_blocker.py +687 -687
  94. package/hooks/blocking/verification_verdict_store.py +1039 -1036
  95. package/hooks/blocking/verified_commit_message_accuracy_blocker.py +167 -167
  96. package/hooks/blocking/verifier_verdict_minter.py +280 -280
  97. package/hooks/git-hooks/CLAUDE.md +3 -0
  98. package/hooks/git-hooks/conftest.py +30 -0
  99. package/hooks/git-hooks/gate_utils.py +2 -2
  100. package/hooks/git-hooks/git_hooks_constants/__init__.py +41 -2
  101. package/hooks/git-hooks/pre_push.py +75 -4
  102. package/hooks/git-hooks/pre_push_base_reference.py +166 -0
  103. package/hooks/git-hooks/test_config.py +0 -15
  104. package/hooks/git-hooks/test_gate_utils.py +3 -15
  105. package/hooks/git-hooks/test_pre_commit.py +1 -15
  106. package/hooks/git-hooks/test_pre_push.py +257 -23
  107. package/hooks/git-hooks/test_pre_push_base_reference.py +339 -0
  108. package/hooks/hooks.json +10 -12
  109. package/hooks/hooks_constants/CLAUDE.md +7 -2
  110. package/hooks/hooks_constants/bash_pre_tool_use_dispatcher_constants.py +4 -4
  111. package/hooks/hooks_constants/eli11_reply_enforcer_constants.py +101 -0
  112. package/hooks/hooks_constants/enter_worktree_prefetch_constants.py +18 -18
  113. package/hooks/hooks_constants/nas_ssh_binary_enforcer_constants.py +2 -8
  114. package/hooks/hooks_constants/orchestrator_refresh_reschedule_gate_constants.py +48 -0
  115. package/hooks/hooks_constants/ruff_integration_constants.py +16 -0
  116. package/hooks/hooks_constants/shell_command_segments.py +82 -0
  117. package/hooks/hooks_constants/shell_substitution_blocker_constants.py +67 -0
  118. package/hooks/hooks_constants/stop_dispatcher_constants.py +1 -0
  119. package/hooks/hooks_constants/test_bash_pre_tool_use_dispatcher_constants.py +5 -6
  120. package/hooks/hooks_constants/test_stop_dispatcher_constants.py +1 -0
  121. package/hooks/hooks_constants/unscoped_search_blocker_constants.py +153 -0
  122. package/hooks/lifecycle/enter_worktree_origin_prefetch.py +163 -146
  123. package/hooks/lifecycle/test_enter_worktree_origin_prefetch.py +185 -178
  124. package/hooks/pyproject.toml +1 -0
  125. package/hooks/validators/CLAUDE.md +1 -0
  126. package/hooks/validators/config/__init__.py +0 -0
  127. package/hooks/validators/config/directory_exemption_constants.py +183 -0
  128. package/hooks/validators/config/test_directory_exemption_constants.py +21 -0
  129. package/hooks/validators/conftest.py +4 -0
  130. package/hooks/validators/ruff_integration.py +49 -5
  131. package/hooks/validators/run_all_validators.py +206 -9
  132. package/hooks/validators/test_directory_exemption_constants.py +185 -0
  133. package/hooks/validators/test_python_antipattern_checks.py +110 -5
  134. package/hooks/validators/test_ruff_integration.py +92 -1
  135. package/hooks/validators/test_run_all_validators.py +115 -68
  136. package/hooks/validators/test_run_all_validators_pretooluse.py +159 -1
  137. package/package.json +13 -3
  138. package/rules/CLAUDE.md +17 -22
  139. package/rules/agent-spawn-protocol.md +6 -6
  140. package/rules/anti-corollary-tests.md +1 -1
  141. package/rules/bdd.md +1 -1
  142. package/rules/cleanup-temp-files.md +10 -4
  143. package/rules/code-standards.md +7 -0
  144. package/rules/conservative-action.md +1 -5
  145. package/rules/context7.md +0 -4
  146. package/rules/destructive-commands.md +47 -0
  147. package/rules/doc-inventory-integrity.md +48 -0
  148. package/rules/doc-prose-cuts.md +58 -0
  149. package/rules/docstring-prose-matches-implementation.md +53 -44
  150. package/rules/durable-post-artifacts.md +0 -4
  151. package/rules/eli11-replies.md +31 -0
  152. package/rules/explore-thoroughly.md +4 -4
  153. package/rules/falsify-before-green.md +68 -0
  154. package/rules/file-global-constants.md +1 -1
  155. package/rules/filesystem-search.md +51 -0
  156. package/rules/gh-cli-conventions.md +27 -0
  157. package/rules/git-workflow.md +26 -0
  158. package/rules/hedging-claims.md +9 -0
  159. package/rules/long-horizon-autonomy.md +0 -4
  160. package/rules/measurement-denominators.md +48 -0
  161. package/rules/nas-ssh-invocation.md +23 -5
  162. package/rules/parallel-tools.md +2 -2
  163. package/rules/plain-illustrative-docstrings.md +3 -7
  164. package/rules/plain-language.md +2 -0
  165. package/rules/proof-of-work-pr-comments.md +0 -4
  166. package/rules/re-stage-before-commit.md +2 -0
  167. package/rules/research-mode.md +10 -0
  168. package/rules/shell-invocation.md +21 -0
  169. package/rules/testing.md +4 -0
  170. package/rules/verified-commit-gate-skip.md +3 -27
  171. package/rules/verify-before-asking.md +5 -0
  172. package/rules/windows-filesystem-safe.md +1 -1
  173. package/rules/workers-done-before-complete.md +4 -0
  174. package/scripts/CLAUDE.md +1 -0
  175. package/scripts/Capture-PoolHealth.ps1 +410 -0
  176. package/scripts/Migrate-ShellPolicy.ps1 +1 -1
  177. package/scripts/_code_review_test_support.py +404 -0
  178. package/scripts/claude_chain_runner.py +141 -1
  179. package/scripts/codex_capability_bridge.py +171 -0
  180. package/scripts/codex_compat_materializer.py +1087 -0
  181. package/scripts/codex_compat_watcher.py +502 -0
  182. package/scripts/conftest.py +16 -1
  183. package/scripts/dev_env_scripts_constants/CLAUDE.md +1 -1
  184. package/scripts/dev_env_scripts_constants/claude_chain_constants.py +9 -0
  185. package/scripts/dev_env_scripts_constants/code_review_constants.py +37 -0
  186. package/scripts/invoke_code_review.py +11 -4
  187. package/scripts/resolve_worker_spawn.py +626 -626
  188. package/scripts/spawn_grok_batch.py +672 -672
  189. package/scripts/sync_to_cursor/rules.py +0 -10
  190. package/scripts/test_claude_chain_runner.py +131 -0
  191. package/scripts/test_invoke_code_review.py +85 -908
  192. package/scripts/test_invoke_code_review_chain.py +70 -0
  193. package/scripts/test_invoke_code_review_cli.py +192 -0
  194. package/scripts/test_invoke_code_review_contract.py +256 -0
  195. package/scripts/test_invoke_code_review_git.py +123 -0
  196. package/scripts/test_invoke_code_review_mode.py +99 -0
  197. package/scripts/test_resolve_worker_spawn.py +1014 -1014
  198. package/scripts/tests/test_code_review_constants.py +80 -0
  199. package/scripts/tests/test_codex_capability_bridge.py +91 -0
  200. package/scripts/tests/test_codex_compat_materializer.py +632 -0
  201. package/scripts/tests/test_codex_compat_watcher.py +599 -0
  202. package/scripts/tests/test_sync_to_cursor.py +0 -1
  203. package/skills/CLAUDE.md +2 -0
  204. package/skills/auditing-claude-config/SKILL.md +114 -114
  205. package/skills/autoconverge/SKILL.md +427 -427
  206. package/skills/autoconverge/reference/convergence.md +24 -3
  207. package/skills/autoconverge/workflow/CLAUDE.md +1 -0
  208. package/skills/autoconverge/workflow/converge.clean-audit.test.mjs +3 -3
  209. package/skills/autoconverge/workflow/converge.contract.test.mjs +1263 -1263
  210. package/skills/autoconverge/workflow/converge.mjs +168 -1
  211. package/skills/autoconverge/workflow/converge.p2-advance.test.mjs +202 -0
  212. package/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a11d903476b803493.jsonl +2 -2
  213. package/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a26213978adeef6fb.jsonl +2 -2
  214. package/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a3def0d15ed9d9110.jsonl +2 -2
  215. package/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a41f41b1b708ee3b7.jsonl +2 -2
  216. package/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a758b880abecc3ff7.jsonl +2 -2
  217. package/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a8897b89656b1bd16.jsonl +2 -2
  218. package/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-abd463d744a1437bc.jsonl +2 -2
  219. package/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-ad19d027ae8ee1816.jsonl +2 -2
  220. package/skills/autoconverge/workflow/fixtures/wf_run/workflows/wf_881252e6-700.json +265 -265
  221. package/skills/bugteam/reference/copilot-gap-analysis.md +1 -1
  222. package/skills/closeout/SKILL.md +33 -50
  223. package/skills/codex-review/scripts/codex_review_scripts_constants/run_constants.py +8 -0
  224. package/skills/codex-review/scripts/run_codex_review.py +233 -1
  225. package/skills/codex-review/scripts/test_run_codex_review.py +189 -0
  226. package/skills/condensing-instructions/SKILL.md +72 -0
  227. package/skills/copilot-review/SKILL.md +119 -119
  228. package/skills/e-code-review/SKILL.md +52 -0
  229. package/skills/e-code-review/reference/fix.md +54 -0
  230. package/skills/e-code-review/reference/loop.md +43 -0
  231. package/skills/e-code-review/reference/low.md +57 -0
  232. package/skills/e-code-review/reference/medium.md +153 -0
  233. package/skills/e-code-review/reference/xhigh.md +182 -0
  234. package/skills/e-simplify/SKILL.md +97 -0
  235. package/skills/fresh-branch/CLAUDE.md +1 -1
  236. package/skills/fresh-branch/SKILL.md +5 -6
  237. package/skills/fresh-branch/scripts/create_fresh_branch.py +42 -24
  238. package/skills/fresh-branch/scripts/fresh_branch_scripts_constants/fresh_branch_cli_constants.py +1 -3
  239. package/skills/fresh-branch/scripts/test_create_fresh_branch.py +30 -126
  240. package/skills/issue-tracker/SKILL.md +92 -0
  241. package/skills/issue-tracker/reference/epic-and-sub-issue-model.md +55 -0
  242. package/skills/issue-tracker/reference/handoff-schema.md +64 -0
  243. package/skills/issue-tracker/reference/operation-matrix.md +41 -0
  244. package/skills/orchestrator/SKILL.md +177 -22
  245. package/skills/orchestrator/scripts/status_gate.py +625 -0
  246. package/skills/orchestrator/scripts/status_gate_constants/__init__.py +1 -0
  247. package/skills/orchestrator/scripts/status_gate_constants/config/__init__.py +1 -0
  248. package/skills/orchestrator/scripts/status_gate_constants/config/constants.py +47 -0
  249. package/skills/orchestrator/scripts/test_status_gate.py +439 -0
  250. package/skills/orchestrator-refresh/SKILL.md +129 -35
  251. package/skills/plan-to-pr/SKILL.md +155 -0
  252. package/skills/plan-to-pr/reference/final-validation-tasks.md +15 -0
  253. package/skills/plan-to-pr/reference/model-routing.md +36 -0
  254. package/skills/plan-to-pr/reference/packet-contract.md +43 -0
  255. package/skills/plan-to-pr/reference/packet-schema.json +57 -0
  256. package/skills/plan-to-pr/reference/process-inventory.md +22 -0
  257. package/skills/plan-to-pr/reference/review-loop.md +33 -0
  258. package/skills/plan-to-pr/reference/run-record.schema.json +27 -0
  259. package/skills/plan-to-pr/reference/self-audit-tasks.md +15 -0
  260. package/skills/plan-to-pr/reference/task-seeds.md +14 -0
  261. package/skills/plan-to-pr/reference/task-ticket.md +38 -0
  262. package/skills/plan-to-pr/scripts/config/__init__.py +1 -0
  263. package/skills/plan-to-pr/scripts/config/constants.py +193 -0
  264. package/skills/plan-to-pr/scripts/create_packet.py +173 -0
  265. package/skills/plan-to-pr/scripts/test_create_packet.py +102 -0
  266. package/skills/plan-to-pr/scripts/test_validate_packet.py +256 -0
  267. package/skills/plan-to-pr/scripts/test_validate_protocol.py +135 -0
  268. package/skills/plan-to-pr/scripts/test_validate_run.py +158 -0
  269. package/skills/plan-to-pr/scripts/validate_packet.py +655 -0
  270. package/skills/plan-to-pr/scripts/validate_protocol.py +622 -0
  271. package/skills/plan-to-pr/scripts/validate_run.py +173 -0
  272. package/skills/plan-to-pr/test_skill_contract.py +207 -0
  273. package/skills/plan-to-pr/test_task_ticket_contract.py +151 -0
  274. package/skills/pr-converge/SKILL.md +472 -469
  275. package/skills/pr-converge/reference/examples.md +3 -3
  276. package/skills/pr-converge/reference/fix-protocol.md +1 -1
  277. package/skills/pr-converge/reference/ground-rules.md +7 -4
  278. package/skills/pr-converge/reference/multi-pr-orchestration.md +4 -1
  279. package/skills/pr-converge/reference/per-tick.md +5 -5
  280. package/skills/pr-converge/reference/progress-checklist.md +1 -1
  281. package/skills/pr-converge/scripts/check_convergence_gates.py +279 -279
  282. package/skills/pr-converge/scripts/test_check_convergence_codex.py +507 -507
  283. package/skills/pr-converge/scripts/test_check_convergence_gates.py +84 -84
  284. package/skills/pr-converge/test_step5_host_branch.py +1 -1
  285. package/skills/pr-fix-protocol/SKILL.md +1 -1
  286. package/skills/privacy-hygiene/SKILL.md +68 -68
  287. package/skills/privacy-hygiene/reference/sweep-procedure.md +1 -1
  288. package/skills/prototype/workflows/promotion.md +1 -1
  289. package/skills/release-notes-html/SKILL.md +164 -0
  290. package/skills/session-log/SKILL.md +1 -1
  291. package/skills/task-build/CLAUDE.md +8 -7
  292. package/skills/task-build/SKILL.md +16 -8
  293. package/skills/task-build/reference/tool-routing.md +19 -0
  294. package/rules/claude-md-orphan-file.md +0 -28
  295. package/rules/cleanup-command-forms.md +0 -23
  296. package/rules/code-reviews.md +0 -11
  297. package/rules/env-var-table-code-drift.md +0 -10
  298. package/rules/gh-body-file.md +0 -5
  299. package/rules/gh-paginate.md +0 -3
  300. package/rules/hook-prose-matches-detector.md +0 -15
  301. package/rules/no-historical-clutter.md +0 -26
  302. package/rules/no-inline-destructive-literals.md +0 -9
  303. package/rules/no-justification-noise.md +0 -61
  304. package/rules/package-inventory-stale-entry.md +0 -25
  305. package/rules/right-sized-engineering.md +0 -28
  306. package/rules/self-contained-docs.md +0 -17
  307. package/rules/shell-invocation-policy.md +0 -5
  308. package/rules/tdd.md +0 -7
  309. package/skills/closeout/reference/issue-body-templates.md +0 -108
@@ -14,4 +14,4 @@ In Node, call `mkdirSync(targetPath, { recursive: true })` on possibly-existing
14
14
 
15
15
  The `windows_rmtree_blocker.py` PreToolUse hook (Write/Edit/Bash) blocks the unsafe rmtree pattern and returns the full `force_rmtree` safe-pattern code.
16
16
 
17
- Define the safe handler trio (`_strip_read_only_and_retry`, `_force_remove_tree` / `force_rmtree`, and the `inspect.signature` onexc/onerror guard) once in a shared Windows-filesystem utility module, and import it from every call site. A second local copy drifts from the first — a fix lands in one and the other keeps the bug (CODE_RULES.md section 3, Reuse before create). The `duplicate_rmtree_helper_blocker.py` PreToolUse hook (Write/Edit) blocks a local re-definition of any trio member outside the shared home and points the writer at the import. This complements the same-directory `check_duplicate_function_body_across_files` gate, which a copy between two distant packages slips past.
17
+ Define the safe handler trio (`_strip_read_only_and_retry`, `_force_remove_tree` / `force_rmtree`, and the `inspect.signature` onexc/onerror guard) once in a shared Windows-filesystem utility module, and import it from every call site. A second local copy drifts from the first — a fix lands in one and the other keeps the bug (CODE_RULES.md, CORE PRINCIPLES — "Reuse before create"). The `duplicate_rmtree_helper_blocker.py` PreToolUse hook (Write/Edit) blocks a local re-definition of any trio member outside the shared home and points the writer at the import. This complements the same-directory `check_duplicate_function_body_across_files` gate, which a copy between two distant packages slips past.
@@ -2,4 +2,8 @@
2
2
 
3
3
  Before marking a task `completed` that spawned workers — subagents, workflow agents, or background shells — confirm both: every worker has finished, and each worker's result is merged into run state (`state.json`, `pr-converge-state.json`, the task list, or whatever record the task keeps). A worker still running, or one whose output never landed in run state, keeps the task `in_progress`: list the live workers, report any dead or hung one as a finding rather than dropping it in silence, and schedule a wakeup so the run picks the workers back up before the task closes.
4
4
 
5
+ This rule gates a task's status, not your own work. It never says wait before acting: keep working while a worker runs, and hold only the `completed` mark until the worker's result has landed.
6
+
7
+ Verify every sub-agent file list, count, description, and finding against the repository and the diff before you merge it into run state or repeat it to the user.
8
+
5
9
  Checklist, examples, and run-state detail: `@~/.claude/docs/worker-completion-gate.md`.
package/scripts/CLAUDE.md CHANGED
@@ -27,6 +27,7 @@ Utility scripts installed into `~/.claude/scripts/` by `bin/install.mjs`. Each s
27
27
  | `check.ps1` | Runs the full code-quality check suite |
28
28
  | `Show-Asset.ps1` | Opens files on screen, sizing each image window to the image's pixel dimensions (scaled to fit the screen); non-image files open in their default application |
29
29
  | `Get-SessionAccount.ps1` | Reports which Claude account the current session is actually logged into by comparing `~/.claude.json`'s CLI login against a `CLAUDE_USER_DATA_DIR` desktop profile's `lastKnownAccountUuid`, recovering the desktop account's email from profile storage when the two accounts differ |
30
+ | `Capture-PoolHealth.ps1` | Captures Windows memory pool counters, high-handle processes, and kernel pool tags (via `NtQuerySystemInformation` class 22), prints a threshold verdict with a remediation map, and exits non-zero when any alert threshold fires |
30
31
 
31
32
  ## Subdirectories
32
33
 
@@ -0,0 +1,410 @@
1
+ <#
2
+ .SYNOPSIS
3
+ Captures Windows pool counters, handle pressure, and kernel pool tags for host health checks.
4
+
5
+ .DESCRIPTION
6
+ Reads memory pool counters, total handle/thread counts, processes over the handle alert
7
+ threshold, and top kernel pool tags via NtQuerySystemInformation (class 22). Prints a
8
+ threshold verdict so an operator can re-run the same recipe from a clean shell.
9
+
10
+ Alert thresholds (defaults):
11
+ - Pool Nonpaged Bytes > 2 GB
12
+ - Any process Handles > 2000
13
+ - Process(_Total) handles > 500000
14
+
15
+ Attribution context (evidence pack results/04-pool-tags.md): dominant tags File (nonpaged)
16
+ and Toke (paged) mean process-object / object-manager pressure. Remediate via RC2 (MCP
17
+ lifecycle), RC3 (Show-Asset orphans), RC4 (Git find handle storms) — not a single driver.
18
+
19
+ .PARAMETER TopTagCount
20
+ How many pool tags to print per nonpaged and paged ranking. Default 20.
21
+
22
+ .PARAMETER TopProcessCount
23
+ How many high-handle processes to list. Default 15.
24
+
25
+ .PARAMETER OutPath
26
+ Optional file path. When set, the full report is also written there as UTF-8 text.
27
+
28
+ .PARAMETER NonpagedAlertBytes
29
+ Nonpaged pool alert threshold in bytes. Default 2147483648 (2 GB).
30
+
31
+ .PARAMETER ProcessHandleAlert
32
+ Per-process handle alert threshold. Default 2000.
33
+
34
+ .PARAMETER TotalHandleAlert
35
+ System-wide handle alert threshold. Default 500000.
36
+
37
+ .EXAMPLE
38
+ pwsh -NoProfile -File "$HOME\.claude\scripts\Capture-PoolHealth.ps1"
39
+
40
+ .EXAMPLE
41
+ pwsh -NoProfile -File .\Capture-PoolHealth.ps1 -OutPath "$env:TEMP\pool-health.txt"
42
+ #>
43
+ [CmdletBinding()]
44
+ param(
45
+ [int]$TopTagCount = 20,
46
+ [int]$TopProcessCount = 15,
47
+ [string]$OutPath = '',
48
+ [long]$NonpagedAlertBytes = 2147483648,
49
+ [int]$ProcessHandleAlert = 2000,
50
+ [int]$TotalHandleAlert = 500000
51
+ )
52
+
53
+ Set-StrictMode -Version Latest
54
+ $ErrorActionPreference = 'Stop'
55
+
56
+ $script:ReportLines = [System.Collections.Generic.List[string]]::new()
57
+
58
+ function Write-ReportLine {
59
+ param([string]$Text = '')
60
+ $script:ReportLines.Add($Text)
61
+ Write-Output $Text
62
+ }
63
+
64
+ function Format-BytesAsGigabytes {
65
+ param([long]$ByteCount)
66
+ return ('{0:N3} GB' -f ($ByteCount / 1GB))
67
+ }
68
+
69
+ function Get-MemoryAndHandleCounters {
70
+ # One source of truth for the counters: request order and lookup key both
71
+ # derive from this map, so a name never has to be restated at the call site.
72
+ $counterPathByName = [ordered]@{
73
+ NonpagedBytes = '\Memory\Pool Nonpaged Bytes'
74
+ PagedBytes = '\Memory\Pool Paged Bytes'
75
+ CommittedBytes = '\Memory\Committed Bytes'
76
+ CommitLimit = '\Memory\Commit Limit'
77
+ AvailableMBytes = '\Memory\Available MBytes'
78
+ TotalHandles = '\Process(_Total)\Handle Count'
79
+ TotalThreads = '\Process(_Total)\Thread Count'
80
+ }
81
+ $sample = Get-Counter -Counter @($counterPathByName.Values) -ErrorAction Stop
82
+ $valueByName = @{}
83
+ $index = 0
84
+ foreach ($eachName in $counterPathByName.Keys) {
85
+ $valueByName[$eachName] = [int64]$sample.CounterSamples[$index++].CookedValue
86
+ }
87
+ return $valueByName
88
+ }
89
+
90
+ function Get-HighHandleProcessReport {
91
+ param(
92
+ [int]$HandleThreshold,
93
+ [int]$MaximumRows
94
+ )
95
+ $allHotProcesses = @(
96
+ Get-Process -ErrorAction SilentlyContinue |
97
+ Where-Object { $_.HandleCount -gt $HandleThreshold } |
98
+ Sort-Object -Property HandleCount -Descending
99
+ )
100
+ $topProcesses = @($allHotProcesses | Select-Object -First $MaximumRows)
101
+ $cimByProcessId = @{}
102
+ if ($topProcesses.Count -gt 0) {
103
+ $processIdFilter = @($topProcesses | ForEach-Object { "ProcessId=$($_.Id)" }) -join ' OR '
104
+ try {
105
+ foreach ($eachCimProcess in @(
106
+ Get-CimInstance -ClassName Win32_Process -Filter $processIdFilter `
107
+ -ErrorAction SilentlyContinue)) {
108
+ $cimByProcessId[[int]$eachCimProcess.ProcessId] = $eachCimProcess
109
+ }
110
+ }
111
+ catch {
112
+ $null = $_
113
+ }
114
+ }
115
+ $topRows = foreach ($eachProcess in $topProcesses) {
116
+ $commandLine = ''
117
+ $parentProcessId = 0
118
+ $cimProcess = $cimByProcessId[[int]$eachProcess.Id]
119
+ if ($cimProcess) {
120
+ $commandLine = [string]$cimProcess.CommandLine
121
+ $parentProcessId = [int]$cimProcess.ParentProcessId
122
+ }
123
+ [pscustomobject]@{
124
+ ProcessId = $eachProcess.Id
125
+ Name = $eachProcess.ProcessName
126
+ HandleCount = $eachProcess.HandleCount
127
+ ParentProcessId = $parentProcessId
128
+ CommandLine = $commandLine
129
+ }
130
+ }
131
+ return [pscustomobject]@{
132
+ TotalCount = $allHotProcesses.Count
133
+ TopRows = @($topRows)
134
+ }
135
+ }
136
+
137
+ function Ensure-PoolTagCaptureType {
138
+ if ('PoolTagCapture' -as [type]) {
139
+ return
140
+ }
141
+ $source = @'
142
+ using System;
143
+ using System.Collections.Generic;
144
+ using System.Linq;
145
+ using System.Runtime.InteropServices;
146
+ using System.Text;
147
+
148
+ public static class PoolTagCapture {
149
+ const int SystemPoolTagInformation = 22;
150
+
151
+ [DllImport("ntdll.dll")]
152
+ static extern int NtQuerySystemInformation(
153
+ int systemInformationClass,
154
+ IntPtr systemInformation,
155
+ int systemInformationLength,
156
+ out int returnLength);
157
+
158
+ [StructLayout(LayoutKind.Explicit, Size = 40)]
159
+ struct SYSTEM_POOLTAG {
160
+ [FieldOffset(0)] public byte Tag0;
161
+ [FieldOffset(1)] public byte Tag1;
162
+ [FieldOffset(2)] public byte Tag2;
163
+ [FieldOffset(3)] public byte Tag3;
164
+ [FieldOffset(4)] public uint PagedAllocs;
165
+ [FieldOffset(8)] public uint PagedFrees;
166
+ [FieldOffset(16)] public ulong PagedUsed;
167
+ [FieldOffset(24)] public uint NonPagedAllocs;
168
+ [FieldOffset(28)] public uint NonPagedFrees;
169
+ [FieldOffset(32)] public ulong NonPagedUsed;
170
+ }
171
+
172
+ public static string Capture(int topN) {
173
+ int size = 2 * 1024 * 1024;
174
+ int retLen = 0;
175
+ int status = -1;
176
+ IntPtr buffer = IntPtr.Zero;
177
+ try {
178
+ for (int attempt = 0; attempt < 10; attempt++) {
179
+ buffer = Marshal.AllocHGlobal(size);
180
+ status = NtQuerySystemInformation(
181
+ SystemPoolTagInformation, buffer, size, out retLen);
182
+ if (unchecked((uint)status) == 0xC0000004u) {
183
+ Marshal.FreeHGlobal(buffer);
184
+ buffer = IntPtr.Zero;
185
+ size = Math.Max(retLen + 8192, size * 2);
186
+ continue;
187
+ }
188
+ break;
189
+ }
190
+ if (status != 0) {
191
+ return "NTSTATUS=0x" + unchecked((uint)status).ToString("X8")
192
+ + " retLen=" + retLen;
193
+ }
194
+ int count = Marshal.ReadInt32(buffer);
195
+ int baseOff = 8;
196
+ var tags = new List<SYSTEM_POOLTAG>();
197
+ for (int i = 0; i < count; i++) {
198
+ int offset = baseOff + i * 40;
199
+ if (offset + 40 > retLen) break;
200
+ tags.Add(Marshal.PtrToStructure<SYSTEM_POOLTAG>(
201
+ IntPtr.Add(buffer, offset)));
202
+ }
203
+ long sumNonPaged = 0;
204
+ long sumPaged = 0;
205
+ foreach (var eachTag in tags) {
206
+ sumNonPaged += (long)eachTag.NonPagedUsed;
207
+ sumPaged += (long)eachTag.PagedUsed;
208
+ }
209
+ var report = new StringBuilder();
210
+ report.AppendLine("retLen=" + retLen + " count=" + count
211
+ + " sizeof_tag=40 status=0 baseOff=" + baseOff);
212
+ report.AppendLine(string.Format(
213
+ "SUM NonPaged={0} ({1:N3} GB) Paged={2} ({3:N3} GB)",
214
+ sumNonPaged, sumNonPaged / 1073741824.0,
215
+ sumPaged, sumPaged / 1073741824.0));
216
+ report.AppendLine(string.Format(
217
+ "{0,-6} {1,14} {2,14}", "Tag", "NonPaged", "Paged"));
218
+ report.AppendLine("--- TOP BY NONPAGED ---");
219
+ foreach (var eachTag in tags.OrderByDescending(t => t.NonPagedUsed).Take(topN)) {
220
+ report.AppendLine(FormatTag(eachTag));
221
+ }
222
+ report.AppendLine("--- TOP BY PAGED ---");
223
+ foreach (var eachTag in tags.OrderByDescending(t => t.PagedUsed).Take(topN)) {
224
+ report.AppendLine(FormatTag(eachTag));
225
+ }
226
+ var watchTagNames = new[] { "File", "IoFE", "Toke", "Key", "FMfn" };
227
+ var watchNames = new HashSet<string>(watchTagNames, StringComparer.Ordinal);
228
+ report.AppendLine("--- WATCHLIST " + string.Join(" ", watchTagNames) + " ---");
229
+ foreach (var eachTag in tags) {
230
+ string cleanedName = TagName(eachTag).TrimEnd(' ', '.', '\0');
231
+ if (watchNames.Contains(cleanedName)) {
232
+ report.AppendLine(FormatTag(eachTag));
233
+ }
234
+ }
235
+ return report.ToString().TrimEnd();
236
+ }
237
+ finally {
238
+ if (buffer != IntPtr.Zero) {
239
+ Marshal.FreeHGlobal(buffer);
240
+ }
241
+ }
242
+ }
243
+
244
+ static string TagName(SYSTEM_POOLTAG tag) {
245
+ return string.Concat(CharOf(tag.Tag0), CharOf(tag.Tag1),
246
+ CharOf(tag.Tag2), CharOf(tag.Tag3));
247
+ }
248
+
249
+ static char CharOf(byte value) {
250
+ return (value >= 32 && value < 127) ? (char)value : '.';
251
+ }
252
+
253
+ static string FormatTag(SYSTEM_POOLTAG tag) {
254
+ return string.Format("{0,-6} {1,14} {2,14}",
255
+ TagName(tag), tag.NonPagedUsed, tag.PagedUsed);
256
+ }
257
+ }
258
+ '@
259
+ Add-Type -TypeDefinition $source -Language CSharp
260
+ }
261
+
262
+ function Get-PoolTagReport {
263
+ param([int]$TopCount)
264
+ Ensure-PoolTagCaptureType
265
+ return [PoolTagCapture]::Capture($TopCount)
266
+ }
267
+
268
+ function Get-ThresholdAlerts {
269
+ param(
270
+ [int64]$NonpagedBytes,
271
+ [int64]$TotalHandles,
272
+ [int]$HighHandleProcessCount,
273
+ [long]$NonpagedAlert,
274
+ [int]$ProcessHandleAlert,
275
+ [int]$TotalHandleAlert
276
+ )
277
+ $allAlerts = [System.Collections.Generic.List[string]]::new()
278
+ if ($NonpagedBytes -gt $NonpagedAlert) {
279
+ $allAlerts.Add((
280
+ "ALERT nonpaged={0} threshold={1}" -f
281
+ (Format-BytesAsGigabytes $NonpagedBytes),
282
+ (Format-BytesAsGigabytes $NonpagedAlert)
283
+ ))
284
+ }
285
+ if ($TotalHandles -gt $TotalHandleAlert) {
286
+ $allAlerts.Add((
287
+ "ALERT total_handles={0} threshold={1}" -f $TotalHandles, $TotalHandleAlert
288
+ ))
289
+ }
290
+ if ($HighHandleProcessCount -gt 0) {
291
+ $allAlerts.Add((
292
+ "ALERT processes_over_{0}_handles={1}" -f
293
+ $ProcessHandleAlert, $HighHandleProcessCount
294
+ ))
295
+ }
296
+ return , $allAlerts
297
+ }
298
+
299
+ # --- main ---
300
+ $timestamp = Get-Date -Format 'yyyy-MM-dd HH:mm:ss zzz'
301
+ Write-ReportLine "TIMESTAMP: $timestamp"
302
+ Write-ReportLine "HOST: $env:COMPUTERNAME"
303
+ Write-ReportLine (
304
+ "THRESHOLDS: nonpaged>{0}; process_handles>{1}; total_handles>{2}" -f
305
+ (Format-BytesAsGigabytes $NonpagedAlertBytes),
306
+ $ProcessHandleAlert,
307
+ $TotalHandleAlert
308
+ )
309
+
310
+ Write-ReportLine ''
311
+ Write-ReportLine '=== COUNTERS ==='
312
+ $counterByName = Get-MemoryAndHandleCounters
313
+ $nonpagedBytes = $counterByName['NonpagedBytes']
314
+ $pagedBytes = $counterByName['PagedBytes']
315
+ $committedBytes = $counterByName['CommittedBytes']
316
+ $commitLimitBytes = $counterByName['CommitLimit']
317
+ $availableMBytes = $counterByName['AvailableMBytes']
318
+ $totalHandles = $counterByName['TotalHandles']
319
+ $totalThreads = $counterByName['TotalThreads']
320
+
321
+ Write-ReportLine ("Pool Nonpaged Bytes = {0} ({1})" -f $nonpagedBytes, (Format-BytesAsGigabytes $nonpagedBytes))
322
+ Write-ReportLine ("Pool Paged Bytes = {0} ({1})" -f $pagedBytes, (Format-BytesAsGigabytes $pagedBytes))
323
+ Write-ReportLine ("Committed Bytes = {0} ({1})" -f $committedBytes, (Format-BytesAsGigabytes $committedBytes))
324
+ Write-ReportLine ("Commit Limit = {0} ({1})" -f $commitLimitBytes, (Format-BytesAsGigabytes $commitLimitBytes))
325
+ Write-ReportLine ("Available MBytes = {0}" -f $availableMBytes)
326
+ Write-ReportLine ("Handle Count Total = {0}" -f $totalHandles)
327
+ Write-ReportLine ("Thread Count Total = {0}" -f $totalThreads)
328
+
329
+ Write-ReportLine ''
330
+ Write-ReportLine ("=== PROCESSES WITH HANDLES > {0} ===" -f $ProcessHandleAlert)
331
+ $highHandleReport = Get-HighHandleProcessReport `
332
+ -HandleThreshold $ProcessHandleAlert `
333
+ -MaximumRows $TopProcessCount
334
+ if ($highHandleReport.TopRows.Count -eq 0) {
335
+ Write-ReportLine '(none)'
336
+ }
337
+ else {
338
+ foreach ($eachProcess in $highHandleReport.TopRows) {
339
+ $commandPreview = ''
340
+ if ($eachProcess.CommandLine) {
341
+ $commandPreview = $eachProcess.CommandLine
342
+ if ($commandPreview.Length -gt 120) {
343
+ $commandPreview = $commandPreview.Substring(0, 117) + '...'
344
+ }
345
+ }
346
+ Write-ReportLine (
347
+ "PID={0} Name={1} Handles={2} Parent={3} Cmd={4}" -f
348
+ $eachProcess.ProcessId,
349
+ $eachProcess.Name,
350
+ $eachProcess.HandleCount,
351
+ $eachProcess.ParentProcessId,
352
+ $commandPreview
353
+ )
354
+ }
355
+ }
356
+
357
+ $highHandleProcessCount = $highHandleReport.TotalCount
358
+ Write-ReportLine ("High-handle process count (all): {0}" -f $highHandleProcessCount)
359
+
360
+ Write-ReportLine ''
361
+ Write-ReportLine '=== POOL TAGS (NtQuerySystemInformation class 22) ==='
362
+ try {
363
+ Write-ReportLine (Get-PoolTagReport -TopCount $TopTagCount)
364
+ }
365
+ catch {
366
+ Write-ReportLine ("POOL TAG CAPTURE FAILED: {0}" -f $_.Exception.Message)
367
+ }
368
+
369
+ Write-ReportLine ''
370
+ Write-ReportLine '=== REMEDIATION MAP (process-object pressure) ==='
371
+ Write-ReportLine 'Dominant tags File (nonpaged) + Toke (paged) -> object-manager sprawl, not a lone driver leak.'
372
+ Write-ReportLine 'RC2 #255 Cap MCP servers (mcpvault/playwright/serena spawn-without-reap) -> cuts File/Toke/Thre'
373
+ Write-ReportLine 'RC3 #254 Show-Asset.ps1 exit on parent death + timeout -> cuts orphan UI process handles'
374
+ Write-ReportLine 'RC4 #253 Block Git find walks; es.exe primary; kill find with handles >2k -> cuts Key/handle storms'
375
+ Write-ReportLine 'RC5 #256 Attribute WSL/Docker starters only after measurement (VdMm secondary)'
376
+ Write-ReportLine 'Optional: install WDK poolmon.exe for stock binary snapshots (this script needs no WDK).'
377
+
378
+ $allThresholdAlerts = Get-ThresholdAlerts `
379
+ -NonpagedBytes $nonpagedBytes `
380
+ -TotalHandles $totalHandles `
381
+ -HighHandleProcessCount $highHandleProcessCount `
382
+ -NonpagedAlert $NonpagedAlertBytes `
383
+ -ProcessHandleAlert $ProcessHandleAlert `
384
+ -TotalHandleAlert $TotalHandleAlert
385
+ Write-ReportLine ''
386
+ Write-ReportLine '=== THRESHOLD VERDICT ==='
387
+ if ($allThresholdAlerts.Count -eq 0) {
388
+ Write-ReportLine 'OK - all thresholds clear'
389
+ $thresholdExitCode = 0
390
+ }
391
+ else {
392
+ foreach ($eachAlert in $allThresholdAlerts) {
393
+ Write-ReportLine $eachAlert
394
+ }
395
+ Write-ReportLine 'REMEDIATE: process-object pressure (File/Toke tags) -> RC2 #255, RC3 #254, RC4 #253'
396
+ $thresholdExitCode = 1
397
+ }
398
+
399
+ if ($OutPath) {
400
+ $destinationDirectory = Split-Path -Parent $OutPath
401
+ if ($destinationDirectory -and -not (Test-Path -LiteralPath $destinationDirectory)) {
402
+ New-Item -ItemType Directory -Path $destinationDirectory -Force | Out-Null
403
+ }
404
+ $script:ReportLines -join [Environment]::NewLine |
405
+ Set-Content -LiteralPath $OutPath -Encoding utf8
406
+ Write-Output ""
407
+ Write-Output "Wrote report: $OutPath"
408
+ }
409
+
410
+ exit $thresholdExitCode
@@ -9,7 +9,7 @@
9
9
  settings.local.json, and settings.local.json.template, and rewrites permission
10
10
  rule strings that invoke powershell / powershell.exe / bash -c / cmd /c
11
11
  into their pwsh equivalents per the migration mapping in
12
- rules/shell-invocation-policy.md. Defaults to dry-run; pass -Apply to write
12
+ rules/shell-invocation.md. Defaults to dry-run; pass -Apply to write
13
13
  changes. Prints exactly one summary line.
14
14
 
15
15
  .PARAMETER Roots