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
@@ -50,3 +50,39 @@ def test_validate_proposed_file_keeps_ruff_as_an_explicit_native_step(
50
50
  )
51
51
 
52
52
  assert "Ruff" in _result_names(all_results)
53
+
54
+
55
+ def _mixed_newline_overlong_source() -> str:
56
+ all_line_endings = ("\r\n", "\n")
57
+ all_body_lines = "".join(
58
+ " running_total = running_total + 1"
59
+ + all_line_endings[each_line_index % len(all_line_endings)]
60
+ for each_line_index in range(29)
61
+ )
62
+ return (
63
+ "def calculate_total(running_total: int) -> int:"
64
+ + all_line_endings[0]
65
+ + all_body_lines
66
+ + " return running_total"
67
+ + all_line_endings[1]
68
+ )
69
+
70
+
71
+ def test_validate_proposed_file_preserves_mixed_newline_diagnostics(
72
+ tmp_path: Path,
73
+ ) -> None:
74
+ all_results = run_all_validators.validate_proposed_file(
75
+ str(tmp_path / "probe.py"),
76
+ _mixed_newline_overlong_source(),
77
+ include_ruff=False,
78
+ )
79
+
80
+ code_quality_result = next(
81
+ each_result
82
+ for each_result in all_results
83
+ if each_result.name == "Code Quality"
84
+ )
85
+ assert code_quality_result.passed is False
86
+ assert "Function 'calculate_total' is 31 lines (max 30)" in (
87
+ code_quality_result.output
88
+ )
@@ -29,6 +29,30 @@ def connect():
29
29
  return password
30
30
  '''
31
31
 
32
+ METADATA_SOURCE_FIXTURE = '''
33
+ AUTHORIZATION_HEADER = "Authorization"
34
+ TOKEN_KEY = "token"
35
+ INSTALLATION_TOKEN_ENDPOINT_TEMPLATE = "/app/installations/{installation_id}/access_tokens"
36
+ TOKEN_RESOURCE_NAME = "installation token"
37
+ '''
38
+
39
+ HEADER_SOURCE_FIXTURE = '''
40
+ AUTHORIZATION_HEADER = "actualsecret"
41
+ '''
42
+
43
+ ERROR_SOURCE_FIXTURE = '''
44
+ PASSWORD_ERROR = "my secret password"
45
+ '''
46
+
47
+ UNSAFE_KEY_METADATA_SOURCE_FIXTURES = (
48
+ '''
49
+ secret_key = "secret"
50
+ ''',
51
+ '''
52
+ password_key = "password"
53
+ ''',
54
+ )
55
+
32
56
  GOOD_PARAMETERIZED_SQL = '''
33
57
  def get_user(user_id):
34
58
  cursor.execute("SELECT * FROM users WHERE id = %s", (user_id,))
@@ -76,6 +100,39 @@ class TestHardcodedSecrets:
76
100
  violations = check_hardcoded_secrets(tree, "test.py")
77
101
  assert len(violations) == 1
78
102
 
103
+ def test_secret_metadata_passes(self) -> None:
104
+ tree = ast.parse(METADATA_SOURCE_FIXTURE)
105
+ violations = check_hardcoded_secrets(tree, "test.py")
106
+ assert violations == []
107
+
108
+ def test_authorization_header_value_fails(self) -> None:
109
+ tree = ast.parse(HEADER_SOURCE_FIXTURE)
110
+ violations = check_hardcoded_secrets(tree, "test.py")
111
+ assert len(violations) == 1
112
+
113
+ def test_password_error_fails(self) -> None:
114
+ tree = ast.parse(ERROR_SOURCE_FIXTURE)
115
+ violations = check_hardcoded_secrets(tree, "test.py")
116
+ assert len(violations) == 1
117
+
118
+ @pytest.mark.parametrize("source_fixture", UNSAFE_KEY_METADATA_SOURCE_FIXTURES)
119
+ def test_sensitive_key_values_fail(self, source_fixture: str) -> None:
120
+ tree = ast.parse(source_fixture)
121
+ violations = check_hardcoded_secrets(tree, "test.py")
122
+ assert len(violations) == 1
123
+
124
+ @pytest.mark.parametrize(
125
+ "endpoint",
126
+ (
127
+ "/tokens/{token_id}?access_token=actualsecret",
128
+ "/tokens/{token_id}#actualsecret",
129
+ ),
130
+ )
131
+ def test_token_endpoint_credentials_fail(self, endpoint: str) -> None:
132
+ tree = ast.parse(f'TOKEN_ENDPOINT_TEMPLATE = "{endpoint}"')
133
+ violations = check_hardcoded_secrets(tree, "test.py")
134
+ assert len(violations) == 1
135
+
79
136
 
80
137
  class TestSqlInjection:
81
138
  def test_parameterized_query_passes(self) -> None:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-dev-env",
3
- "version": "4.3.0",
3
+ "version": "7.1.0",
4
4
  "description": "Claude Code development standards — rules, hooks, agents, commands, and skills",
5
5
  "type": "module",
6
6
  "bin": {
@@ -9,7 +9,7 @@
9
9
  "cde": "bin/cde.mjs"
10
10
  },
11
11
  "scripts": {
12
- "test": "node --test \"bin/*.test.mjs\" \".agents/skills/**/*.test.mjs\" \"tests/fresh-session/**/*.test.mjs\""
12
+ "test": "node --test \"bin/*.test.mjs\" \".agents/skills/**/*.test.mjs\" \"tests/fresh-session/**/*.test.mjs\" \"scripts/ci/*.test.mjs\""
13
13
  },
14
14
  "files": [
15
15
  "bin/",
@@ -5,3 +5,5 @@ At a material fork — two or more viable paths that change the deliverable's sc
5
5
  How to ask: plain language, one option per path with its tradeoff in the description, recommended path listed first and flagged "(Recommended)", hold edits to the forked area until the answer arrives.
6
6
 
7
7
  Not a fork (just proceed): trivially reversible internal-only choices, anything the codebase / stated goal / an existing rule already determines (see `verify-before-asking`), or a single viable path.
8
+
9
+ When an option you offered names a repair and the answer leaves it undone, write it down before the turn moves on: a todo entry, a `spawn_task` chip, or a filed issue. An answer of "no preference" settles which path you take now. It leaves the repair you found still waiting.
@@ -40,7 +40,8 @@ name does not form a path.
40
40
 
41
41
  ## Validation
42
42
 
43
- Run `.agents/skills/_shared/pr-loop/scripts/durable_post_lint.py` before the
43
+ Resolve the active managed root (`CLAUDE_CONFIG_DIR` when set, `~/.claude`
44
+ otherwise), then run `<managed-root>/scripts/durable_post_lint.py` before the
44
45
  server write. Pass the matching action and body file. Use `pr-create`,
45
46
  `pr-edit`, `pr-comment`, `pr-review`, `issue-create`, `issue-edit`,
46
47
  `issue-comment`, or `github-mcp-post`.
@@ -17,15 +17,27 @@ User-level rule: applies to **every** git repo that uses GitHub with `gh`. Small
17
17
 
18
18
  **ALWAYS create PRs as DRAFT:** Use `gh pr create --draft` for ALL PRs
19
19
 
20
+ **A release bot's PR body is machine input. Leave it alone.** Release automation reads
21
+ back the body of its own merged pull request to decide it owns that merge. Rewriting the
22
+ body, or trimming its header or footer, makes the bot treat the merge as somebody else's
23
+ work: it cuts no tag, the publish job skips, and it opens one more release pull request on
24
+ the next run. The merge stays in the repository. No tag is cut and the package never publishes.
25
+
26
+ Spot one by its head branch, which starts `release-please--branches--`, or by a body that
27
+ opens with the bot's own marker line. The description rules in this file, the
28
+ `pr-description-writer` agent, and the house wording style all step aside for it. The
29
+ failure signature in the release job log reads
30
+ `could not parse pull request body as a release PR`.
31
+
20
32
  Use the `pr-description-writer` agent before creating a pull request or
21
33
  rewriting its full description. Publish its title and body file through
22
- `.agents/skills/pull-request/scripts/pull_request.py`. The
23
- `pr-title-description` skill may review the writer's output but cannot replace
24
- the required writer.
34
+ `.agents/skills/pull-request/scripts/pull_request.py`.
25
35
 
26
- Run `_shared/pr-loop/scripts/durable_post_lint.py` before any pull request,
27
- issue, or GitHub MCP post. The linter checks the action-specific title, body,
28
- and volatile-path rules before credential lookup or network access.
36
+ Resolve the active managed root (`CLAUDE_CONFIG_DIR` when set, `~/.claude`
37
+ otherwise), then run `<managed-root>/scripts/durable_post_lint.py` before any
38
+ pull request, issue, or GitHub MCP post. The linter checks the action-specific
39
+ title, body, and volatile-path rules before credential lookup or network
40
+ access.
29
41
 
30
42
  Use `.agents/skills/pull-request/scripts/recover_legacy_author.py
31
43
  <exact-state-file> --confirm-inactive` only for one explicitly selected legacy
@@ -0,0 +1,48 @@
1
+ # Pstack host mapping
2
+
3
+ Pstack skills ship with one host's tool names and paths written into their steps. The
4
+ active host supplies the real ones. Read a pstack step for the shape of the work, and take
5
+ the tool name, the skill home, and the transcript location from the host you run on.
6
+
7
+ [`pstack-models.md`](pstack-models.md) covers the model choice for each role. This rule
8
+ covers everything else a pstack step names.
9
+
10
+ ## What each host supplies
11
+
12
+ | A pstack step names | Take from the host |
13
+ |---|---|
14
+ | A subagent tool | The native subagent tool this session exposes, with its own agent-type field |
15
+ | A skills directory | The skills home this host reads |
16
+ | A transcript directory | The session transcript location this host writes |
17
+ | A model identifier | The identifiers the native subagent tool accepts today |
18
+
19
+ A pstack step that names one host's directory means "the matching directory here". Resolve
20
+ it before the search, and search only inside the active workspace.
21
+
22
+ ## The final message is the whole report
23
+
24
+ On a host where a subagent returns one message to its parent, that message is all the
25
+ parent receives. Working notes, tool output, and text the child printed along the way do
26
+ not travel.
27
+
28
+ Every pstack prompt that asks a child for a list, a set of findings, or a verdict also
29
+ asks for the whole thing, word for word, in the final message. A prompt without that line
30
+ gets back a summary such as "findings reported above", and the findings are gone. The
31
+ parent then reruns the child, which costs the full run a second time.
32
+
33
+ ## Panel spawns
34
+
35
+ Panel size and model diversity follow `pstack-models.md`. Two host limits shape a spawn
36
+ beyond that:
37
+
38
+ - A spawn gate can refuse a model tier. Read the denial, take the tier it names as
39
+ allowed, and spawn again.
40
+ - A host may accept fewer distinct models than a panel asks for. A panel that requires
41
+ distinct models stops; a panel that treats diversity as optional runs with repeats.
42
+
43
+ ## Editing pstack
44
+
45
+ Pstack installs as a plugin. A plugin update overwrites its files, so an edit inside a
46
+ pstack skill lasts until the next update. Durable changes belong in a rule beside this
47
+ one. The installer copies this package's rules into the managed rules directory and
48
+ generates the Cursor copy from the same source.
@@ -1,7 +1,5 @@
1
- # Obsidian Vault Context
1
+ # Obsidian vault context
2
2
 
3
- An Obsidian vault holds session reports (`sessions/`), decisions (`decisions/`), and research (`Research/`) across projects, reached through the obsidian MCP tools.
3
+ An Obsidian vault holds session reports (`sessions/`), decisions (`decisions/`), and research (`Research/`) across projects.
4
4
 
5
- Before substantive project work, search the vault for prior sessions and decisions on the current project through the `recall` skill — by `project` frontmatter first, then by keyword. Search again when touching a component with known history, or when a task might repeat or reverse a prior decision.
6
-
7
- At the end of a substantive session, offer the `session-log` skill; it owns the report format, the `vault_context_retrieved` and `session_id` frontmatter, and the closing `/rename` hand-off.
5
+ Before project work, search the vault with the obsidian MCP tools. Search by `project` frontmatter first, then by keyword. Search again when a component has known history, or when a task might repeat or reverse a prior decision.
@@ -8,6 +8,10 @@ A verdict that a component is fine or not the cause rests on live evidence gathe
8
8
 
9
9
  Gather the probe before you write the verdict. When the probe contradicts the code (the code looks right but the port refuses the connection), report the live result and treat the component as suspect.
10
10
 
11
+ A status field is a report, not the effect. An exit code, a green pipeline run, and a task result all say the work finished. They do not say the work happened. Read the thing the work was meant to make.
12
+
13
+ Some evidence lasts only a moment. When a user shows you a failure, read the source they already hold: the terminal itself, and any log file the error names. A fresh probe minutes later measures a different moment, and a system that healed in between hides the failure you were asked about.
14
+
11
15
  ## Grounding checklist
12
16
 
13
17
  Before stating a runtime claim, gather the matching live signal:
@@ -20,6 +24,9 @@ Before stating a runtime claim, gather the matching live signal:
20
24
  | The process is running | List processes and match the name or PID. |
21
25
  | The change took effect | Drive the flow and watch the new behavior. |
22
26
  | The dependency is reachable | Send one real request and read the response. |
27
+ | The release or deploy shipped | Read what it makes: the tag, the published version, the file on disk. |
28
+ | The pipeline did the work | Read each job's own result. A run reports success while a job inside it is skipped. |
29
+ | The automation works | Drive the branch that matters. A green run of the do-nothing branch proves nothing. |
23
30
 
24
31
  Only after a live signal backs the claim do you state it.
25
32
 
@@ -11,6 +11,7 @@ function parseArguments(argv) {
11
11
  homeDirectory: null,
12
12
  includeInstalled: false,
13
13
  outputPath: null,
14
+ requireNonblocking: false,
14
15
  repositoryRoot: path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../../.."),
15
16
  };
16
17
  for (let offset = 0; offset < argv.length; offset += 1) {
@@ -20,6 +21,7 @@ function parseArguments(argv) {
20
21
  else if (argument === "--format") options.format = argv[++offset];
21
22
  else if (argument === "--home") options.homeDirectory = argv[++offset];
22
23
  else if (argument === "--output") options.outputPath = argv[++offset];
24
+ else if (argument === "--require-nonblocking") options.requireNonblocking = true;
23
25
  else if (argument === "--repository-root") options.repositoryRoot = argv[++offset];
24
26
  else throw new Error(`unknown argument ${argument}`);
25
27
  }
@@ -37,6 +39,9 @@ function renderText(report) {
37
39
  `installed Claude direct: ${summary.claudeDirectCount}`,
38
40
  `installed Codex direct: ${summary.codexDirectCount}`,
39
41
  `active native Git hooks: ${summary.gitHookCount}`,
42
+ `known native Git hooks: ${summary.knownGitHookCount}`,
43
+ `registration eligibility: ${report.registrationEligibility.status}`,
44
+ "runtime proof: separate verification required",
40
45
  `findings: ${summary.findingCount}`,
41
46
  ].join("\n");
42
47
  }
@@ -3,7 +3,8 @@ import { existsSync, readFileSync } from "node:fs";
3
3
  import { homedir } from "node:os";
4
4
  import path from "node:path";
5
5
 
6
- const expectedCounts = Object.freeze({ direct: 32, dispatchers: 5, hosted: 43 });
6
+ import { KNOWN_GIT_HOOK_NAMES } from "../bin/git_hooks_installer.mjs";
7
+
7
8
  const dispatcherSpecs = Object.freeze([
8
9
  ["script:blocking/pre_tool_use_dispatcher.py", "hooks_constants/pre_tool_use_dispatcher_constants.py", "ALL_HOSTED_HOOK_ENTRIES"],
9
10
  ["script:blocking/bash_pre_tool_use_dispatcher.py", "hooks_constants/bash_pre_tool_use_dispatcher_constants.py", "ALL_BASH_HOSTED_HOOK_ENTRIES"],
@@ -19,6 +20,8 @@ const lifecycleNames = new Set([
19
20
  "move_to_explicit_command",
20
21
  "move_to_linter",
21
22
  ]);
23
+ const nonblockingLifecycle = "keep_nonblocking_automation";
24
+ const blockingGitEvents = new Set(["pre-commit", "pre-push"]);
22
25
 
23
26
  function normalizeMatcher(rawMatcher) {
24
27
  return typeof rawMatcher === "string" && rawMatcher
@@ -269,6 +272,55 @@ function lifecycleFindings(records, lifecycle) {
269
272
  ];
270
273
  }
271
274
 
275
+ function nonblockingFindings(records, lifecycle) {
276
+ const lifecycleByTarget = new Map(
277
+ lifecycle.map(({ target, lifecycle: lifecycleName }) => [target, lifecycleName]),
278
+ );
279
+ const uniqueTargets = [...new Set(records.map(({ target }) => target))];
280
+ const lifecycleMismatches = uniqueTargets
281
+ .filter((target) => !target.startsWith("git:") && lifecycleByTarget.has(target))
282
+ .filter((target) => lifecycleByTarget.get(target) !== nonblockingLifecycle)
283
+ .map((target) => ({
284
+ code: "NONBLOCKING_LIFECYCLE_MISMATCH",
285
+ message: "The registration is not eligible for nonblocking automation.",
286
+ scope: "catalog",
287
+ severity: "error",
288
+ target,
289
+ }));
290
+ const blockingGitFindings = records
291
+ .filter(({ event, scope }) => scope === "git" && blockingGitEvents.has(event))
292
+ .map(({ target }) => ({
293
+ code: "NATIVE_GIT_BLOCKING_HOOK",
294
+ message: "A native Git blocking hook remains active.",
295
+ scope: "git",
296
+ severity: "error",
297
+ target,
298
+ }));
299
+ return [...lifecycleMismatches, ...blockingGitFindings];
300
+ }
301
+
302
+ function registrationEligibility(records, lifecycle, isRequired) {
303
+ if (!isRequired) {
304
+ return { status: "not_checked", runtimeProof: "not_assessed" };
305
+ }
306
+ const lifecycleByTarget = new Map(
307
+ lifecycle.map(({ target, lifecycle: lifecycleName }) => [target, lifecycleName]),
308
+ );
309
+ const uniqueTargets = [...new Set(records.map(({ target }) => target))];
310
+ const hasUnclassifiedTarget = uniqueTargets.some((target) => !lifecycleByTarget.has(target));
311
+ const hasIneligibleTarget = uniqueTargets.some(
312
+ (target) => lifecycleByTarget.get(target) && lifecycleByTarget.get(target) !== nonblockingLifecycle,
313
+ );
314
+ const hasBlockingGitHook = records.some(
315
+ ({ event, scope }) => scope === "git" && blockingGitEvents.has(event),
316
+ );
317
+ const isEligible = !hasUnclassifiedTarget && !hasIneligibleTarget && !hasBlockingGitHook;
318
+ return {
319
+ status: isEligible ? "eligible" : "ineligible",
320
+ runtimeProof: "not_assessed",
321
+ };
322
+ }
323
+
272
324
  function readInstalled(configPath, hooksRoot, scope) {
273
325
  if (!existsSync(configPath)) return { findings: [], logical: [], records: [] };
274
326
  const records = readDirect(configPath, scope);
@@ -295,7 +347,7 @@ function activeGitHooks(repositoryRoot) {
295
347
  const hooksPath = gitQuery.stdout?.trim();
296
348
  if (!hooksPath) return [];
297
349
  const hooksRoot = path.isAbsolute(hooksPath) ? hooksPath : path.resolve(repositoryRoot, hooksPath);
298
- return ["pre-commit", "pre-push", "post-commit"]
350
+ return KNOWN_GIT_HOOK_NAMES
299
351
  .filter((name) => existsSync(path.join(hooksRoot, name)))
300
352
  .map((name, ordinal) => ({
301
353
  event: name,
@@ -308,17 +360,16 @@ function activeGitHooks(repositoryRoot) {
308
360
  }));
309
361
  }
310
362
 
311
- function countFindings(directCount, dispatcherCount, hostedCount) {
312
- const actual = { direct: directCount, dispatchers: dispatcherCount, hosted: hostedCount };
313
- return Object.entries(expectedCounts)
314
- .filter(([name, expected]) => actual[name] !== expected)
315
- .map(([name, expected]) => ({
316
- code: `${name.toUpperCase()}_COUNT_DRIFT`,
317
- message: `Expected ${expected} entries and found ${actual[name]}.`,
318
- scope: "canonical",
319
- severity: "error",
320
- target: null,
321
- }));
363
+ function knownGitHooks() {
364
+ return KNOWN_GIT_HOOK_NAMES.map((event, ordinal) => ({
365
+ event,
366
+ matcher: "*",
367
+ ordinal,
368
+ role: "native",
369
+ scope: "git",
370
+ target: `git:${event}`,
371
+ timeoutSeconds: null,
372
+ }));
322
373
  }
323
374
 
324
375
  export function auditHooks(options) {
@@ -327,16 +378,18 @@ export function auditHooks(options) {
327
378
  const direct = readDirect(path.join(hooksRoot, "hooks.json"), "canonical");
328
379
  const hosted = expandHosted(direct, hooksRoot);
329
380
  const logical = logicalRecords(direct, hosted);
381
+ const knownGit = knownGitHooks();
330
382
  const lifecycle = readLifecycle(options.catalogPath);
331
383
  const dispatcherCount = direct.filter(({ role }) => role === "dispatcher").length;
332
384
  const installed = options.includeInstalled
333
385
  ? installedAudit(options.homeDirectory ?? homedir(), repositoryRoot, logical)
334
386
  : { claudeCount: 0, codexCount: 0, findings: [], git: [], logical: [], records: [] };
335
387
  const allLogical = [...logical, ...installed.logical, ...installed.git];
388
+ const isNonblockingRequired = options.requireNonblocking === true;
336
389
  const findings = [
337
- ...countFindings(direct.length, dispatcherCount, hosted.length),
338
390
  ...duplicateFindings(logical, "canonical"),
339
- ...(options.catalogPath ? lifecycleFindings(allLogical, lifecycle) : []),
391
+ ...(options.catalogPath || isNonblockingRequired ? lifecycleFindings(allLogical, lifecycle) : []),
392
+ ...(isNonblockingRequired ? nonblockingFindings(allLogical, lifecycle) : []),
340
393
  ...installed.findings,
341
394
  ].sort((left, right) => JSON.stringify(left).localeCompare(JSON.stringify(right)));
342
395
  const targets = new Set(allLogical.map(({ target }) => target));
@@ -348,6 +401,7 @@ export function auditHooks(options) {
348
401
  installedRegistrations: installed.records.sort(recordSort),
349
402
  installedLogicalRegistrations: installed.logical.sort(recordSort),
350
403
  gitRegistrations: installed.git,
404
+ knownGitRegistrations: knownGit,
351
405
  lifecycle,
352
406
  logicalRegistrations: logical,
353
407
  schemaVersion: 1,
@@ -359,13 +413,15 @@ export function auditHooks(options) {
359
413
  effectiveCount: hosted.length,
360
414
  findingCount: findings.length,
361
415
  gitHookCount: installed.git.length,
416
+ knownGitHookCount: knownGit.length,
362
417
  lifecycleCount: lifecycle.length,
363
418
  logicalAssociationCount: logical.length,
364
- unclassifiedCount: options.catalogPath
419
+ unclassifiedCount: options.catalogPath || isNonblockingRequired
365
420
  ? [...targets].filter((target) => !classified.has(target)).length
366
421
  : 0,
367
422
  uniqueTargetCount: targets.size,
368
423
  },
424
+ registrationEligibility: registrationEligibility(allLogical, lifecycle, isNonblockingRequired),
369
425
  };
370
426
  }
371
427
 
@@ -0,0 +1 @@
1
+ """Automatic local verification for explicitly registered pull requests."""
@@ -0,0 +1,51 @@
1
+ from __future__ import annotations
2
+
3
+ import subprocess
4
+ from pathlib import Path
5
+
6
+ from .config.constants import (
7
+ ALL_GIT_HEAD_ARGUMENTS,
8
+ ALL_GIT_STATUS_ARGUMENTS,
9
+ GIT_BASE_REF_TEMPLATE,
10
+ GIT_EXECUTABLE,
11
+ )
12
+ from .model import AdvisoryRegistration, LocalCheckout
13
+ from .window_flags import hidden_window_creation_flags
14
+
15
+
16
+ def read_local_checkout(checkout_path: Path) -> LocalCheckout:
17
+ """Read the current commit and clean status for one checkout.
18
+
19
+ Args:
20
+ checkout_path: Git working tree to inspect.
21
+
22
+ Returns:
23
+ Commit and clean status, with no commit when Git cannot inspect it.
24
+ """
25
+ try:
26
+ head_process = _run_git_command(ALL_GIT_HEAD_ARGUMENTS, checkout_path)
27
+ status_process = _run_git_command(ALL_GIT_STATUS_ARGUMENTS, checkout_path)
28
+ except OSError:
29
+ return LocalCheckout(None, False)
30
+ head_sha = head_process.stdout.strip() if head_process.returncode == 0 else None
31
+ return LocalCheckout(
32
+ head_sha,
33
+ status_process.returncode == 0 and not status_process.stdout,
34
+ )
35
+
36
+
37
+ def _run_git_command(
38
+ all_arguments: tuple[str, ...], checkout_path: Path
39
+ ) -> subprocess.CompletedProcess[str]:
40
+ return subprocess.run(
41
+ (GIT_EXECUTABLE, *all_arguments),
42
+ cwd=checkout_path,
43
+ capture_output=True,
44
+ check=False,
45
+ text=True,
46
+ creationflags=hidden_window_creation_flags(),
47
+ )
48
+
49
+
50
+ def dedicated_base_ref(registration: AdvisoryRegistration) -> str:
51
+ return GIT_BASE_REF_TEMPLATE.format(pull_request=registration.pull_request_number)