claude-dev-env 4.3.0 → 7.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (480) hide show
  1. package/.agents/agents/pr-description-writer.md +2 -2
  2. package/.agents/agents/test_agent_frontmatter.py +2 -2
  3. package/.agents/agents/test_pr_description_writer_style.py +1 -3
  4. package/.agents/skills/e-code-review/SKILL.md +12 -12
  5. package/.agents/skills/e-code-review/preflight-proposal.contract.test.mjs +20 -0
  6. package/.agents/skills/e-code-review/reference/fix.md +15 -17
  7. package/.agents/skills/e-code-review/reference/loop.md +35 -39
  8. package/.agents/skills/e-code-review/reference/mode-contract.test.mjs +2 -1
  9. package/.agents/skills/e-code-review/reference/preflight-proposal.md +44 -9
  10. package/.agents/skills/e-code-review/reference/runner-selection.md +13 -14
  11. package/.agents/skills/issue-tracker/SKILL.md +5 -4
  12. package/.agents/skills/pull-request/SKILL.md +11 -13
  13. package/.agents/skills/pull-request/reference/publication-tasks.md +3 -3
  14. package/.agents/skills/pull-request/scripts/github_pr_command_constants/config/constants.py +9 -1
  15. package/.agents/skills/pull-request/scripts/pull_request.py +35 -44
  16. package/.agents/skills/pull-request/scripts/test_github_pr_command_constants.py +9 -0
  17. package/.agents/skills/pull-request/scripts/test_pull_request.py +35 -3
  18. package/.agents/skills/session-continuity/README.md +189 -0
  19. package/.agents/skills/session-continuity/SKILL.md +114 -0
  20. package/.agents/skills/session-continuity/continuity.mjs +375 -0
  21. package/.agents/skills/session-continuity/continuity.test.mjs +303 -0
  22. package/.agents/skills/skill-builder/SKILL.md +3 -196
  23. package/.agents/skills/syncing-submodules/scripts/test_sync_parent_pointer.py +0 -7
  24. package/.agents/skills/windows-scheduled-task/SKILL.md +153 -0
  25. package/_shared/pr-loop/scripts/pr_loop_shared_constants/terminology_sweep_constants.py +6 -0
  26. package/_shared/pr-loop/scripts/terminology_sweep.py +64 -19
  27. package/_shared/pr-loop/scripts/tests/test_terminology_sweep.py +59 -0
  28. package/bin/cde.mjs +36 -8
  29. package/bin/cde.test.mjs +48 -0
  30. package/bin/ever-shipped-skills.mjs +2 -20
  31. package/bin/ever-shipped-skills.test.mjs +8 -0
  32. package/bin/expand_home_directory_tokens.mjs +4 -5
  33. package/bin/expand_home_directory_tokens.test.mjs +128 -0
  34. package/bin/git_hooks_installer.mjs +22 -3
  35. package/bin/git_hooks_installer.test.mjs +159 -5
  36. package/bin/install-session-continuity.mjs +78 -0
  37. package/bin/install-session-continuity.test.mjs +42 -0
  38. package/bin/install.agents-home.test.mjs +15 -13
  39. package/bin/install.codex-rules.test.mjs +5 -2
  40. package/bin/install.cursor-rules.test.mjs +5 -2
  41. package/bin/install.mjs +506 -63
  42. package/bin/install.policy-lint.test.mjs +130 -0
  43. package/bin/install.profiles.test.mjs +10 -0
  44. package/bin/install.prune.test.mjs +286 -37
  45. package/bin/install.pstack-plugin.test.mjs +114 -0
  46. package/bin/install.test.mjs +537 -120
  47. package/bin/install.transaction.test.mjs +3 -3
  48. package/bin/refresh-pstack-plugin-skills.test.mjs +211 -0
  49. package/docs/CODE_RULES.md +1 -1
  50. package/hooks/advisory/pr_done_reminder.py +342 -0
  51. package/hooks/advisory/test_pr_done_reminder.py +249 -0
  52. package/hooks/blocking/bash_post_call_dispatcher.py +53 -6
  53. package/hooks/blocking/code_rules_banned_identifiers.py +3 -0
  54. package/hooks/blocking/code_rules_paired_test.py +22 -15
  55. package/hooks/blocking/precommit_code_rules_gate.py +5 -8
  56. package/hooks/blocking/test_bash_dispatcher_interpreter_starts.py +7 -52
  57. package/hooks/blocking/test_bash_post_call_dispatcher.py +65 -4
  58. package/hooks/blocking/test_bash_pre_tool_use_dispatcher.py +0 -69
  59. package/hooks/blocking/test_code_rules_banned_identifiers.py +64 -0
  60. package/hooks/blocking/test_code_rules_enforcer_paired_test.py +36 -29
  61. package/hooks/blocking/test_code_rules_js_resume_task_enumeration.py +4 -4
  62. package/hooks/blocking/test_code_rules_js_returns_object_schemaless.py +5 -5
  63. package/hooks/blocking/test_pre_tool_use_dispatcher.py +43 -342
  64. package/hooks/blocking/test_pre_tool_use_dispatcher_native.py +20 -51
  65. package/hooks/blocking/test_shared_stdin_adoption.py +1 -47
  66. package/hooks/git-hooks/git_hooks_constants/staged_policy_lint.py +12 -0
  67. package/hooks/git-hooks/git_hooks_constants/verification_notice_constants.py +116 -0
  68. package/hooks/git-hooks/post_commit.py +33 -0
  69. package/hooks/git-hooks/pre_commit.py +18 -49
  70. package/hooks/git-hooks/pre_push.py +45 -541
  71. package/hooks/git-hooks/test_installed_policy_lint.py +208 -0
  72. package/hooks/git-hooks/test_native_hook_support.py +129 -0
  73. package/hooks/git-hooks/test_native_policy_commit.py +120 -0
  74. package/hooks/git-hooks/test_post_commit.py +43 -0
  75. package/hooks/git-hooks/test_pre_commit.py +38 -148
  76. package/hooks/git-hooks/test_pre_push.py +48 -1631
  77. package/hooks/git-hooks/test_verification_notice.py +60 -0
  78. package/hooks/git-hooks/test_verification_start.py +173 -0
  79. package/hooks/git-hooks/verification_notice.py +192 -0
  80. package/hooks/git-hooks/verification_notice_context.py +253 -0
  81. package/hooks/git-hooks/verification_notice_state.py +237 -0
  82. package/hooks/git-hooks/verification_start.py +100 -0
  83. package/hooks/hooks.json +1 -120
  84. package/hooks/hooks_constants/banned_identifiers_constants.py +4 -0
  85. package/hooks/hooks_constants/bash_post_call_dispatcher_constants.py +14 -1
  86. package/hooks/hooks_constants/bash_pre_tool_use_dispatcher_constants.py +1 -15
  87. package/hooks/hooks_constants/post_tool_use_dispatcher_constants.py +0 -4
  88. package/hooks/hooks_constants/pr_done_reminder_constants.py +98 -0
  89. package/hooks/hooks_constants/pre_tool_use_dispatcher_constants.py +10 -93
  90. package/hooks/hooks_constants/stop_dispatcher_constants.py +1 -4
  91. package/hooks/hooks_constants/test_bash_post_call_dispatcher_constants.py +19 -2
  92. package/hooks/hooks_constants/test_bash_pre_tool_use_dispatcher_constants.py +3 -66
  93. package/hooks/hooks_constants/test_pr_done_reminder_constants.py +40 -0
  94. package/hooks/hooks_constants/test_pre_tool_use_dispatcher_constants.py +46 -201
  95. package/hooks/hooks_constants/test_stop_dispatcher_constants.py +3 -25
  96. package/hooks/validation/test_post_tool_use_dispatcher.py +35 -298
  97. package/hooks/validators/run_all_validators.py +5 -1
  98. package/hooks/validators/security_checks.py +57 -2
  99. package/hooks/validators/test_hook_timing_harness.py +2 -5
  100. package/hooks/validators/test_run_all_validators_mutation_tool_parity.py +3 -11
  101. package/hooks/validators/test_run_all_validators_policy_lint.py +36 -0
  102. package/hooks/validators/test_security_checks.py +57 -0
  103. package/package.json +2 -2
  104. package/rules/confirm-implementation-forks.md +2 -0
  105. package/rules/durable-post-artifacts.md +2 -1
  106. package/rules/git-workflow.md +18 -6
  107. package/rules/pstack-host-mapping.md +48 -0
  108. package/rules/vault-context.md +3 -5
  109. package/rules/verify-runtime-state.md +7 -0
  110. package/scripts/audit-hooks-cli.mjs +5 -0
  111. package/scripts/audit-hooks.mjs +72 -16
  112. package/scripts/automatic_advisory/__init__.py +1 -0
  113. package/scripts/automatic_advisory/checkout.py +51 -0
  114. package/scripts/automatic_advisory/cli.py +334 -0
  115. package/scripts/automatic_advisory/config/__init__.py +1 -0
  116. package/scripts/automatic_advisory/config/constants.py +93 -0
  117. package/scripts/automatic_advisory/config/timing.py +4 -0
  118. package/scripts/automatic_advisory/configuration.py +197 -0
  119. package/scripts/automatic_advisory/execution.py +350 -0
  120. package/scripts/automatic_advisory/git.py +69 -0
  121. package/scripts/automatic_advisory/model.py +107 -0
  122. package/scripts/automatic_advisory/process_host.py +32 -0
  123. package/scripts/automatic_advisory/publisher.py +84 -0
  124. package/scripts/automatic_advisory/runner.py +399 -0
  125. package/scripts/automatic_advisory/state.py +116 -0
  126. package/scripts/automatic_advisory/window_flags.py +41 -0
  127. package/scripts/automatic_advisory/windows_job.py +122 -0
  128. package/scripts/check.ps1 +0 -1
  129. package/{.agents/skills/run-claude-dev-env/driver.mjs → scripts/ci/installer-lifecycle.mjs} +3 -28
  130. package/scripts/ci/installer-lifecycle.test.mjs +26 -0
  131. package/scripts/ci/windows-installer-lifecycle.ps1 +1 -11
  132. package/scripts/codex_compat_materializer.py +99 -13
  133. package/scripts/dev_env_scripts_constants/shared_tree_constants.py +4 -5
  134. package/{.agents/skills/_shared/pr-loop/scripts → scripts}/durable_post_lint.py +35 -43
  135. package/{.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/durable_post_lint_constants.py → scripts/durable_post_lint_config/config/constants.py} +10 -10
  136. package/{.agents/skills/_shared/pr-loop/scripts/test_durable_post_lint_constants.py → scripts/durable_post_lint_config/config/test_constants.py} +14 -1
  137. package/scripts/local_report_cli.py +184 -0
  138. package/scripts/local_report_core.py +247 -0
  139. package/scripts/local_report_publisher.py +12 -0
  140. package/scripts/local_report_validation.py +357 -0
  141. package/scripts/local_verification/__init__.py +23 -0
  142. package/scripts/local_verification/check_runner.py +364 -0
  143. package/scripts/local_verification/check_support.py +99 -0
  144. package/scripts/local_verification/cli.py +158 -0
  145. package/scripts/local_verification/command_runner.py +84 -0
  146. package/scripts/local_verification/config/__init__.py +1 -0
  147. package/scripts/local_verification/config/constants.py +89 -0
  148. package/scripts/local_verification/config/timing.py +1 -0
  149. package/scripts/local_verification/git_state.py +146 -0
  150. package/scripts/local_verification/manifest.py +224 -0
  151. package/scripts/local_verification/model.py +174 -0
  152. package/scripts/local_verification/runner.py +234 -0
  153. package/scripts/policy_lint/adapter_detectors.py +13 -6
  154. package/scripts/policy_lint/adapter_pairing.py +58 -3
  155. package/scripts/policy_lint/adapters.py +7 -4
  156. package/scripts/policy_lint/config/approved_test_pairs.py +323 -0
  157. package/scripts/policy_lint/config/constants.py +5 -0
  158. package/scripts/policy_lint/engine.py +48 -4
  159. package/scripts/policy_lint/model.py +1 -0
  160. package/scripts/policy_lint/registry.py +1 -1
  161. package/scripts/policy_lint/selection.py +2 -1
  162. package/scripts/policy_lint/selection_git.py +2 -0
  163. package/scripts/pr_verification/__init__.py +1 -0
  164. package/scripts/pr_verification/branch_refs.py +114 -0
  165. package/scripts/pr_verification/config/__init__.py +1 -0
  166. package/scripts/pr_verification/config/constants.py +84 -0
  167. package/scripts/pr_verification/config/timing.py +5 -0
  168. package/scripts/pr_verification/github.py +137 -0
  169. package/scripts/pr_verification/github_api.py +376 -0
  170. package/scripts/pr_verification/github_labels.py +88 -0
  171. package/scripts/pr_verification/github_parsing.py +182 -0
  172. package/scripts/pr_verification/github_transport.py +91 -0
  173. package/scripts/pr_verification/lock.py +122 -0
  174. package/scripts/pr_verification/model.py +43 -0
  175. package/scripts/pr_verification/requirements.txt +1 -0
  176. package/scripts/refresh_pstack_plugin_skills.mjs +200 -0
  177. package/scripts/shared_tree_paths.py +32 -3
  178. package/{.agents/skills/_shared/pr-loop/scripts → scripts}/test_durable_post_lint.py +97 -0
  179. package/scripts/test_shared_tree_paths.py +33 -0
  180. package/scripts/tests/test-audit-hooks-cli.mjs +150 -0
  181. package/scripts/tests/test-audit-hooks.mjs +94 -2
  182. package/scripts/tests/test_automatic_advisory.py +376 -0
  183. package/scripts/tests/test_automatic_advisory_job_cleanup.py +71 -0
  184. package/scripts/tests/test_automatic_advisory_polling.py +216 -0
  185. package/scripts/tests/test_automatic_advisory_recovery.py +320 -0
  186. package/scripts/tests/test_automatic_advisory_repairs.py +400 -0
  187. package/scripts/tests/test_automatic_advisory_settings.py +48 -0
  188. package/scripts/tests/test_automatic_advisory_window_flags.py +163 -0
  189. package/scripts/tests/test_closed_pr_label.py +157 -0
  190. package/scripts/tests/test_codex_compat_materializer.py +189 -6
  191. package/scripts/tests/test_github_labels.py +101 -0
  192. package/scripts/tests/test_github_transport.py +125 -0
  193. package/scripts/tests/test_local_report_publisher.py +396 -0
  194. package/scripts/tests/test_local_report_publisher_cli.py +85 -0
  195. package/scripts/tests/test_local_verification.py +348 -0
  196. package/scripts/tests/test_local_verification_cli.py +98 -0
  197. package/scripts/tests/test_policy_lint_rules_archive.py +120 -0
  198. package/scripts/tests/test_policy_lint_rules_engine.py +25 -4
  199. package/scripts/tests/test_policy_lint_rules_installed_loader.py +29 -0
  200. package/scripts/tests/test_policy_lint_rules_pairing.py +163 -0
  201. package/scripts/tests/test_policy_lint_rules_registry.py +227 -13
  202. package/scripts/tests/test_policy_lint_selection.py +25 -2
  203. package/scripts/tests/test_policy_lint_selection_native_index.py +30 -0
  204. package/scripts/tests/test_pr_verification_github.py +392 -0
  205. package/scripts/tests/test_pr_verification_lock.py +168 -0
  206. package/scripts/tests/test_rules.py +3 -7
  207. package/scripts/tests/test_verification_notice.py +347 -0
  208. package/.agents/skills/_shared/pr-loop/.claude/CLAUDE.md +0 -1
  209. package/.agents/skills/_shared/pr-loop/audit-contract.md +0 -5
  210. package/.agents/skills/_shared/pr-loop/audit-reply-template.md +0 -5
  211. package/.agents/skills/_shared/pr-loop/code-rules-gate.md +0 -5
  212. package/.agents/skills/_shared/pr-loop/fix-protocol.md +0 -5
  213. package/.agents/skills/_shared/pr-loop/gh-payloads.md +0 -5
  214. package/.agents/skills/_shared/pr-loop/portable-driver.md +0 -149
  215. package/.agents/skills/_shared/pr-loop/post-audit-thread-contract.md +0 -5
  216. package/.agents/skills/_shared/pr-loop/precatch-rubric.md +0 -5
  217. package/.agents/skills/_shared/pr-loop/preflight-proposal.contract.test.mjs +0 -119
  218. package/.agents/skills/_shared/pr-loop/preflight-proposal.md +0 -5
  219. package/.agents/skills/_shared/pr-loop/prompts/.claude/CLAUDE.md +0 -1
  220. package/.agents/skills/_shared/pr-loop/prompts/AGENTS.md +0 -1
  221. package/.agents/skills/_shared/pr-loop/prompts/pr-consistency-audit.xml +0 -324
  222. package/.agents/skills/_shared/pr-loop/scripts/.claude/CLAUDE.md +0 -1
  223. package/.agents/skills/_shared/pr-loop/scripts/AGENTS.md +0 -1
  224. package/.agents/skills/_shared/pr-loop/scripts/RUNTIME_SCRIPTS.md +0 -29
  225. package/.agents/skills/_shared/pr-loop/scripts/_cli_utils.py +0 -22
  226. package/.agents/skills/_shared/pr-loop/scripts/_path_resolver.py +0 -186
  227. package/.agents/skills/_shared/pr-loop/scripts/_xml_utils.py +0 -20
  228. package/.agents/skills/_shared/pr-loop/scripts/audit_category_schema.py +0 -355
  229. package/.agents/skills/_shared/pr-loop/scripts/build_audit_prompt.py +0 -289
  230. package/.agents/skills/_shared/pr-loop/scripts/build_converge_task_list.py +0 -310
  231. package/.agents/skills/_shared/pr-loop/scripts/build_fix_prompt.py +0 -292
  232. package/.agents/skills/_shared/pr-loop/scripts/init_loop_state.py +0 -134
  233. package/.agents/skills/_shared/pr-loop/scripts/portable_converge_driver.py +0 -1646
  234. package/.agents/skills/_shared/pr-loop/scripts/preflight_worktree.py +0 -392
  235. package/.agents/skills/_shared/pr-loop/scripts/select_converge_pacer.py +0 -215
  236. package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/.claude/CLAUDE.md +0 -1
  237. package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/AGENTS.md +0 -1
  238. package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/__init__.py +0 -0
  239. package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/audit_category_schema_constants.py +0 -37
  240. package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/converge_task_list_constants.py +0 -56
  241. package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/handoff_constants.py +0 -45
  242. package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/pacer_constants.py +0 -47
  243. package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/path_resolver_constants.py +0 -157
  244. package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/portable_driver_constants.py +0 -177
  245. package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/preflight_constants.py +0 -70
  246. package/.agents/skills/_shared/pr-loop/scripts/teardown_worktrees.py +0 -172
  247. package/.agents/skills/_shared/pr-loop/scripts/test__path_resolver.py +0 -106
  248. package/.agents/skills/_shared/pr-loop/scripts/test_audit_category_schema.py +0 -94
  249. package/.agents/skills/_shared/pr-loop/scripts/test_build_audit_prompt.py +0 -499
  250. package/.agents/skills/_shared/pr-loop/scripts/test_build_converge_task_list.py +0 -140
  251. package/.agents/skills/_shared/pr-loop/scripts/test_build_fix_prompt.py +0 -262
  252. package/.agents/skills/_shared/pr-loop/scripts/test_init_loop_state.py +0 -71
  253. package/.agents/skills/_shared/pr-loop/scripts/test_portable_converge_driver.py +0 -1119
  254. package/.agents/skills/_shared/pr-loop/scripts/test_preflight_worktree.py +0 -287
  255. package/.agents/skills/_shared/pr-loop/scripts/test_select_converge_pacer.py +0 -207
  256. package/.agents/skills/_shared/pr-loop/scripts/test_teardown_worktrees.py +0 -59
  257. package/.agents/skills/_shared/pr-loop/scripts/test_write_handoff.py +0 -201
  258. package/.agents/skills/_shared/pr-loop/scripts/write_audit_outcomes.py +0 -182
  259. package/.agents/skills/_shared/pr-loop/scripts/write_fix_outcomes.py +0 -206
  260. package/.agents/skills/_shared/pr-loop/scripts/write_handoff.py +0 -309
  261. package/.agents/skills/_shared/pr-loop/state-schema.md +0 -5
  262. package/.agents/skills/_shared/pr-loop/worker-spawn.md +0 -5
  263. package/.agents/skills/autoconverge/.claude/CLAUDE.md +0 -1
  264. package/.agents/skills/autoconverge/AGENTS.md +0 -1
  265. package/.agents/skills/autoconverge/SKILL.md +0 -431
  266. package/.agents/skills/autoconverge/reference/.claude/CLAUDE.md +0 -1
  267. package/.agents/skills/autoconverge/reference/AGENTS.md +0 -1
  268. package/.agents/skills/autoconverge/reference/closing-report.md +0 -93
  269. package/.agents/skills/autoconverge/reference/convergence-gates.md +0 -31
  270. package/.agents/skills/autoconverge/reference/convergence.md +0 -219
  271. package/.agents/skills/autoconverge/reference/copilot-findings.md +0 -51
  272. package/.agents/skills/autoconverge/reference/gotchas.md +0 -66
  273. package/.agents/skills/autoconverge/reference/headless-safety.md +0 -44
  274. package/.agents/skills/autoconverge/reference/multi-pr.md +0 -128
  275. package/.agents/skills/autoconverge/reference/self-closing-loop.md +0 -84
  276. package/.agents/skills/autoconverge/reference/stop-conditions.md +0 -127
  277. package/.agents/skills/autoconverge/test_portable_pacer_gate.py +0 -54
  278. package/.agents/skills/autoconverge/workflow/.claude/CLAUDE.md +0 -1
  279. package/.agents/skills/autoconverge/workflow/AGENTS.md +0 -1
  280. package/.agents/skills/autoconverge/workflow/aggregate_runs.py +0 -371
  281. package/.agents/skills/autoconverge/workflow/autoconverge_report_constants/.claude/CLAUDE.md +0 -1
  282. package/.agents/skills/autoconverge/workflow/autoconverge_report_constants/AGENTS.md +0 -1
  283. package/.agents/skills/autoconverge/workflow/autoconverge_report_constants/__init__.py +0 -0
  284. package/.agents/skills/autoconverge/workflow/autoconverge_report_constants/render_report_constants.py +0 -250
  285. package/.agents/skills/autoconverge/workflow/converge.clean-audit.test.mjs +0 -665
  286. package/.agents/skills/autoconverge/workflow/converge.codex-gate.test.mjs +0 -472
  287. package/.agents/skills/autoconverge/workflow/converge.contract.test.mjs +0 -64
  288. package/.agents/skills/autoconverge/workflow/converge.copilot-gate.test.mjs +0 -1009
  289. package/.agents/skills/autoconverge/workflow/converge.fix-progress.test.mjs +0 -107
  290. package/.agents/skills/autoconverge/workflow/converge.fix-recovery.test.mjs +0 -33
  291. package/.agents/skills/autoconverge/workflow/converge.merge-conflict.test.mjs +0 -15
  292. package/.agents/skills/autoconverge/workflow/converge.mjs +0 -3132
  293. package/.agents/skills/autoconverge/workflow/converge.p2-advance.test.mjs +0 -202
  294. package/.agents/skills/autoconverge/workflow/converge.path-aware.test.mjs +0 -47
  295. package/.agents/skills/autoconverge/workflow/converge.precatch.test.mjs +0 -152
  296. package/.agents/skills/autoconverge/workflow/converge.run-input.test.mjs +0 -116
  297. package/.agents/skills/autoconverge/workflow/converge_multi.mjs +0 -169
  298. package/.agents/skills/autoconverge/workflow/converge_multi.run-input.test.mjs +0 -173
  299. package/.agents/skills/autoconverge/workflow/convergence_summary.py +0 -110
  300. package/.agents/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a11d903476b803493.jsonl +0 -2
  301. package/.agents/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a26213978adeef6fb.jsonl +0 -2
  302. package/.agents/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a3def0d15ed9d9110.jsonl +0 -2
  303. package/.agents/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a41f41b1b708ee3b7.jsonl +0 -2
  304. package/.agents/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a758b880abecc3ff7.jsonl +0 -2
  305. package/.agents/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a8897b89656b1bd16.jsonl +0 -2
  306. package/.agents/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-ab1c2d3e4f5a6b7c8.jsonl +0 -2
  307. package/.agents/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-abd463d744a1437bc.jsonl +0 -2
  308. package/.agents/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-ad19d027ae8ee1816.jsonl +0 -2
  309. package/.agents/skills/autoconverge/workflow/fixtures/wf_run/workflows/wf_881252e6-700.json +0 -266
  310. package/.agents/skills/autoconverge/workflow/render_report.py +0 -1024
  311. package/.agents/skills/autoconverge/workflow/test_aggregate_runs.py +0 -134
  312. package/.agents/skills/autoconverge/workflow/test_convergence_summary.py +0 -149
  313. package/.agents/skills/autoconverge/workflow/test_render_report.py +0 -812
  314. package/.agents/skills/hitl/SKILL.md +0 -45
  315. package/.agents/skills/pr-cleanup/SKILL.md +0 -140
  316. package/.agents/skills/pr-cleanup/reference/process-inventory.md +0 -17
  317. package/.agents/skills/pr-cleanup/reference/task-seeds.md +0 -22
  318. package/.agents/skills/pr-name-by-capability/SKILL.md +0 -73
  319. package/.agents/skills/pr-name-by-capability/reference/fetch-commands.md +0 -29
  320. package/.agents/skills/pr-name-by-capability/reference/offense-examples.md +0 -32
  321. package/.agents/skills/pr-name-by-capability/reference/report-template.md +0 -29
  322. package/.agents/skills/pr-name-by-capability/reference/rule-checklist.md +0 -38
  323. package/.agents/skills/pr-name-by-capability/reference/task-seeds.md +0 -10
  324. package/.agents/skills/pr-plain-language-cleanup/SKILL.md +0 -93
  325. package/.agents/skills/pr-refinement/SKILL.md +0 -31
  326. package/.agents/skills/pr-shared-extraction/SKILL.md +0 -177
  327. package/.agents/skills/pr-shared-extraction/reference/examples.md +0 -46
  328. package/.agents/skills/pr-shared-extraction/reference/offense-taxonomy.md +0 -100
  329. package/.agents/skills/pr-small-cl/SKILL.md +0 -52
  330. package/.agents/skills/pr-title-description/SKILL.md +0 -96
  331. package/.agents/skills/prototype/SKILL.md +0 -85
  332. package/.agents/skills/prototype/reference/honest-limitations.md +0 -23
  333. package/.agents/skills/prototype/reference/promotion-tasks.md +0 -23
  334. package/.agents/skills/prototype/scripts/build_sandbox_settings.py +0 -249
  335. package/.agents/skills/prototype/scripts/conftest.py +0 -15
  336. package/.agents/skills/prototype/scripts/launch_sandbox.py +0 -205
  337. package/.agents/skills/prototype/scripts/probe_sandbox_safety.py +0 -311
  338. package/.agents/skills/prototype/scripts/prototype_scripts_constants/__init__.py +0 -1
  339. package/.agents/skills/prototype/scripts/prototype_scripts_constants/config/__init__.py +0 -0
  340. package/.agents/skills/prototype/scripts/prototype_scripts_constants/config/build_sandbox_settings_constants.py +0 -41
  341. package/.agents/skills/prototype/scripts/prototype_scripts_constants/config/launch_sandbox_constants.py +0 -23
  342. package/.agents/skills/prototype/scripts/prototype_scripts_constants/config/probe_sandbox_safety_constants.py +0 -45
  343. package/.agents/skills/prototype/scripts/prototype_scripts_constants/config/prototype_common_constants.py +0 -10
  344. package/.agents/skills/prototype/scripts/test_build_sandbox_settings.py +0 -275
  345. package/.agents/skills/prototype/scripts/test_launch_sandbox.py +0 -303
  346. package/.agents/skills/prototype/scripts/test_probe_sandbox_safety.py +0 -312
  347. package/.agents/skills/prototype/workflows/promotion.md +0 -25
  348. package/.agents/skills/prototype/workflows/sandbox.md +0 -35
  349. package/.agents/skills/rebase/.claude/CLAUDE.md +0 -1
  350. package/.agents/skills/rebase/AGENTS.md +0 -1
  351. package/.agents/skills/rebase/SKILL.md +0 -178
  352. package/.agents/skills/review-router/SKILL.md +0 -51
  353. package/.agents/skills/review-router/reference/route-policy.json +0 -7
  354. package/.agents/skills/review-router/reference/task-seeds.md +0 -1
  355. package/.agents/skills/review-router/scripts/conftest.py +0 -4
  356. package/.agents/skills/review-router/scripts/review_router.py +0 -50
  357. package/.agents/skills/review-router/scripts/review_router_cli.py +0 -211
  358. package/.agents/skills/review-router/scripts/review_router_constants/__init__.py +0 -1
  359. package/.agents/skills/review-router/scripts/review_router_constants/config/__init__.py +0 -0
  360. package/.agents/skills/review-router/scripts/review_router_constants/config/constants.py +0 -13
  361. package/.agents/skills/review-router/scripts/test_review_router.py +0 -23
  362. package/.agents/skills/review-router/scripts/test_review_router_cli.py +0 -47
  363. package/.agents/skills/review-tier/SKILL.md +0 -56
  364. package/.agents/skills/review-tier/reference/task-seeds.md +0 -1
  365. package/.agents/skills/review-tier/reference/tier-policy.json +0 -9
  366. package/.agents/skills/review-tier/scripts/conftest.py +0 -4
  367. package/.agents/skills/review-tier/scripts/review_tier.py +0 -359
  368. package/.agents/skills/review-tier/scripts/review_tier_constants/__init__.py +0 -1
  369. package/.agents/skills/review-tier/scripts/review_tier_constants/config/__init__.py +0 -0
  370. package/.agents/skills/review-tier/scripts/review_tier_constants/config/constants.py +0 -29
  371. package/.agents/skills/review-tier/scripts/test_generation.py +0 -159
  372. package/.agents/skills/review-tier/scripts/test_review_tier.py +0 -33
  373. package/.agents/skills/run-claude-dev-env/SKILL.md +0 -84
  374. package/.agents/skills/session-log/.claude/CLAUDE.md +0 -1
  375. package/.agents/skills/session-log/AGENTS.md +0 -1
  376. package/.agents/skills/session-log/SKILL.md +0 -170
  377. package/.agents/skills/session-log/templates/frontmatter.md +0 -40
  378. package/.agents/skills/session-tidy/.claude/CLAUDE.md +0 -1
  379. package/.agents/skills/session-tidy/AGENTS.md +0 -1
  380. package/.agents/skills/session-tidy/SKILL.md +0 -191
  381. package/.agents/skills/skill-builder/references/.claude/CLAUDE.md +0 -1
  382. package/.agents/skills/skill-builder/references/AGENTS.md +0 -1
  383. package/.agents/skills/skill-builder/references/delegation-map.md +0 -130
  384. package/.agents/skills/skill-builder/references/description-field.md +0 -111
  385. package/.agents/skills/skill-builder/references/deterministic-elements.md +0 -218
  386. package/.agents/skills/skill-builder/references/progressive-disclosure.md +0 -122
  387. package/.agents/skills/skill-builder/references/self-audit-checklist.md +0 -126
  388. package/.agents/skills/skill-builder/references/skill-modularity.md +0 -111
  389. package/.agents/skills/skill-builder/references/skill-types.md +0 -232
  390. package/.agents/skills/skill-builder/references/thariq-x-post-skills.json +0 -33
  391. package/.agents/skills/skill-builder/templates/.claude/CLAUDE.md +0 -1
  392. package/.agents/skills/skill-builder/templates/AGENTS.md +0 -1
  393. package/.agents/skills/skill-builder/templates/gap-analysis.md +0 -87
  394. package/.agents/skills/skill-builder/workflows/.claude/CLAUDE.md +0 -1
  395. package/.agents/skills/skill-builder/workflows/AGENTS.md +0 -1
  396. package/.agents/skills/skill-builder/workflows/improve-skill.md +0 -136
  397. package/.agents/skills/skill-builder/workflows/new-skill.md +0 -179
  398. package/.agents/skills/skill-builder/workflows/polish-skill.md +0 -139
  399. package/.agents/skills/source-command-sr-loop/SKILL.md +0 -82
  400. package/.agents/skills/update/.claude/CLAUDE.md +0 -1
  401. package/.agents/skills/update/AGENTS.md +0 -1
  402. package/.agents/skills/update/SKILL.md +0 -190
  403. package/_shared/pr-loop/AGENTS.md +0 -1
  404. package/_shared/pr-loop/audit-contract.md +0 -183
  405. package/_shared/pr-loop/audit-reply-template.md +0 -151
  406. package/_shared/pr-loop/code-rules-gate.md +0 -65
  407. package/_shared/pr-loop/fix-protocol.md +0 -60
  408. package/_shared/pr-loop/gh-payloads.md +0 -75
  409. package/_shared/pr-loop/post-audit-thread-contract.md +0 -51
  410. package/_shared/pr-loop/precatch-rubric.md +0 -66
  411. package/_shared/pr-loop/preflight-proposal.md +0 -56
  412. package/_shared/pr-loop/scripts/post_audit_thread.py +0 -1242
  413. package/_shared/pr-loop/scripts/pr_loop_shared_constants/post_audit_thread_constants.py +0 -199
  414. package/_shared/pr-loop/scripts/tests/test_post_audit_thread.py +0 -1115
  415. package/_shared/pr-loop/scripts/tests/test_post_audit_thread_constants.py +0 -129
  416. package/_shared/pr-loop/state-schema.md +0 -45
  417. package/_shared/pr-loop/worker-spawn.md +0 -189
  418. package/hooks/blocking/ask_user_question_shape_blocker.py +0 -83
  419. package/hooks/blocking/bot_mention_comment_blocker.py +0 -76
  420. package/hooks/blocking/claude_md_orphan_file_blocker.py +0 -129
  421. package/hooks/blocking/cursor_cli_python_misfire_blocker.py +0 -108
  422. package/hooks/blocking/destructive_command_blocker.py +0 -2073
  423. package/hooks/blocking/fable_spawn_gate.py +0 -187
  424. package/hooks/blocking/luna_fast_mode_gate.py +0 -160
  425. package/hooks/blocking/nas_ssh_binary_enforcer.py +0 -163
  426. package/hooks/blocking/orchestrator_refresh_reschedule_gate.py +0 -260
  427. package/hooks/blocking/package_inventory_stale_blocker.py +0 -107
  428. package/hooks/blocking/pii_prevention_blocker.py +0 -365
  429. package/hooks/blocking/piped_pytest_blocker.py +0 -1223
  430. package/hooks/blocking/question_to_user_enforcer.py +0 -130
  431. package/hooks/blocking/send_user_file_open_locally_blocker.py +0 -71
  432. package/hooks/blocking/sensitive_file_protector.py +0 -167
  433. package/hooks/blocking/session_edit_stage_gate.py +0 -684
  434. package/hooks/blocking/session_handoff_blocker.py +0 -182
  435. package/hooks/blocking/shell_substitution_blocker.py +0 -350
  436. package/hooks/blocking/test_ask_user_question_shape.py +0 -69
  437. package/hooks/blocking/test_bot_mention_comment_blocker.py +0 -131
  438. package/hooks/blocking/test_claude_md_orphan_file_blocker.py +0 -1277
  439. package/hooks/blocking/test_cursor_cli_python_misfire_blocker.py +0 -208
  440. package/hooks/blocking/test_destructive_command_blocker.py +0 -2024
  441. package/hooks/blocking/test_destructive_command_blocker_deny_mode.py +0 -105
  442. package/hooks/blocking/test_destructive_command_blocker_no_verify.py +0 -122
  443. package/hooks/blocking/test_destructive_command_blocker_patterns.py +0 -133
  444. package/hooks/blocking/test_fable_spawn_gate.py +0 -381
  445. package/hooks/blocking/test_inventory_deadlock_resolution.py +0 -154
  446. package/hooks/blocking/test_luna_fast_mode_gate.py +0 -211
  447. package/hooks/blocking/test_nas_ssh_binary_enforcer.py +0 -225
  448. package/hooks/blocking/test_orchestrator_refresh_reschedule_gate.py +0 -231
  449. package/hooks/blocking/test_package_inventory_stale_blocker.py +0 -382
  450. package/hooks/blocking/test_pii_prevention_blocker.py +0 -1222
  451. package/hooks/blocking/test_pii_prevention_windows_git_path.py +0 -41
  452. package/hooks/blocking/test_pii_write_surface_ephemeral.py +0 -221
  453. package/hooks/blocking/test_piped_pytest_blocker.py +0 -587
  454. package/hooks/blocking/test_precommit_code_rules_gate_native_owner.py +0 -233
  455. package/hooks/blocking/test_question_to_user_enforcer.py +0 -169
  456. package/hooks/blocking/test_send_user_file_open_locally_blocker.py +0 -118
  457. package/hooks/blocking/test_sensitive_file_protector.py +0 -365
  458. package/hooks/blocking/test_session_edit_stage_gate.py +0 -537
  459. package/hooks/blocking/test_session_edit_stage_gate_staging.py +0 -64
  460. package/hooks/blocking/test_session_edit_stage_gate_support.py +0 -204
  461. package/hooks/blocking/test_session_edit_stage_gate_tracker.py +0 -116
  462. package/hooks/blocking/test_session_handoff_blocker.py +0 -318
  463. package/hooks/blocking/test_shell_substitution_blocker.py +0 -298
  464. package/hooks/blocking/test_unscoped_search_blocker.py +0 -102
  465. package/hooks/blocking/test_write_existing_file_blocker.py +0 -122
  466. package/hooks/blocking/tests/test_pii_prevention_blocker.py +0 -259
  467. package/hooks/blocking/unscoped_search_blocker.py +0 -391
  468. package/hooks/blocking/write_existing_file_blocker.py +0 -124
  469. package/hooks/hooks_constants/bot_mention_comment_blocker_constants.py +0 -19
  470. package/hooks/hooks_constants/cursor_cli_python_misfire_blocker_constants.py +0 -79
  471. package/hooks/hooks_constants/fable_spawn_gate_constants.py +0 -61
  472. package/hooks/hooks_constants/luna_fast_mode_gate_constants.py +0 -45
  473. package/hooks/hooks_constants/nas_ssh_binary_enforcer_constants.py +0 -20
  474. package/hooks/hooks_constants/orchestrator_refresh_reschedule_gate_constants.py +0 -57
  475. package/hooks/hooks_constants/send_user_file_open_locally_blocker_constants.py +0 -17
  476. package/hooks/hooks_constants/sensitive_file_protector_constants.py +0 -40
  477. package/hooks/hooks_constants/session_handoff_blocker_constants.py +0 -10
  478. package/hooks/hooks_constants/shell_substitution_blocker_constants.py +0 -80
  479. /package/.agents/skills/{_shared/pr-loop → session-continuity}/AGENTS.md +0 -0
  480. /package/{_shared/pr-loop → .agents/skills/session-continuity}/CLAUDE.md +0 -0
@@ -1,298 +0,0 @@
1
- """Tests for shell_substitution_blocker hook."""
2
-
3
- import json
4
- import subprocess
5
- import sys
6
- from pathlib import Path
7
-
8
-
9
- SCRIPT_PATH = Path(__file__).parent / "shell_substitution_blocker.py"
10
-
11
-
12
- def _run_hook(payload: dict) -> subprocess.CompletedProcess[str]:
13
- return subprocess.run(
14
- [sys.executable, str(SCRIPT_PATH)],
15
- input=json.dumps(payload),
16
- text=True,
17
- capture_output=True,
18
- check=False,
19
- )
20
-
21
-
22
- def test_denies_dollar_paren_substitution() -> None:
23
- payload = {
24
- "tool_name": "Bash",
25
- "tool_input": {"command": 'echo "head: $(git rev-parse HEAD)"'},
26
- }
27
- response = json.loads(_run_hook(payload).stdout)
28
- assert response["hookSpecificOutput"]["permissionDecision"] == "deny"
29
- assert (
30
- "shell-substitution"
31
- in response["hookSpecificOutput"]["permissionDecisionReason"]
32
- )
33
-
34
-
35
- def test_denies_unescaped_backtick_substitution() -> None:
36
- payload = {
37
- "tool_name": "Bash",
38
- "tool_input": {"command": "echo `date`"},
39
- }
40
- response = json.loads(_run_hook(payload).stdout)
41
- assert response["hookSpecificOutput"]["permissionDecision"] == "deny"
42
-
43
-
44
- def test_allows_plain_command_without_substitution() -> None:
45
- payload = {
46
- "tool_name": "Bash",
47
- "tool_input": {"command": "git rev-parse HEAD"},
48
- }
49
- assert _run_hook(payload).stdout == ""
50
-
51
-
52
- def test_allows_escaped_backtick_in_prose() -> None:
53
- payload = {
54
- "tool_name": "Bash",
55
- "tool_input": {"command": r'echo "use \`foo\` like this"'},
56
- }
57
- assert _run_hook(payload).stdout == ""
58
-
59
-
60
- def test_ignores_non_bash_tool() -> None:
61
- payload = {
62
- "tool_name": "Edit",
63
- "tool_input": {"command": 'echo "$(date)"'},
64
- }
65
- assert _run_hook(payload).stdout == ""
66
-
67
-
68
- def test_denies_double_backslash_backtick_bypass() -> None:
69
- payload = {
70
- "tool_name": "Bash",
71
- "tool_input": {"command": r"echo \\`date`"},
72
- }
73
- response = json.loads(_run_hook(payload).stdout)
74
- assert response["hookSpecificOutput"]["permissionDecision"] == "deny"
75
-
76
-
77
- def test_allows_dollar_paren_inside_single_quotes() -> None:
78
- payload = {
79
- "tool_name": "Bash",
80
- "tool_input": {"command": "echo '$(not-executed)'"},
81
- }
82
- assert _run_hook(payload).stdout == ""
83
-
84
-
85
- def test_allows_backtick_inside_single_quotes() -> None:
86
- payload = {
87
- "tool_name": "Bash",
88
- "tool_input": {"command": "echo '`not-executed`'"},
89
- }
90
- assert _run_hook(payload).stdout == ""
91
-
92
-
93
- def test_denies_input_process_substitution() -> None:
94
- payload = {
95
- "tool_name": "Bash",
96
- "tool_input": {"command": "diff <(cat a) <(cat b)"},
97
- }
98
- response = json.loads(_run_hook(payload).stdout)
99
- assert response["hookSpecificOutput"]["permissionDecision"] == "deny"
100
-
101
-
102
- def test_denies_output_process_substitution() -> None:
103
- payload = {
104
- "tool_name": "Bash",
105
- "tool_input": {"command": "tee >(gzip > out.gz)"},
106
- }
107
- response = json.loads(_run_hook(payload).stdout)
108
- assert response["hookSpecificOutput"]["permissionDecision"] == "deny"
109
-
110
-
111
- def test_allows_process_substitution_inside_single_quotes() -> None:
112
- payload = {
113
- "tool_name": "Bash",
114
- "tool_input": {"command": "echo '<(not-executed)'"},
115
- }
116
- assert _run_hook(payload).stdout == ""
117
-
118
-
119
- def test_allows_arithmetic_expansion() -> None:
120
- payload = {
121
- "tool_name": "Bash",
122
- "tool_input": {"command": "echo $((2+2))"},
123
- }
124
- assert _run_hook(payload).stdout == ""
125
-
126
-
127
- def test_allows_arithmetic_expansion_with_nested_parens() -> None:
128
- payload = {
129
- "tool_name": "Bash",
130
- "tool_input": {"command": "echo $(( (1+2) * 3 ))"},
131
- }
132
- assert _run_hook(payload).stdout == ""
133
-
134
-
135
- def test_allows_arithmetic_expansion_whose_body_bash_itself_rejects() -> None:
136
- payload = {
137
- "tool_name": "Bash",
138
- "tool_input": {"command": "echo $((echo hi))"},
139
- }
140
- assert _run_hook(payload).stdout == ""
141
-
142
-
143
- def test_allows_arithmetic_lookalike_inside_single_quotes() -> None:
144
- payload = {
145
- "tool_name": "Bash",
146
- "tool_input": {"command": "echo '$((cd /tmp) && pwd)'"},
147
- }
148
- assert _run_hook(payload).stdout == ""
149
-
150
-
151
- def test_denies_subshell_disguised_as_arithmetic_expansion() -> None:
152
- payload = {
153
- "tool_name": "Bash",
154
- "tool_input": {"command": "echo $((cd /tmp) && pwd)"},
155
- }
156
- response = json.loads(_run_hook(payload).stdout)
157
- assert response["hookSpecificOutput"]["permissionDecision"] == "deny"
158
-
159
-
160
- def test_denies_parenthesized_command_word_disguised_as_arithmetic() -> None:
161
- payload = {
162
- "tool_name": "Bash",
163
- "tool_input": {"command": "echo $((1+2) )"},
164
- }
165
- response = json.loads(_run_hook(payload).stdout)
166
- assert response["hookSpecificOutput"]["permissionDecision"] == "deny"
167
-
168
-
169
- def test_denies_command_substitution_nested_inside_arithmetic_expansion() -> None:
170
- payload = {
171
- "tool_name": "Bash",
172
- "tool_input": {"command": "echo $(( $(id -u) + 1 ))"},
173
- }
174
- response = json.loads(_run_hook(payload).stdout)
175
- assert response["hookSpecificOutput"]["permissionDecision"] == "deny"
176
-
177
-
178
- def test_denies_backtick_substitution_nested_inside_arithmetic_expansion() -> None:
179
- payload = {
180
- "tool_name": "Bash",
181
- "tool_input": {"command": "echo $(( `id -u` + 1 ))"},
182
- }
183
- response = json.loads(_run_hook(payload).stdout)
184
- assert response["hookSpecificOutput"]["permissionDecision"] == "deny"
185
-
186
-
187
- def test_denies_nested_command_substitution_without_arithmetic() -> None:
188
- payload = {
189
- "tool_name": "Bash",
190
- "tool_input": {"command": "echo $(echo $(whoami))"},
191
- }
192
- response = json.loads(_run_hook(payload).stdout)
193
- assert response["hookSpecificOutput"]["permissionDecision"] == "deny"
194
-
195
-
196
- def test_allows_backtick_inside_single_quoted_heredoc_body() -> None:
197
- payload = {
198
- "tool_name": "Bash",
199
- "tool_input": {
200
- "command": (
201
- "cat > notes.md <<'EOF'\n"
202
- "reStructuredText markup: ``inert literal``\n"
203
- "EOF"
204
- )
205
- },
206
- }
207
- assert _run_hook(payload).stdout == ""
208
-
209
-
210
- def test_allows_backtick_inside_tab_stripped_quoted_heredoc_body() -> None:
211
- """A ``<<-`` opener closes on a tab-indented terminator, and stays inert.
212
-
213
- The tab-strip rule decides which line ends the body. Getting it wrong
214
- swallows the rest of the command or ends the body early, so the branch is
215
- pinned here as well as in the shared pipeline that owns the rule.
216
- """
217
- payload = {
218
- "tool_name": "Bash",
219
- "tool_input": {
220
- "command": (
221
- "cat > notes.md <<-'EOF'\n"
222
- "reStructuredText markup: ``inert literal``\n"
223
- "\tEOF\n"
224
- "echo done"
225
- )
226
- },
227
- }
228
- assert _run_hook(payload).stdout == ""
229
-
230
-
231
- def test_denies_backtick_inside_bare_heredoc_body() -> None:
232
- payload = {
233
- "tool_name": "Bash",
234
- "tool_input": {"command": "cat > notes.md <<EOF\nnow: `date`\nEOF"},
235
- }
236
- response = json.loads(_run_hook(payload).stdout)
237
- assert response["hookSpecificOutput"]["permissionDecision"] == "deny"
238
-
239
-
240
- def test_denies_command_substitution_inside_bare_heredoc_body() -> None:
241
- payload = {
242
- "tool_name": "Bash",
243
- "tool_input": {
244
- "command": "cat > notes.md <<EOF\nhead: $(git rev-parse HEAD)\nEOF"
245
- },
246
- }
247
- response = json.loads(_run_hook(payload).stdout)
248
- assert response["hookSpecificOutput"]["permissionDecision"] == "deny"
249
-
250
-
251
- def test_denies_live_substitution_outside_a_quoted_heredoc() -> None:
252
- payload = {
253
- "tool_name": "Bash",
254
- "tool_input": {
255
- "command": (
256
- "cat > notes.md <<'EOF'\n"
257
- "inert ``literal``\n"
258
- "EOF\n"
259
- 'echo "$(git rev-parse HEAD)"'
260
- )
261
- },
262
- }
263
- response = json.loads(_run_hook(payload).stdout)
264
- assert response["hookSpecificOutput"]["permissionDecision"] == "deny"
265
-
266
-
267
- def test_allows_backslash_escaped_heredoc_delimiter_body() -> None:
268
- payload = {
269
- "tool_name": "Bash",
270
- "tool_input": {
271
- "command": "cat > notes.md <<\\EOF\ninert `text`\nEOF"
272
- },
273
- }
274
- assert _run_hook(payload).stdout == ""
275
-
276
-
277
- def test_denies_a_substitution_below_an_opener_inside_a_quoted_string() -> None:
278
- """An opener spelled inside a quoted string opens no heredoc.
279
-
280
- Bash runs the second line here. Reading the first line as an opener and
281
- dropping everything below it hides a live substitution from the scan.
282
- """
283
- payload = {
284
- "tool_name": "Bash",
285
- "tool_input": {"command": 'echo "<<\'EOF\'"\necho $(whoami)'},
286
- }
287
- response = json.loads(_run_hook(payload).stdout)
288
- assert response["hookSpecificOutput"]["permissionDecision"] == "deny"
289
-
290
-
291
- def test_denies_that_bypass_even_when_a_terminator_line_follows() -> None:
292
- """A terminator line below the substitution does not make the strip safe."""
293
- payload = {
294
- "tool_name": "Bash",
295
- "tool_input": {"command": 'echo "<<\'EOF\'"\necho $(whoami)\nEOF'},
296
- }
297
- response = json.loads(_run_hook(payload).stdout)
298
- assert response["hookSpecificOutput"]["permissionDecision"] == "deny"
@@ -1,102 +0,0 @@
1
- """Tests for unscoped_search_blocker hook."""
2
-
3
- import json
4
- import subprocess
5
- import sys
6
- from pathlib import Path
7
-
8
- import pytest
9
-
10
-
11
- SCRIPT_PATH = Path(__file__).parent / "unscoped_search_blocker.py"
12
-
13
- ALL_DENIED_COMMANDS = [
14
- "find / -iname code_rules_gate.py",
15
- "find /c -name '*.py'",
16
- "find ~ -name README.md",
17
- "find $HOME -type f",
18
- "ls -R /",
19
- "ls -laR /",
20
- "ls -Rl /",
21
- "find //server/share -name x",
22
- "find \\\\server\\share -name x",
23
- "bash -c 'find / -name x'",
24
- ]
25
-
26
- ALL_ALLOWED_COMMANDS = [
27
- "find . -iname '*.py'",
28
- "find packages/claude-dev-env -name code_rules_gate.py",
29
- "find /c/Users/example/repo -iname SKILL.md",
30
- "ls -r /",
31
- "ls -la /tmp/x",
32
- "find //server/share/project/src -name x",
33
- "es.exe path:C:\\dev\\repo ext:py gate",
34
- "git status --short",
35
- ]
36
-
37
-
38
- def _run_hook(payload: dict) -> subprocess.CompletedProcess[str]:
39
- return subprocess.run(
40
- [sys.executable, str(SCRIPT_PATH)],
41
- input=json.dumps(payload),
42
- text=True,
43
- capture_output=True,
44
- check=False,
45
- )
46
-
47
-
48
- def _bash_payload(command: str) -> dict:
49
- return {"tool_name": "Bash", "tool_input": {"command": command}}
50
-
51
-
52
- def _powershell_payload(command: str) -> dict:
53
- return {"tool_name": "PowerShell", "tool_input": {"command": command}}
54
-
55
-
56
- @pytest.mark.parametrize("each_command", ALL_DENIED_COMMANDS)
57
- def test_denies_unscoped_root_walk(each_command: str) -> None:
58
- response = json.loads(_run_hook(_bash_payload(each_command)).stdout)
59
- assert response["hookSpecificOutput"]["permissionDecision"] == "deny"
60
-
61
-
62
- @pytest.mark.parametrize("each_command", ALL_ALLOWED_COMMANDS)
63
- def test_allows_scoped_search(each_command: str) -> None:
64
- assert _run_hook(_bash_payload(each_command)).stdout == ""
65
-
66
-
67
- def test_denies_recursive_listing_on_windows_drive_root() -> None:
68
- response = json.loads(
69
- _run_hook(_powershell_payload("Get-ChildItem -Path C:\\ -Recurse")).stdout
70
- )
71
- assert response["hookSpecificOutput"]["permissionDecision"] == "deny"
72
-
73
-
74
- def test_allows_recursive_listing_under_project_directory() -> None:
75
- assert _run_hook(_powershell_payload("Get-ChildItem -Path .\\src -Recurse")).stdout == ""
76
-
77
-
78
- def test_allows_recursive_listing_without_recurse_flag() -> None:
79
- assert _run_hook(_powershell_payload("Get-ChildItem -Path C:\\")).stdout == ""
80
-
81
-
82
- def test_denies_find_root_in_a_chained_segment() -> None:
83
- response = json.loads(
84
- _run_hook(_bash_payload("cd /tmp && find / -name x.py")).stdout
85
- )
86
- assert response["hookSpecificOutput"]["permissionDecision"] == "deny"
87
-
88
-
89
- def test_ignores_unsupported_tool_name() -> None:
90
- payload = {"tool_name": "Edit", "tool_input": {"command": "find / -name x"}}
91
- assert _run_hook(payload).stdout == ""
92
-
93
-
94
- def test_ignores_payload_without_a_command() -> None:
95
- payload = {"tool_name": "Bash", "tool_input": {}}
96
- assert _run_hook(payload).stdout == ""
97
-
98
-
99
- def test_deny_message_names_the_scoped_alternative() -> None:
100
- response = json.loads(_run_hook(_bash_payload("find / -name x.py")).stdout)
101
- deny_reason = response["hookSpecificOutput"]["permissionDecisionReason"]
102
- assert "scope" in deny_reason.lower()
@@ -1,122 +0,0 @@
1
- """Tests for the write_existing_file_blocker hook.
2
-
3
- Each case drives the real hook's ``main()`` through its production stdin path,
4
- feeding it the PreToolUse JSON payload Claude Code sends and reading the
5
- permission decision back off stdout.
6
- """
7
-
8
- from __future__ import annotations
9
-
10
- import contextlib
11
- import io
12
- import json
13
- from collections.abc import Mapping
14
- from pathlib import Path
15
-
16
- import pytest
17
-
18
- import write_existing_file_blocker
19
-
20
-
21
- def _run_payload(
22
- payload: Mapping[str, object],
23
- monkeypatch: pytest.MonkeyPatch,
24
- capsys: pytest.CaptureFixture[str],
25
- ) -> str:
26
- """Run the real hook entry point and return its stdout."""
27
- monkeypatch.setattr(write_existing_file_blocker.sys, "stdin", io.StringIO(json.dumps(payload)))
28
- with contextlib.suppress(SystemExit):
29
- write_existing_file_blocker.main()
30
- return capsys.readouterr().out
31
-
32
-
33
- def _is_deny(stdout_text: str) -> bool:
34
- if not stdout_text.strip():
35
- return False
36
- decision = json.loads(stdout_text)
37
- return decision["hookSpecificOutput"]["permissionDecision"] == "deny"
38
-
39
-
40
- def test_write_denies_an_existing_target(
41
- tmp_path: Path, monkeypatch: pytest.MonkeyPatch, capsys: pytest.CaptureFixture[str]
42
- ) -> None:
43
- """A Write onto a path that already exists is denied."""
44
- existing_path = tmp_path / "already_here.py"
45
- existing_path.write_text("x = 1\n", encoding="utf-8")
46
- payload = {
47
- "tool_name": "Write",
48
- "tool_input": {"file_path": str(existing_path), "content": "x = 2\n"},
49
- }
50
-
51
- stdout = _run_payload(payload, monkeypatch, capsys)
52
-
53
- assert _is_deny(stdout), f"expected a deny, got {stdout!r}"
54
-
55
-
56
- def test_apply_patch_add_denies_an_existing_target(
57
- tmp_path: Path, monkeypatch: pytest.MonkeyPatch, capsys: pytest.CaptureFixture[str]
58
- ) -> None:
59
- """An apply_patch 'Add File' section targeting an existing path is denied."""
60
- existing_path = tmp_path / "already_here.py"
61
- existing_path.write_text("x = 1\n", encoding="utf-8")
62
- payload = {
63
- "tool_name": "apply_patch",
64
- "cwd": str(tmp_path),
65
- "tool_input": {
66
- "command": ("*** Begin Patch\n*** Add File: already_here.py\n+x = 2\n*** End Patch")
67
- },
68
- }
69
-
70
- stdout = _run_payload(payload, monkeypatch, capsys)
71
-
72
- assert _is_deny(stdout), f"expected a deny, got {stdout!r}"
73
-
74
-
75
- def test_apply_patch_update_on_an_existing_target_is_allowed(
76
- tmp_path: Path, monkeypatch: pytest.MonkeyPatch, capsys: pytest.CaptureFixture[str]
77
- ) -> None:
78
- """An 'Update File' section on an existing path is not an unread overwrite."""
79
- existing_path = tmp_path / "already_here.py"
80
- existing_path.write_text("x = 1\n", encoding="utf-8")
81
- payload = {
82
- "tool_name": "apply_patch",
83
- "cwd": str(tmp_path),
84
- "tool_input": {
85
- "command": (
86
- "*** Begin Patch\n"
87
- "*** Update File: already_here.py\n"
88
- "@@\n"
89
- "-x = 1\n"
90
- "+x = 2\n"
91
- "*** End Patch"
92
- )
93
- },
94
- }
95
-
96
- stdout = _run_payload(payload, monkeypatch, capsys)
97
-
98
- assert not _is_deny(stdout), f"expected an allow, got {stdout!r}"
99
-
100
-
101
- def test_multi_edit_on_an_existing_target_is_allowed(
102
- tmp_path: Path, monkeypatch: pytest.MonkeyPatch, capsys: pytest.CaptureFixture[str]
103
- ) -> None:
104
- """A MultiEdit always targets a file already on disk, so it is never denied here.
105
-
106
- Every MultiEdit edit must match an ``old_string`` already present in the
107
- file, so MultiEdit carries no blind create-or-clobber path the way a Write
108
- or an apply_patch 'Add File' does — this hook allows it unconditionally.
109
- """
110
- existing_path = tmp_path / "already_here.py"
111
- existing_path.write_text("x = 1\n", encoding="utf-8")
112
- payload = {
113
- "tool_name": "MultiEdit",
114
- "tool_input": {
115
- "file_path": str(existing_path),
116
- "edits": [{"old_string": "x = 1", "new_string": "x = 2"}],
117
- },
118
- }
119
-
120
- stdout = _run_payload(payload, monkeypatch, capsys)
121
-
122
- assert not _is_deny(stdout), f"expected an allow, got {stdout!r}"