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,275 +0,0 @@
1
- """Tests for the sandbox safety-settings builder."""
2
-
3
- from __future__ import annotations
4
-
5
- import importlib.util
6
- import json
7
- from pathlib import Path
8
- from types import ModuleType
9
-
10
- from prototype_scripts_constants.config.build_sandbox_settings_constants import (
11
- ALL_DESTRUCTIVE_REQUIRED_MATCHERS,
12
- ALL_PII_REQUIRED_MATCHERS,
13
- ALL_SAFETY_HOOK_SCRIPT_BASENAMES,
14
- BUILD_SUCCESS_EXIT_CODE,
15
- COMMAND_KEY,
16
- HOOKS_KEY,
17
- MATCHER_KEY,
18
- PRE_TOOL_USE_KEY,
19
- SETTINGS_MISSING_SAFETY_HOOK_EXIT_CODE,
20
- )
21
-
22
- SCRIPTS_DIRECTORY = Path(__file__).resolve().parent
23
- BUILDER_PATH = SCRIPTS_DIRECTORY / "build_sandbox_settings.py"
24
-
25
- PII_HOOK_BASENAME = ALL_SAFETY_HOOK_SCRIPT_BASENAMES[0]
26
- DESTRUCTIVE_HOOK_BASENAME = ALL_SAFETY_HOOK_SCRIPT_BASENAMES[1]
27
-
28
- CODE_RULES_HOOK_BASENAME = "code_rules_enforcer.py"
29
- TDD_HOOK_BASENAME = "tdd_enforcer.py"
30
- QUESTION_SHAPE_HOOK_BASENAME = "ask_user_question_shape_blocker.py"
31
-
32
- BASH_MATCHER = "Bash"
33
- WRITE_MATCHER = "Write"
34
- EDIT_MATCHER = "Edit"
35
- MULTI_EDIT_MATCHER = "MultiEdit"
36
- NARROW_PII_MATCHER = "mcp__plugin_github_github__.*"
37
-
38
- SUBHOOK_TIMEOUT = 15
39
- PII_COMMAND = f"python hooks/blocking/{PII_HOOK_BASENAME}"
40
- DESTRUCTIVE_COMMAND = f"python hooks/blocking/{DESTRUCTIVE_HOOK_BASENAME}"
41
- CODE_RULES_COMMAND = f"python hooks/blocking/{CODE_RULES_HOOK_BASENAME}"
42
-
43
-
44
- def load_builder_module() -> ModuleType:
45
- spec = importlib.util.spec_from_file_location(
46
- "build_sandbox_settings", BUILDER_PATH
47
- )
48
- assert spec is not None
49
- assert spec.loader is not None
50
- builder_module = importlib.util.module_from_spec(spec)
51
- spec.loader.exec_module(builder_module)
52
- return builder_module
53
-
54
-
55
- def make_subhook(command: str) -> dict:
56
- return {"type": "command", "command": command, "timeout": SUBHOOK_TIMEOUT}
57
-
58
-
59
- def sample_settings_document() -> dict:
60
- """Build a settings document that registers pii on a narrow matcher only.
61
-
62
- ::
63
-
64
- Write block -> [code_rules_enforcer]
65
- Bash block -> [destructive_command_blocker]
66
- GitHub block -> [pii_prevention_blocker] (narrow matcher)
67
-
68
- The live pii gate is scoped to the GitHub MCP tool family, so a
69
- presence-only copy would leave disk writes ungated.
70
- """
71
- write_block = {
72
- MATCHER_KEY: WRITE_MATCHER,
73
- HOOKS_KEY: [make_subhook(CODE_RULES_COMMAND)],
74
- }
75
- bash_block = {
76
- MATCHER_KEY: BASH_MATCHER,
77
- HOOKS_KEY: [make_subhook(DESTRUCTIVE_COMMAND)],
78
- }
79
- github_block = {
80
- MATCHER_KEY: NARROW_PII_MATCHER,
81
- HOOKS_KEY: [make_subhook(PII_COMMAND)],
82
- }
83
- return {HOOKS_KEY: {PRE_TOOL_USE_KEY: [write_block, bash_block, github_block]}}
84
-
85
-
86
- def document_without_destructive() -> dict:
87
- """Build a settings document that registers pii but no destructive hook."""
88
- github_block = {
89
- MATCHER_KEY: NARROW_PII_MATCHER,
90
- HOOKS_KEY: [make_subhook(PII_COMMAND)],
91
- }
92
- return {HOOKS_KEY: {PRE_TOOL_USE_KEY: [github_block]}}
93
-
94
-
95
- def minimal_settings_for(builder: ModuleType, settings_document: dict) -> dict:
96
- entry_by_basename = builder.resolve_safety_hook_entries(settings_document)
97
- return builder.build_minimal_settings(entry_by_basename)
98
-
99
-
100
- def blocks_of(minimal_settings: dict) -> list[dict]:
101
- return minimal_settings[HOOKS_KEY][PRE_TOOL_USE_KEY]
102
-
103
-
104
- def commands_by_matcher(minimal_settings: dict) -> dict[str, list[str]]:
105
- commands_by_each_matcher: dict[str, list[str]] = {}
106
- for each_block in blocks_of(minimal_settings):
107
- commands_by_each_matcher[each_block[MATCHER_KEY]] = [
108
- each_subhook[COMMAND_KEY] for each_subhook in each_block[HOOKS_KEY]
109
- ]
110
- return commands_by_each_matcher
111
-
112
-
113
- def test_read_settings_document_parses_the_source_json(tmp_path: Path) -> None:
114
- builder = load_builder_module()
115
- source_path = tmp_path / "settings.json"
116
- source_path.write_text(json.dumps(sample_settings_document()), encoding="utf-8")
117
- parsed_document = builder.read_settings_document(source_path)
118
- assert parsed_document == sample_settings_document()
119
-
120
-
121
- def test_resolve_safety_hook_entries_copies_each_live_command_through() -> None:
122
- builder = load_builder_module()
123
- entry_by_basename = builder.resolve_safety_hook_entries(sample_settings_document())
124
- assert set(entry_by_basename) == set(ALL_SAFETY_HOOK_SCRIPT_BASENAMES)
125
- assert entry_by_basename[PII_HOOK_BASENAME][COMMAND_KEY] == PII_COMMAND
126
- assert (
127
- entry_by_basename[DESTRUCTIVE_HOOK_BASENAME][COMMAND_KEY] == DESTRUCTIVE_COMMAND
128
- )
129
- assert entry_by_basename[PII_HOOK_BASENAME]["timeout"] == SUBHOOK_TIMEOUT
130
-
131
-
132
- def test_find_unresolved_safety_hook_basenames_names_the_missing_hook() -> None:
133
- builder = load_builder_module()
134
- entry_by_basename = builder.resolve_safety_hook_entries(
135
- document_without_destructive()
136
- )
137
- assert builder.find_unresolved_safety_hook_basenames(entry_by_basename) == [
138
- DESTRUCTIVE_HOOK_BASENAME
139
- ]
140
-
141
-
142
- def test_find_unresolved_safety_hook_basenames_empty_when_both_resolve() -> None:
143
- builder = load_builder_module()
144
- entry_by_basename = builder.resolve_safety_hook_entries(sample_settings_document())
145
- assert builder.find_unresolved_safety_hook_basenames(entry_by_basename) == []
146
-
147
-
148
- def test_build_registers_pii_on_every_required_write_and_command_matcher() -> None:
149
- builder = load_builder_module()
150
- commands = commands_by_matcher(
151
- minimal_settings_for(builder, sample_settings_document())
152
- )
153
- assert set(commands) == set(ALL_PII_REQUIRED_MATCHERS)
154
- for each_matcher in ALL_PII_REQUIRED_MATCHERS:
155
- assert PII_COMMAND in commands[each_matcher]
156
-
157
-
158
- def test_build_registers_destructive_on_the_command_matcher_only() -> None:
159
- builder = load_builder_module()
160
- commands = commands_by_matcher(
161
- minimal_settings_for(builder, sample_settings_document())
162
- )
163
- for each_matcher, each_command_list in commands.items():
164
- has_destructive = DESTRUCTIVE_COMMAND in each_command_list
165
- assert has_destructive == (each_matcher in ALL_DESTRUCTIVE_REQUIRED_MATCHERS)
166
-
167
-
168
- def test_build_bash_block_carries_both_safety_hooks() -> None:
169
- builder = load_builder_module()
170
- commands = commands_by_matcher(
171
- minimal_settings_for(builder, sample_settings_document())
172
- )
173
- assert commands[BASH_MATCHER] == [PII_COMMAND, DESTRUCTIVE_COMMAND]
174
-
175
-
176
- def test_build_excludes_every_non_safety_hook() -> None:
177
- builder = load_builder_module()
178
- commands = commands_by_matcher(
179
- minimal_settings_for(builder, sample_settings_document())
180
- )
181
- all_commands = [
182
- each_command
183
- for each_command_list in commands.values()
184
- for each_command in each_command_list
185
- ]
186
- for each_excluded in (
187
- CODE_RULES_HOOK_BASENAME,
188
- TDD_HOOK_BASENAME,
189
- QUESTION_SHAPE_HOOK_BASENAME,
190
- ):
191
- assert all(each_excluded not in each_command for each_command in all_commands)
192
-
193
-
194
- def test_narrow_live_pii_matcher_does_not_leak_into_output() -> None:
195
- builder = load_builder_module()
196
- all_matchers = set(
197
- commands_by_matcher(minimal_settings_for(builder, sample_settings_document()))
198
- )
199
- assert NARROW_PII_MATCHER not in all_matchers
200
- assert all_matchers.issuperset(
201
- {WRITE_MATCHER, EDIT_MATCHER, MULTI_EDIT_MATCHER, BASH_MATCHER}
202
- )
203
-
204
-
205
- def test_build_emits_blocks_in_sorted_matcher_order() -> None:
206
- builder = load_builder_module()
207
- minimal_settings = minimal_settings_for(builder, sample_settings_document())
208
- emitted_matchers = [
209
- each_block[MATCHER_KEY] for each_block in blocks_of(minimal_settings)
210
- ]
211
- assert emitted_matchers == sorted(emitted_matchers)
212
-
213
-
214
- def test_build_emits_the_deny_mode_env_block() -> None:
215
- builder = load_builder_module()
216
- minimal_settings = minimal_settings_for(builder, sample_settings_document())
217
- assert minimal_settings[builder.ENV_KEY] == {
218
- builder.DESTRUCTIVE_DENY_MODE_ENV_VAR: builder.DESTRUCTIVE_DENY_MODE_ENV_VALUE
219
- }
220
-
221
-
222
- def test_write_minimal_settings_round_trips_the_document(tmp_path: Path) -> None:
223
- builder = load_builder_module()
224
- minimal_settings = minimal_settings_for(builder, sample_settings_document())
225
- out_path = tmp_path / "sandbox-settings.json"
226
- builder.write_minimal_settings(minimal_settings, out_path)
227
- assert json.loads(out_path.read_text(encoding="utf-8")) == minimal_settings
228
-
229
-
230
- def test_main_writes_minimal_settings_and_succeeds(tmp_path: Path) -> None:
231
- builder = load_builder_module()
232
- source_path = tmp_path / "settings.json"
233
- source_path.write_text(json.dumps(sample_settings_document()), encoding="utf-8")
234
- out_path = tmp_path / "sandbox-settings.json"
235
- exit_code = builder.main(
236
- ["--out", str(out_path), "--settings-source", str(source_path)]
237
- )
238
- assert exit_code == BUILD_SUCCESS_EXIT_CODE
239
- written = json.loads(out_path.read_text(encoding="utf-8"))
240
- assert set(commands_by_matcher(written)) == set(ALL_PII_REQUIRED_MATCHERS)
241
-
242
-
243
- def test_main_exits_when_the_settings_source_is_unreadable(tmp_path: Path) -> None:
244
- builder = load_builder_module()
245
- absent_source_path = tmp_path / "does-not-exist.json"
246
- out_path = tmp_path / "sandbox-settings.json"
247
- exit_code = builder.main(
248
- ["--out", str(out_path), "--settings-source", str(absent_source_path)]
249
- )
250
- assert exit_code == builder.SETTINGS_SOURCE_UNREADABLE_EXIT_CODE
251
- assert not out_path.exists()
252
-
253
-
254
- def test_main_exits_when_the_settings_source_is_invalid_json(tmp_path: Path) -> None:
255
- builder = load_builder_module()
256
- source_path = tmp_path / "settings.json"
257
- source_path.write_text("{not valid json", encoding="utf-8")
258
- out_path = tmp_path / "sandbox-settings.json"
259
- exit_code = builder.main(
260
- ["--out", str(out_path), "--settings-source", str(source_path)]
261
- )
262
- assert exit_code == builder.SETTINGS_SOURCE_UNREADABLE_EXIT_CODE
263
- assert not out_path.exists()
264
-
265
-
266
- def test_main_exits_when_a_safety_hook_is_missing(tmp_path: Path) -> None:
267
- builder = load_builder_module()
268
- source_path = tmp_path / "settings.json"
269
- source_path.write_text(json.dumps(document_without_destructive()), encoding="utf-8")
270
- out_path = tmp_path / "sandbox-settings.json"
271
- exit_code = builder.main(
272
- ["--out", str(out_path), "--settings-source", str(source_path)]
273
- )
274
- assert exit_code == SETTINGS_MISSING_SAFETY_HOOK_EXIT_CODE
275
- assert not out_path.exists()
@@ -1,303 +0,0 @@
1
- """Tests for the hookless sandbox launcher."""
2
-
3
- from __future__ import annotations
4
-
5
- import importlib.util
6
- from pathlib import Path
7
- from types import ModuleType
8
-
9
- import pytest
10
-
11
- from prototype_scripts_constants.config.launch_sandbox_constants import (
12
- BARE_FLAG,
13
- CLAUDE_EXECUTABLE_NAME,
14
- LAUNCH_MISSING_PATH_EXIT_CODE,
15
- PROMPT_FLAG,
16
- SETTINGS_FLAG,
17
- SKIP_PERMISSIONS_FLAG,
18
- )
19
-
20
- SCRIPTS_DIRECTORY = Path(__file__).resolve().parent
21
- LAUNCHER_PATH = SCRIPTS_DIRECTORY / "launch_sandbox.py"
22
-
23
- SANDBOX_TASK_TEXT = "Build a proof of concept for the widget cache."
24
- SANDBOX_TIMEOUT_SECONDS = 42
25
- FAKE_RUNNER_EXIT_CODE = 7
26
-
27
-
28
- def load_launcher_module() -> ModuleType:
29
- spec = importlib.util.spec_from_file_location("launch_sandbox", LAUNCHER_PATH)
30
- assert spec is not None
31
- assert spec.loader is not None
32
- launcher_module = importlib.util.module_from_spec(spec)
33
- spec.loader.exec_module(launcher_module)
34
- return launcher_module
35
-
36
-
37
- class RecordingCommandRunner:
38
- def __init__(self, exit_code: int) -> None:
39
- self.exit_code = exit_code
40
- self.recorded_tokens: list[str] = []
41
- self.recorded_working_directory: Path | None = None
42
- self.recorded_timeout_seconds: int | None = None
43
- self.call_count = 0
44
-
45
- def __call__(
46
- self,
47
- all_command_tokens: list[str],
48
- working_directory: Path,
49
- timeout_seconds: int | None,
50
- ) -> int:
51
- self.call_count += 1
52
- self.recorded_tokens = all_command_tokens
53
- self.recorded_working_directory = working_directory
54
- self.recorded_timeout_seconds = timeout_seconds
55
- return self.exit_code
56
-
57
-
58
- def make_sandbox_worktree(tmp_path: Path) -> tuple[Path, Path]:
59
- worktree_path = tmp_path / "worktree"
60
- worktree_path.mkdir()
61
- settings_path = tmp_path / "sandbox-settings.json"
62
- settings_path.write_text("{}", encoding="utf-8")
63
- return worktree_path, settings_path
64
-
65
-
66
- def make_task_file(tmp_path: Path) -> Path:
67
- task_file_path = tmp_path / "task.txt"
68
- task_file_path.write_text(SANDBOX_TASK_TEXT, encoding="utf-8")
69
- return task_file_path
70
-
71
-
72
- def test_build_sandbox_command_has_the_exact_ordered_argv() -> None:
73
- launcher = load_launcher_module()
74
- settings_path = Path("/tmp/sandbox-settings.json")
75
- sandbox_command = launcher.build_sandbox_command(SANDBOX_TASK_TEXT, settings_path)
76
- assert sandbox_command == [
77
- CLAUDE_EXECUTABLE_NAME,
78
- PROMPT_FLAG,
79
- SANDBOX_TASK_TEXT,
80
- BARE_FLAG,
81
- SKIP_PERMISSIONS_FLAG,
82
- SETTINGS_FLAG,
83
- str(settings_path),
84
- ]
85
-
86
-
87
- def test_run_sandbox_records_cwd_and_argv_without_launching_claude(
88
- tmp_path: Path,
89
- ) -> None:
90
- launcher = load_launcher_module()
91
- worktree_path, settings_path = make_sandbox_worktree(tmp_path)
92
- recording_runner = RecordingCommandRunner(FAKE_RUNNER_EXIT_CODE)
93
- exit_code = launcher.run_sandbox(
94
- worktree_path,
95
- settings_path,
96
- SANDBOX_TASK_TEXT,
97
- SANDBOX_TIMEOUT_SECONDS,
98
- recording_runner,
99
- )
100
- assert exit_code == FAKE_RUNNER_EXIT_CODE
101
- assert recording_runner.call_count == 1
102
- assert recording_runner.recorded_working_directory == worktree_path
103
- assert recording_runner.recorded_tokens == launcher.build_sandbox_command(
104
- SANDBOX_TASK_TEXT, settings_path
105
- )
106
- assert recording_runner.recorded_timeout_seconds == SANDBOX_TIMEOUT_SECONDS
107
-
108
-
109
- def test_validate_sandbox_paths_passes_when_every_path_exists(tmp_path: Path) -> None:
110
- launcher = load_launcher_module()
111
- worktree_path, settings_path = make_sandbox_worktree(tmp_path)
112
- task_file_path = make_task_file(tmp_path)
113
- error_message = launcher.validate_sandbox_paths(
114
- worktree_path, settings_path, task_file_path
115
- )
116
- assert error_message is None
117
-
118
-
119
- def test_validate_sandbox_paths_reports_a_missing_worktree(tmp_path: Path) -> None:
120
- launcher = load_launcher_module()
121
- _, settings_path = make_sandbox_worktree(tmp_path)
122
- task_file_path = make_task_file(tmp_path)
123
- error_message = launcher.validate_sandbox_paths(
124
- tmp_path / "absent-worktree", settings_path, task_file_path
125
- )
126
- assert error_message is not None
127
- assert "worktree" in error_message
128
-
129
-
130
- def test_validate_sandbox_paths_reports_a_missing_task_file(tmp_path: Path) -> None:
131
- launcher = load_launcher_module()
132
- worktree_path, settings_path = make_sandbox_worktree(tmp_path)
133
- error_message = launcher.validate_sandbox_paths(
134
- worktree_path, settings_path, tmp_path / "absent-task.txt"
135
- )
136
- assert error_message is not None
137
- assert "task file" in error_message
138
-
139
-
140
- def test_validate_sandbox_paths_reports_a_missing_settings_file(tmp_path: Path) -> None:
141
- launcher = load_launcher_module()
142
- worktree_path, _ = make_sandbox_worktree(tmp_path)
143
- task_file_path = make_task_file(tmp_path)
144
- error_message = launcher.validate_sandbox_paths(
145
- worktree_path, tmp_path / "absent-settings.json", task_file_path
146
- )
147
- assert error_message is not None
148
- assert "settings" in error_message
149
-
150
-
151
- def test_main_returns_the_missing_path_exit_code_for_an_absent_worktree(
152
- tmp_path: Path,
153
- ) -> None:
154
- launcher = load_launcher_module()
155
- _, settings_path = make_sandbox_worktree(tmp_path)
156
- task_file_path = make_task_file(tmp_path)
157
- exit_code = launcher.main(
158
- [
159
- "--worktree",
160
- str(tmp_path / "absent-worktree"),
161
- "--settings",
162
- str(settings_path),
163
- "--task-file",
164
- str(task_file_path),
165
- ]
166
- )
167
- assert exit_code == LAUNCH_MISSING_PATH_EXIT_CODE
168
-
169
-
170
- def test_main_runs_the_sandbox_and_returns_the_runner_exit_code(
171
- tmp_path: Path, monkeypatch: pytest.MonkeyPatch
172
- ) -> None:
173
- launcher = load_launcher_module()
174
- worktree_path, settings_path = make_sandbox_worktree(tmp_path)
175
- task_file_path = make_task_file(tmp_path)
176
- recording_runner = RecordingCommandRunner(FAKE_RUNNER_EXIT_CODE)
177
- monkeypatch.setattr(launcher, "_run_via_subprocess", recording_runner)
178
- exit_code = launcher.main(
179
- [
180
- "--worktree",
181
- str(worktree_path),
182
- "--settings",
183
- str(settings_path),
184
- "--task-file",
185
- str(task_file_path),
186
- ]
187
- )
188
- assert exit_code == FAKE_RUNNER_EXIT_CODE
189
- assert recording_runner.call_count == 1
190
- assert recording_runner.recorded_working_directory == worktree_path.resolve()
191
-
192
-
193
- def test_run_via_subprocess_returns_the_timeout_code_when_the_session_outruns(
194
- tmp_path: Path, monkeypatch: pytest.MonkeyPatch
195
- ) -> None:
196
- launcher = load_launcher_module()
197
- worktree_path, _ = make_sandbox_worktree(tmp_path)
198
-
199
- def raise_timeout(*_args: object, **_kwargs: object) -> object:
200
- raise launcher.subprocess.TimeoutExpired(
201
- cmd=[CLAUDE_EXECUTABLE_NAME], timeout=SANDBOX_TIMEOUT_SECONDS
202
- )
203
-
204
- monkeypatch.setattr(launcher.subprocess, "run", raise_timeout)
205
- exit_code = launcher._run_via_subprocess(
206
- [CLAUDE_EXECUTABLE_NAME], worktree_path, SANDBOX_TIMEOUT_SECONDS
207
- )
208
- assert exit_code == launcher.LAUNCH_TIMEOUT_EXIT_CODE
209
-
210
-
211
- def test_run_via_subprocess_returns_the_missing_path_code_when_claude_is_absent(
212
- tmp_path: Path, monkeypatch: pytest.MonkeyPatch
213
- ) -> None:
214
- launcher = load_launcher_module()
215
- worktree_path, _ = make_sandbox_worktree(tmp_path)
216
-
217
- def raise_file_not_found(*_args: object, **_kwargs: object) -> object:
218
- raise FileNotFoundError(CLAUDE_EXECUTABLE_NAME)
219
-
220
- monkeypatch.setattr(launcher.subprocess, "run", raise_file_not_found)
221
- exit_code = launcher._run_via_subprocess(
222
- [CLAUDE_EXECUTABLE_NAME], worktree_path, SANDBOX_TIMEOUT_SECONDS
223
- )
224
- assert exit_code == LAUNCH_MISSING_PATH_EXIT_CODE
225
-
226
-
227
- def test_main_returns_the_missing_path_code_when_claude_is_absent(
228
- tmp_path: Path, monkeypatch: pytest.MonkeyPatch, capsys: pytest.CaptureFixture[str]
229
- ) -> None:
230
- launcher = load_launcher_module()
231
- worktree_path, settings_path = make_sandbox_worktree(tmp_path)
232
- task_file_path = make_task_file(tmp_path)
233
-
234
- def raise_file_not_found(*_args: object, **_kwargs: object) -> object:
235
- raise FileNotFoundError(CLAUDE_EXECUTABLE_NAME)
236
-
237
- monkeypatch.setattr(launcher.subprocess, "run", raise_file_not_found)
238
- exit_code = launcher.main(
239
- [
240
- "--worktree",
241
- str(worktree_path),
242
- "--settings",
243
- str(settings_path),
244
- "--task-file",
245
- str(task_file_path),
246
- ]
247
- )
248
- assert exit_code == LAUNCH_MISSING_PATH_EXIT_CODE
249
- emitted_summary = launcher.json.loads(capsys.readouterr().out)
250
- assert emitted_summary["exit_code"] == LAUNCH_MISSING_PATH_EXIT_CODE
251
-
252
-
253
- def test_main_returns_the_timeout_code_and_emits_the_summary_on_timeout(
254
- tmp_path: Path, monkeypatch: pytest.MonkeyPatch, capsys: pytest.CaptureFixture[str]
255
- ) -> None:
256
- launcher = load_launcher_module()
257
- worktree_path, settings_path = make_sandbox_worktree(tmp_path)
258
- task_file_path = make_task_file(tmp_path)
259
-
260
- def raise_timeout(*_args: object, **_kwargs: object) -> object:
261
- raise launcher.subprocess.TimeoutExpired(
262
- cmd=[CLAUDE_EXECUTABLE_NAME], timeout=SANDBOX_TIMEOUT_SECONDS
263
- )
264
-
265
- monkeypatch.setattr(launcher.subprocess, "run", raise_timeout)
266
- exit_code = launcher.main(
267
- [
268
- "--worktree",
269
- str(worktree_path),
270
- "--settings",
271
- str(settings_path),
272
- "--task-file",
273
- str(task_file_path),
274
- ]
275
- )
276
- assert exit_code == launcher.LAUNCH_TIMEOUT_EXIT_CODE
277
- emitted_summary = launcher.json.loads(capsys.readouterr().out)
278
- assert emitted_summary["exit_code"] == launcher.LAUNCH_TIMEOUT_EXIT_CODE
279
-
280
-
281
- def test_main_resolves_a_relative_settings_path_to_absolute(
282
- tmp_path: Path, monkeypatch: pytest.MonkeyPatch
283
- ) -> None:
284
- launcher = load_launcher_module()
285
- worktree_path, settings_path = make_sandbox_worktree(tmp_path)
286
- task_file_path = make_task_file(tmp_path)
287
- recording_runner = RecordingCommandRunner(FAKE_RUNNER_EXIT_CODE)
288
- monkeypatch.setattr(launcher, "_run_via_subprocess", recording_runner)
289
- monkeypatch.chdir(tmp_path)
290
- launcher.main(
291
- [
292
- "--worktree",
293
- worktree_path.name,
294
- "--settings",
295
- settings_path.name,
296
- "--task-file",
297
- task_file_path.name,
298
- ]
299
- )
300
- recorded_settings_token = recording_runner.recorded_tokens[-1]
301
- assert Path(recorded_settings_token).is_absolute()
302
- assert Path(recorded_settings_token) == settings_path.resolve()
303
- assert recording_runner.recorded_working_directory == worktree_path.resolve()