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,211 +0,0 @@
1
- """Behavior tests for the Codex Luna fast-mode spawn gate."""
2
-
3
- from __future__ import annotations
4
-
5
- import importlib.util
6
- import io
7
- import json
8
- import pathlib
9
- import subprocess
10
- import sys
11
- from typing import Any
12
- from unittest import mock
13
-
14
- _HOOK_DIR = pathlib.Path(__file__).parent
15
- _HOOKS_TREE = _HOOK_DIR.parent
16
- for each_path in (str(_HOOK_DIR), str(_HOOKS_TREE)):
17
- if each_path not in sys.path:
18
- sys.path.insert(0, each_path)
19
-
20
- hook_spec = importlib.util.spec_from_file_location(
21
- "luna_fast_mode_gate",
22
- _HOOK_DIR / "luna_fast_mode_gate.py",
23
- )
24
- assert hook_spec is not None
25
- assert hook_spec.loader is not None
26
- hook_module = importlib.util.module_from_spec(hook_spec)
27
- hook_spec.loader.exec_module(hook_module)
28
-
29
- from hooks_constants.luna_fast_mode_gate_constants import ( # noqa: E402
30
- AGENT_TOOL_NAME,
31
- CALLING_HOOK_NAME,
32
- CODEX_AGENT_TOOL_NAME,
33
- FAST_SERVICE_TIER,
34
- TASK_TOOL_NAME,
35
- )
36
-
37
- _MODEL_ID = "gpt-5.6-luna"
38
- _NON_LUNA_MODEL_ID = "gpt-5.6-sol"
39
- _UNRELATED_TOOL_NAME = "Write"
40
- _SERVICE_TIER_FIELD_NAME = "service_tier"
41
- _MODEL_FIELD_NAME = "model"
42
- _DENY_DECISION = "deny"
43
-
44
-
45
- def _spawn_payload(
46
- *,
47
- tool_name: str = AGENT_TOOL_NAME,
48
- model: object = _MODEL_ID,
49
- service_tier: object = None,
50
- include_service_tier: bool = True,
51
- ) -> dict[str, Any]:
52
- """Build one PreToolUse payload for a spawn surface."""
53
- tool_input: dict[str, object] = {
54
- _MODEL_FIELD_NAME: model,
55
- }
56
- if include_service_tier:
57
- tool_input[_SERVICE_TIER_FIELD_NAME] = service_tier
58
- return {"tool_name": tool_name, "tool_input": tool_input}
59
-
60
-
61
- def _run_main(payload: object) -> str:
62
- """Run the production hook and return its stdout."""
63
- with mock.patch("sys.stdin", io.StringIO(json.dumps(payload))):
64
- with mock.patch("sys.stdout", new_callable=io.StringIO) as captured_stdout:
65
- try:
66
- hook_module.main()
67
- except SystemExit:
68
- pass
69
- return captured_stdout.getvalue()
70
-
71
-
72
- def _decision(payload: object) -> str:
73
- """Return the hook decision for a payload."""
74
- return json.loads(_run_main(payload))["hookSpecificOutput"]["permissionDecision"]
75
-
76
-
77
- def test_blocks_luna_without_fast_for_headless_and_in_session_surfaces() -> None:
78
- all_tool_names = (AGENT_TOOL_NAME, TASK_TOOL_NAME, CODEX_AGENT_TOOL_NAME)
79
- for each_tool_name in all_tool_names:
80
- payload = _spawn_payload(tool_name=each_tool_name, service_tier="flex")
81
- assert _decision(payload) == _DENY_DECISION
82
-
83
-
84
- def test_allows_luna_with_exact_fast_service_tier() -> None:
85
- for each_tool_name in (AGENT_TOOL_NAME, TASK_TOOL_NAME, CODEX_AGENT_TOOL_NAME):
86
- payload = _spawn_payload(
87
- tool_name=each_tool_name,
88
- service_tier=FAST_SERVICE_TIER,
89
- )
90
- assert _run_main(payload) == ""
91
-
92
-
93
- def test_allows_luna_with_native_priority_service_tier() -> None:
94
- payload = _spawn_payload(
95
- tool_name=CODEX_AGENT_TOOL_NAME,
96
- service_tier="priority",
97
- )
98
- assert _run_main(payload) == ""
99
-
100
-
101
- def test_blocks_luna_with_priority_for_agent_and_task_surfaces() -> None:
102
- for each_tool_name in (AGENT_TOOL_NAME, TASK_TOOL_NAME):
103
- payload = _spawn_payload(
104
- tool_name=each_tool_name,
105
- service_tier="priority",
106
- )
107
- assert _decision(payload) == _DENY_DECISION
108
-
109
-
110
- def test_blocks_missing_and_non_string_service_tier() -> None:
111
- assert _decision(_spawn_payload(include_service_tier=False)) == _DENY_DECISION
112
- assert _decision(_spawn_payload(service_tier=None)) == _DENY_DECISION
113
- assert _decision(_spawn_payload(service_tier=True)) == _DENY_DECISION
114
-
115
-
116
- def test_blocks_default_and_wrong_case_fast_service_tiers() -> None:
117
- assert _decision(_spawn_payload(service_tier="default")) == _DENY_DECISION
118
- assert _decision(_spawn_payload(service_tier="FAST")) == _DENY_DECISION
119
-
120
-
121
- def test_allows_non_luna_and_unrelated_tool_payloads() -> None:
122
- assert _run_main(_spawn_payload(model=_NON_LUNA_MODEL_ID)) == ""
123
- assert _run_main(
124
- _spawn_payload(tool_name=_UNRELATED_TOOL_NAME, service_tier="flex")
125
- ) == ""
126
-
127
-
128
- def test_recognizes_case_insensitive_luna_model_segments() -> None:
129
- assert _decision(_spawn_payload(model="GPT-5.6-LUNA", service_tier="flex")) == (
130
- _DENY_DECISION
131
- )
132
- assert _run_main(_spawn_payload(model="gpt-5.6-lunacy", service_tier="flex")) == ""
133
-
134
-
135
- def test_malformed_outer_payload_allows() -> None:
136
- assert _run_main({"tool_name": AGENT_TOOL_NAME}) == ""
137
- assert _run_main({"tool_name": AGENT_TOOL_NAME, "tool_input": []}) == ""
138
- assert _run_main("not an object") == ""
139
- assert _run_main({"tool_name": AGENT_TOOL_NAME, "tool_input": {_MODEL_FIELD_NAME: 7}}) == ""
140
-
141
-
142
- def test_deny_payload_and_log_do_not_include_a_prompt() -> None:
143
- payload = _spawn_payload(service_tier="default")
144
- with mock.patch.object(hook_module, "log_hook_block") as recorded_block:
145
- output = _run_main(payload)
146
- parsed_output = json.loads(output)
147
- assert parsed_output["hookSpecificOutput"]["permissionDecision"] == _DENY_DECISION
148
- assert recorded_block.call_args.kwargs["calling_hook_name"] == CALLING_HOOK_NAME
149
- assert "prompt" not in recorded_block.call_args.kwargs["offending_input_preview"]
150
-
151
-
152
- def test_hooks_json_registers_all_spawn_surfaces() -> None:
153
- hooks_configuration = json.loads(
154
- (_HOOKS_TREE / "hooks.json").read_text(encoding="utf-8")
155
- )
156
- matching_groups = [
157
- each_group
158
- for each_group in hooks_configuration["hooks"]["PreToolUse"]
159
- if CALLING_HOOK_NAME
160
- in " ".join(each_hook["command"] for each_hook in each_group["hooks"])
161
- ]
162
- assert len(matching_groups) == 1
163
- assert matching_groups[0]["matcher"] == (
164
- f"{AGENT_TOOL_NAME}|{TASK_TOOL_NAME}|{CODEX_AGENT_TOOL_NAME}"
165
- )
166
- registered_command = matching_groups[0]["hooks"][0]["command"]
167
- assert registered_command.endswith(
168
- f"/hooks/blocking/{CALLING_HOOK_NAME}"
169
- )
170
- assert (_HOOKS_TREE / "blocking" / CALLING_HOOK_NAME).is_file()
171
-
172
-
173
- def test_registered_command_runs_under_windows_cmd_for_allow_and_deny() -> None:
174
- hooks_configuration = json.loads(
175
- (_HOOKS_TREE / "hooks.json").read_text(encoding="utf-8")
176
- )
177
- matching_group = next(
178
- each_group
179
- for each_group in hooks_configuration["hooks"]["PreToolUse"]
180
- if CALLING_HOOK_NAME
181
- in " ".join(each_hook["command"] for each_hook in each_group["hooks"])
182
- )
183
- registered_command = matching_group["hooks"][0]["command"]
184
- assert registered_command.startswith("python ")
185
- command_line = registered_command.replace(
186
- "${CLAUDE_PLUGIN_ROOT}",
187
- str(_HOOKS_TREE.parent).replace("\\", "/"),
188
- )
189
-
190
- for each_service_tier, expected_output in (
191
- (FAST_SERVICE_TIER, ""),
192
- ("flex", _DENY_DECISION),
193
- ):
194
- completed_process = subprocess.run(
195
- command_line,
196
- input=json.dumps(_spawn_payload(service_tier=each_service_tier)),
197
- capture_output=True,
198
- shell=True,
199
- text=True,
200
- check=False,
201
- )
202
- assert completed_process.returncode == 0, completed_process.stderr
203
- if expected_output == "":
204
- assert completed_process.stdout == ""
205
- else:
206
- assert (
207
- json.loads(completed_process.stdout)["hookSpecificOutput"][
208
- "permissionDecision"
209
- ]
210
- == expected_output
211
- )
@@ -1,225 +0,0 @@
1
- """Unit tests for nas-ssh-binary-enforcer PreToolUse hook.
2
-
3
- The real NAS host, ssh user, and port are private, so these tests set them via
4
- the ``CLAUDE_NAS_*`` environment variables and drive the real hook, asserting
5
- the runtime-built host pattern and deny messages.
6
- """
7
-
8
- import importlib.util
9
- import os
10
- import pathlib
11
- import sys
12
- from collections.abc import Iterator
13
- from unittest.mock import patch
14
-
15
- import pytest
16
-
17
- _HOOK_DIR = pathlib.Path(__file__).parent
18
- if str(_HOOK_DIR) not in sys.path:
19
- sys.path.insert(0, str(_HOOK_DIR))
20
- if str(_HOOK_DIR.parent) not in sys.path:
21
- sys.path.insert(0, str(_HOOK_DIR.parent))
22
-
23
- hook_spec = importlib.util.spec_from_file_location(
24
- "nas_ssh_binary_enforcer",
25
- _HOOK_DIR / "nas_ssh_binary_enforcer.py",
26
- )
27
- assert hook_spec is not None
28
- assert hook_spec.loader is not None
29
- hook_module = importlib.util.module_from_spec(hook_spec)
30
- hook_spec.loader.exec_module(hook_module)
31
- _find_nas_ssh_violation = hook_module._find_nas_ssh_violation
32
-
33
- from hooks_constants.local_identity import ( # noqa: E402
34
- bare_ssh_binary_deny_message,
35
- missing_batch_mode_deny_message,
36
- )
37
-
38
- NAS_HOST = "test-nas.example.net"
39
- NAS_SSH_USER = "tester"
40
- NAS_SSH_PORT = "2222"
41
-
42
-
43
- @pytest.fixture(autouse=True)
44
- def _set_nas_identity_env() -> Iterator[None]:
45
- with patch.dict(
46
- os.environ,
47
- {
48
- "CLAUDE_NAS_HOST": NAS_HOST,
49
- "CLAUDE_NAS_SSH_USER": NAS_SSH_USER,
50
- "CLAUDE_NAS_SSH_PORT": NAS_SSH_PORT,
51
- },
52
- clear=False,
53
- ):
54
- yield
55
-
56
-
57
- def test_bare_ssh_to_nas_is_denied_with_binary_message() -> None:
58
- assert (
59
- _find_nas_ssh_violation(
60
- f'ssh -p {NAS_SSH_PORT} {NAS_SSH_USER}@{NAS_HOST} "ls /volume1"'
61
- )
62
- == bare_ssh_binary_deny_message()
63
- )
64
-
65
-
66
- def test_bare_scp_to_nas_is_denied() -> None:
67
- assert (
68
- _find_nas_ssh_violation(
69
- f"scp -P {NAS_SSH_PORT} file.txt {NAS_SSH_USER}@{NAS_HOST}:/volume1/"
70
- )
71
- == bare_ssh_binary_deny_message()
72
- )
73
-
74
-
75
- def test_bare_sftp_to_nas_is_denied() -> None:
76
- assert (
77
- _find_nas_ssh_violation(f"sftp -P {NAS_SSH_PORT} {NAS_SSH_USER}@{NAS_HOST}")
78
- == bare_ssh_binary_deny_message()
79
- )
80
-
81
-
82
- def test_bare_ssh_to_nas_behind_launcher_wrapper_is_denied() -> None:
83
- assert (
84
- _find_nas_ssh_violation(
85
- f'timeout 10 ssh -p {NAS_SSH_PORT} {NAS_SSH_USER}@{NAS_HOST} "uptime"'
86
- )
87
- == bare_ssh_binary_deny_message()
88
- )
89
-
90
-
91
- def test_bare_ssh_to_nas_after_shell_operator_is_denied() -> None:
92
- assert (
93
- _find_nas_ssh_violation(
94
- f'cd /tmp && ssh -p {NAS_SSH_PORT} {NAS_SSH_USER}@{NAS_HOST} "uptime"'
95
- )
96
- == bare_ssh_binary_deny_message()
97
- )
98
-
99
-
100
- def test_bare_ssh_to_nas_after_glued_operator_is_denied() -> None:
101
- assert (
102
- _find_nas_ssh_violation(
103
- f'true;ssh -p {NAS_SSH_PORT} {NAS_SSH_USER}@{NAS_HOST} "uptime"'
104
- )
105
- == bare_ssh_binary_deny_message()
106
- )
107
-
108
-
109
- def test_bare_ssh_to_nas_after_pipe_ampersand_operator_is_denied() -> None:
110
- assert (
111
- _find_nas_ssh_violation(
112
- f'echo start |& ssh -p {NAS_SSH_PORT} {NAS_SSH_USER}@{NAS_HOST} "echo hi"'
113
- )
114
- == bare_ssh_binary_deny_message()
115
- )
116
-
117
-
118
- def test_full_openssh_binary_to_nas_without_batchmode_is_denied() -> None:
119
- assert (
120
- _find_nas_ssh_violation(
121
- '"/c/Windows/System32/OpenSSH/ssh.exe" -o ConnectTimeout=10 '
122
- f'-p {NAS_SSH_PORT} {NAS_SSH_USER}@{NAS_HOST} "uptime"'
123
- )
124
- == missing_batch_mode_deny_message()
125
- )
126
-
127
-
128
- def test_full_openssh_scp_to_nas_without_batchmode_is_denied() -> None:
129
- assert (
130
- _find_nas_ssh_violation(
131
- '"/c/Windows/System32/OpenSSH/scp.exe" '
132
- f"-P {NAS_SSH_PORT} file.txt {NAS_SSH_USER}@{NAS_HOST}:/volume1/"
133
- )
134
- == missing_batch_mode_deny_message()
135
- )
136
-
137
-
138
- def test_full_openssh_binary_to_nas_with_batchmode_is_allowed() -> None:
139
- assert (
140
- _find_nas_ssh_violation(
141
- '"/c/Windows/System32/OpenSSH/ssh.exe" -o BatchMode=yes '
142
- f'-o ConnectTimeout=10 -p {NAS_SSH_PORT} {NAS_SSH_USER}@{NAS_HOST} "uptime"'
143
- )
144
- is None
145
- )
146
-
147
-
148
- def test_full_openssh_binary_glued_batchmode_flag_is_allowed() -> None:
149
- assert (
150
- _find_nas_ssh_violation(
151
- '"/c/Windows/System32/OpenSSH/ssh.exe" -oBatchMode=yes '
152
- f'-p {NAS_SSH_PORT} {NAS_SSH_USER}@{NAS_HOST} "uptime"'
153
- )
154
- is None
155
- )
156
-
157
-
158
- def test_bare_ssh_to_other_host_is_allowed() -> None:
159
- assert _find_nas_ssh_violation(f'ssh -p 22 {NAS_SSH_USER}@example.com "uptime"') is None
160
-
161
-
162
- def test_full_openssh_binary_to_other_host_without_batchmode_is_allowed() -> None:
163
- assert (
164
- _find_nas_ssh_violation(
165
- f'"/c/Windows/System32/OpenSSH/ssh.exe" -p 22 {NAS_SSH_USER}@example.com "uptime"'
166
- )
167
- is None
168
- )
169
-
170
-
171
- def test_nas_host_as_echoed_data_is_allowed() -> None:
172
- assert _find_nas_ssh_violation(f'echo "connect via ssh to {NAS_HOST}"') is None
173
-
174
-
175
- def test_nas_host_mentioned_without_ssh_command_word_is_allowed() -> None:
176
- assert _find_nas_ssh_violation(f"ping -c 1 {NAS_HOST}") is None
177
-
178
-
179
- def test_ssh_family_word_only_in_remote_command_argument_is_allowed() -> None:
180
- assert (
181
- _find_nas_ssh_violation(
182
- '"/c/Windows/System32/OpenSSH/ssh.exe" -o BatchMode=yes '
183
- f'-p {NAS_SSH_PORT} {NAS_SSH_USER}@{NAS_HOST} "grep ssh /etc/config"'
184
- )
185
- is None
186
- )
187
-
188
-
189
- def test_nas_host_in_different_segment_than_ssh_is_allowed() -> None:
190
- assert (
191
- _find_nas_ssh_violation(
192
- f'echo {NAS_HOST} && ssh -p 22 {NAS_SSH_USER}@example.com "id"'
193
- )
194
- is None
195
- )
196
-
197
-
198
- def test_ssh_to_other_host_with_nas_host_in_remote_command_is_allowed() -> None:
199
- assert (
200
- _find_nas_ssh_violation(
201
- f'ssh -p 22 {NAS_SSH_USER}@example.com "ping -c1 {NAS_HOST}"'
202
- )
203
- is None
204
- )
205
-
206
-
207
- def test_scp_to_other_host_with_nas_host_in_remote_path_is_allowed() -> None:
208
- assert (
209
- _find_nas_ssh_violation(
210
- f"scp -P 22 f.txt {NAS_SSH_USER}@example.com:/backup/{NAS_HOST}/"
211
- )
212
- is None
213
- )
214
-
215
-
216
- def test_similar_host_suffix_is_not_matched() -> None:
217
- assert _find_nas_ssh_violation(f'ssh -p 22 {NAS_SSH_USER}@{NAS_HOST}x "id"') is None
218
-
219
-
220
- def test_empty_command_is_allowed() -> None:
221
- assert _find_nas_ssh_violation("") is None
222
-
223
-
224
- def test_unbalanced_quotes_command_is_allowed() -> None:
225
- assert _find_nas_ssh_violation(f"ssh 'unterminated {NAS_HOST}") is None
@@ -1,231 +0,0 @@
1
- """Tests for orchestrator_refresh_reschedule_gate PreToolUse hook."""
2
-
3
- from __future__ import annotations
4
-
5
- import importlib.util
6
- import io
7
- import json
8
- import sys
9
- from pathlib import Path
10
- from types import ModuleType
11
-
12
- import pytest
13
-
14
- BLOCKING_DIRECTORY = Path(__file__).resolve().parent
15
- HOOKS_DIRECTORY = BLOCKING_DIRECTORY.parent
16
- if str(HOOKS_DIRECTORY) not in sys.path:
17
- sys.path.insert(0, str(HOOKS_DIRECTORY))
18
-
19
- SKILL_SCRIPTS = HOOKS_DIRECTORY.parent / ".agents" / "skills" / "orchestrator" / "scripts"
20
- if str(SKILL_SCRIPTS) not in sys.path:
21
- sys.path.insert(0, str(SKILL_SCRIPTS))
22
-
23
- from status_gate_constants.config.constants import RUN_STATUS_ACTIVE, RUN_STATUS_DONE # noqa: E402
24
- from status_gate import write_status_file # noqa: E402
25
-
26
-
27
- def load_gate_module() -> ModuleType:
28
- module_path = BLOCKING_DIRECTORY / "orchestrator_refresh_reschedule_gate.py"
29
- spec = importlib.util.spec_from_file_location(
30
- "orchestrator_refresh_reschedule_gate",
31
- module_path,
32
- )
33
- assert spec is not None
34
- assert spec.loader is not None
35
- gate_module = importlib.util.module_from_spec(spec)
36
- sys.modules[spec.name] = gate_module
37
- spec.loader.exec_module(gate_module)
38
- return gate_module
39
-
40
-
41
- def run_main_with_payload(
42
- gate_module: ModuleType,
43
- payload: dict[str, object],
44
- monkeypatch: pytest.MonkeyPatch,
45
- ) -> tuple[int, str]:
46
- stdin_buffer = io.StringIO(json.dumps(payload))
47
- stdout_buffer = io.StringIO()
48
- monkeypatch.setattr(sys, "stdin", stdin_buffer)
49
- monkeypatch.setattr(sys, "stdout", stdout_buffer)
50
- exit_code = 0
51
- try:
52
- gate_module.main()
53
- except SystemExit as system_exit:
54
- exit_code = int(system_exit.code or 0)
55
- return exit_code, stdout_buffer.getvalue()
56
-
57
-
58
- class TestOrchestratorRefreshRescheduleGate:
59
- def should_allow_when_status_is_active(
60
- self,
61
- temporary_directory: Path,
62
- monkeypatch: pytest.MonkeyPatch,
63
- ) -> None:
64
- status_file_path = temporary_directory / "status.json"
65
- write_status_file(status_file_path, RUN_STATUS_ACTIVE, "", is_rearm_pending=False)
66
- monkeypatch.setenv("ORCHESTRATOR_RUN_STATUS_FILE", str(status_file_path))
67
- gate_module = load_gate_module()
68
- payload = {
69
- "tool_name": "ScheduleWakeup",
70
- "tool_input": {"prompt": "/orchestrator-refresh", "delaySeconds": 1200},
71
- "cwd": str(temporary_directory),
72
- }
73
- exit_code, stdout_text = run_main_with_payload(
74
- gate_module, payload, monkeypatch
75
- )
76
- assert exit_code == 0
77
- assert stdout_text == ""
78
-
79
- def should_deny_when_status_is_done(
80
- self,
81
- temporary_directory: Path,
82
- monkeypatch: pytest.MonkeyPatch,
83
- ) -> None:
84
- status_file_path = temporary_directory / "status.json"
85
- write_status_file(status_file_path, RUN_STATUS_DONE, "", is_rearm_pending=False)
86
- monkeypatch.setenv("ORCHESTRATOR_RUN_STATUS_FILE", str(status_file_path))
87
- gate_module = load_gate_module()
88
- payload = {
89
- "tool_name": "ScheduleWakeup",
90
- "tool_input": {"prompt": "/orchestrator-refresh re-arm"},
91
- "cwd": str(temporary_directory),
92
- }
93
- exit_code, stdout_text = run_main_with_payload(
94
- gate_module, payload, monkeypatch
95
- )
96
- assert exit_code == 0
97
- denial = json.loads(stdout_text)
98
- assert denial["hookSpecificOutput"]["permissionDecision"] == "deny"
99
-
100
- def should_deny_when_status_file_missing(
101
- self,
102
- temporary_directory: Path,
103
- monkeypatch: pytest.MonkeyPatch,
104
- ) -> None:
105
- missing_path = temporary_directory / "nope.json"
106
- monkeypatch.setenv("ORCHESTRATOR_RUN_STATUS_FILE", str(missing_path))
107
- gate_module = load_gate_module()
108
- payload = {
109
- "tool_name": "ScheduleWakeup",
110
- "tool_input": {"prompt": "/orchestrator-refresh now"},
111
- "cwd": str(temporary_directory),
112
- }
113
- _exit_code, stdout_text = run_main_with_payload(
114
- gate_module, payload, monkeypatch
115
- )
116
- denial = json.loads(stdout_text)
117
- assert denial["hookSpecificOutput"]["permissionDecision"] == "deny"
118
-
119
- def should_deny_when_rearm_slot_already_pending(
120
- self,
121
- temporary_directory: Path,
122
- monkeypatch: pytest.MonkeyPatch,
123
- ) -> None:
124
- status_file_path = temporary_directory / "status.json"
125
- write_status_file(
126
- status_file_path, RUN_STATUS_ACTIVE, "", is_rearm_pending=True
127
- )
128
- monkeypatch.setenv("ORCHESTRATOR_RUN_STATUS_FILE", str(status_file_path))
129
- gate_module = load_gate_module()
130
- payload = {
131
- "tool_name": "ScheduleWakeup",
132
- "tool_input": {"prompt": "/orchestrator-refresh", "delaySeconds": 1200},
133
- "cwd": str(temporary_directory),
134
- }
135
- _exit_code, stdout_text = run_main_with_payload(
136
- gate_module, payload, monkeypatch
137
- )
138
- denial = json.loads(stdout_text)
139
- assert denial["hookSpecificOutput"]["permissionDecision"] == "deny"
140
- assert "rearm_already_pending" in denial["hookSpecificOutput"][
141
- "permissionDecisionReason"
142
- ]
143
-
144
- def should_always_deny_cron_create_for_orchestrator_refresh(
145
- self,
146
- temporary_directory: Path,
147
- monkeypatch: pytest.MonkeyPatch,
148
- ) -> None:
149
- status_file_path = temporary_directory / "status.json"
150
- write_status_file(status_file_path, RUN_STATUS_ACTIVE, "", is_rearm_pending=False)
151
- monkeypatch.setenv("ORCHESTRATOR_RUN_STATUS_FILE", str(status_file_path))
152
- gate_module = load_gate_module()
153
- payload = {
154
- "tool_name": "CronCreate",
155
- "tool_input": {"prompt": "/orchestrator-refresh"},
156
- "cwd": str(temporary_directory),
157
- }
158
- _exit_code, stdout_text = run_main_with_payload(
159
- gate_module, payload, monkeypatch
160
- )
161
- denial = json.loads(stdout_text)
162
- assert denial["hookSpecificOutput"]["permissionDecision"] == "deny"
163
- assert "cron_create_forbidden" in denial["hookSpecificOutput"][
164
- "permissionDecisionReason"
165
- ]
166
-
167
- def should_ignore_unrelated_schedule_prompts(
168
- self,
169
- temporary_directory: Path,
170
- monkeypatch: pytest.MonkeyPatch,
171
- ) -> None:
172
- gate_module = load_gate_module()
173
- payload = {
174
- "tool_name": "ScheduleWakeup",
175
- "tool_input": {"prompt": "/pr-converge"},
176
- "cwd": str(temporary_directory),
177
- }
178
- exit_code, stdout_text = run_main_with_payload(
179
- gate_module, payload, monkeypatch
180
- )
181
- assert exit_code == 0
182
- assert stdout_text == ""
183
-
184
- def should_ignore_prose_mention_of_orchestrator_refresh(
185
- self,
186
- temporary_directory: Path,
187
- monkeypatch: pytest.MonkeyPatch,
188
- ) -> None:
189
- gate_module = load_gate_module()
190
- payload = {
191
- "tool_name": "ScheduleWakeup",
192
- "tool_input": {
193
- "prompt": "See docs about /orchestrator-refresh for later"
194
- },
195
- "cwd": str(temporary_directory),
196
- }
197
- exit_code, stdout_text = run_main_with_payload(
198
- gate_module, payload, monkeypatch
199
- )
200
- assert exit_code == 0
201
- assert stdout_text == ""
202
-
203
- def should_allow_when_prompt_carries_run_slug_for_scoped_status(
204
- self,
205
- temporary_directory: Path,
206
- monkeypatch: pytest.MonkeyPatch,
207
- ) -> None:
208
- run_slug = "demo-run"
209
- status_file_path = temporary_directory.joinpath(
210
- "docs", "plans", run_slug, ".orchestrator-run-status.json"
211
- )
212
- write_status_file(status_file_path, RUN_STATUS_ACTIVE, run_slug, is_rearm_pending=False)
213
- monkeypatch.delenv("ORCHESTRATOR_RUN_STATUS_FILE", raising=False)
214
- gate_module = load_gate_module()
215
- payload = {
216
- "tool_name": "ScheduleWakeup",
217
- "tool_input": {
218
- "prompt": f"/orchestrator-refresh --run-slug {run_slug}"
219
- },
220
- "cwd": str(temporary_directory),
221
- }
222
- exit_code, stdout_text = run_main_with_payload(
223
- gate_module, payload, monkeypatch
224
- )
225
- assert exit_code == 0
226
- assert stdout_text == ""
227
-
228
-
229
- @pytest.fixture
230
- def temporary_directory(tmp_path: Path) -> Path:
231
- return tmp_path