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,204 +0,0 @@
1
- """Production-neutral fixtures for session-edit stage gate tests."""
2
-
3
- from __future__ import annotations
4
-
5
- import json
6
- import os
7
- import subprocess
8
- import sys
9
- from pathlib import Path
10
-
11
- _SUPPORT_DIRECTORY = Path(__file__).resolve().parent
12
- _HOOKS_TREE = _SUPPORT_DIRECTORY.parent
13
- if str(_HOOKS_TREE) not in sys.path:
14
- sys.path.insert(0, str(_HOOKS_TREE))
15
-
16
- from hooks_constants.session_edit_stage_gate_constants import ( # noqa: E402
17
- ALL_EDITED_FILE_PATHS_KEY,
18
- SESSION_EDIT_FILE_PREFIX,
19
- SESSION_EDIT_FILE_SUFFIX,
20
- )
21
-
22
-
23
- def clean_git_environment() -> dict[str, str]:
24
- """Return the environment without inherited repository overrides."""
25
- return {
26
- each_key: each_value
27
- for each_key, each_value in os.environ.items()
28
- if not each_key.startswith("GIT_")
29
- }
30
-
31
-
32
- def run_git(repository_root: Path, *git_arguments: str) -> None:
33
- """Run one Git command in a test repository."""
34
- subprocess.run(
35
- ["git", "-C", str(repository_root), *git_arguments],
36
- check=True,
37
- capture_output=True,
38
- env=clean_git_environment(),
39
- )
40
-
41
-
42
- def initialize_repository(repository_root: Path) -> None:
43
- """Create a Git repository on a non-protected test branch."""
44
- run_git(repository_root, "init")
45
- run_git(repository_root, "checkout", "-b", "test-session-stage")
46
- run_git(repository_root, "config", "user.email", "tests@example.com")
47
- run_git(repository_root, "config", "user.name", "Gate Tests")
48
-
49
-
50
- def prepare_repository_with_unstaged_edit(repository_root: Path) -> Path:
51
- """Create one tracked file with an unstaged edit."""
52
- initialize_repository(repository_root)
53
- tracked_file = repository_root / "widget.py"
54
- tracked_file.write_text("x = 1\n", encoding="utf-8")
55
- run_git(repository_root, "add", "widget.py")
56
- run_git(repository_root, "commit", "-m", "add widget")
57
- tracked_file.write_text("x = 2\n", encoding="utf-8")
58
- return tracked_file
59
-
60
-
61
- def prepare_repository_with_two_unstaged_edits(repository_root: Path) -> tuple[Path, Path]:
62
- """Create two tracked files with separate unstaged edits."""
63
- initialize_repository(repository_root)
64
- tracked_file = repository_root / "widget.py"
65
- second_file = repository_root / "second_widget.py"
66
- tracked_file.write_text("x = 1\n", encoding="utf-8")
67
- second_file.write_text("y = 1\n", encoding="utf-8")
68
- run_git(repository_root, "add", "widget.py", "second_widget.py")
69
- run_git(repository_root, "commit", "-m", "add widgets")
70
- tracked_file.write_text("x = 2\n", encoding="utf-8")
71
- second_file.write_text("y = 2\n", encoding="utf-8")
72
- return tracked_file, second_file
73
-
74
-
75
- def make_test_directories(tmp_path: Path) -> tuple[Path, Path, Path]:
76
- """Create repository, tracker, and home directories for one test."""
77
- repository_root = tmp_path / "repo"
78
- repository_root.mkdir()
79
- temp_directory = tmp_path / "tmp"
80
- temp_directory.mkdir()
81
- home_directory = tmp_path / "home"
82
- home_directory.mkdir()
83
- return repository_root, temp_directory, home_directory
84
-
85
-
86
- def make_process_repository(tmp_path: Path) -> Path:
87
- """Create a separate Git repository for the dispatcher process directory."""
88
- process_repository = tmp_path / "process-repository"
89
- process_repository.mkdir()
90
- initialize_repository(process_repository)
91
- return process_repository
92
-
93
-
94
- def prepare_process_child_repository(process_repository: Path) -> None:
95
- """Create the relative command directory inside process repository B."""
96
- process_child_repository = process_repository / "child"
97
- process_child_repository.mkdir()
98
- initialize_repository(process_child_repository)
99
-
100
-
101
- def build_hook_environment(
102
- temp_directory: Path,
103
- home_directory: Path,
104
- ) -> dict[str, str]:
105
- """Build isolated environment variables for production hooks."""
106
- environment = clean_git_environment()
107
- environment["TMP"] = str(temp_directory)
108
- environment["TEMP"] = str(temp_directory)
109
- environment["TMPDIR"] = str(temp_directory)
110
- environment["USERPROFILE"] = str(home_directory)
111
- environment["HOME"] = str(home_directory)
112
- return environment
113
-
114
-
115
- def run_production_hook(
116
- hook_path: Path,
117
- payload: str,
118
- repository_root: Path,
119
- temp_directory: Path,
120
- home_directory: Path,
121
- process_directory: Path | None = None,
122
- ) -> subprocess.CompletedProcess[str]:
123
- """Run one hook script as a production subprocess."""
124
- return subprocess.run(
125
- [sys.executable, str(hook_path)],
126
- check=False,
127
- input=payload,
128
- capture_output=True,
129
- text=True,
130
- cwd=str(process_directory or repository_root),
131
- env=build_hook_environment(temp_directory, home_directory),
132
- timeout=60,
133
- )
134
-
135
-
136
- def run_tracker_event(
137
- tracked_file: Path,
138
- session_id: str,
139
- repository_root: Path,
140
- temp_directory: Path,
141
- home_directory: Path,
142
- ) -> subprocess.CompletedProcess[str]:
143
- """Run the production PostToolUse tracker for one edited file."""
144
- payload = json.dumps(
145
- {
146
- "tool_name": "Edit",
147
- "session_id": session_id,
148
- "tool_input": {"file_path": str(tracked_file)},
149
- }
150
- )
151
- return run_production_hook(
152
- _HOOKS_TREE / "observability" / "session_file_edit_tracker.py",
153
- payload,
154
- repository_root,
155
- temp_directory,
156
- home_directory,
157
- )
158
-
159
-
160
- def run_bash_dispatcher(
161
- bash_command: str,
162
- session_id: str,
163
- repository_root: Path,
164
- temp_directory: Path,
165
- home_directory: Path,
166
- process_directory: Path | None = None,
167
- ) -> subprocess.CompletedProcess[str]:
168
- """Run the production Bash PreToolUse dispatcher for one command."""
169
- payload = json.dumps(
170
- {
171
- "tool_name": "Bash",
172
- "cwd": str(repository_root),
173
- "session_id": session_id,
174
- "tool_input": {"command": bash_command},
175
- }
176
- )
177
- return run_production_hook(
178
- _SUPPORT_DIRECTORY / "bash_pre_tool_use_dispatcher.py",
179
- payload,
180
- repository_root,
181
- temp_directory,
182
- home_directory,
183
- process_directory,
184
- )
185
-
186
-
187
- def read_tracker_paths(temp_directory: Path, session_id: str) -> list[str]:
188
- """Read the recorded paths from one production tracker file."""
189
- tracker_file = (
190
- temp_directory / f"{SESSION_EDIT_FILE_PREFIX}{session_id}{SESSION_EDIT_FILE_SUFFIX}"
191
- )
192
- tracker_payload = json.loads(tracker_file.read_text(encoding="utf-8"))
193
- return tracker_payload[ALL_EDITED_FILE_PATHS_KEY]
194
-
195
-
196
- def parse_dispatcher_decision(stdout_text: str) -> tuple[str, str]:
197
- """Return the dispatcher decision and reason from its stdout payload."""
198
- if not stdout_text.strip():
199
- return "", ""
200
- hook_specific_output = json.loads(stdout_text)["hookSpecificOutput"]
201
- return (
202
- hook_specific_output.get("permissionDecision", ""),
203
- hook_specific_output.get("permissionDecisionReason", ""),
204
- )
@@ -1,116 +0,0 @@
1
- """Production-path tracker event-order tests for the session-edit stage gate."""
2
-
3
- from __future__ import annotations
4
-
5
- import sys
6
- from pathlib import Path
7
-
8
- import pytest
9
-
10
- _TEST_DIRECTORY = Path(__file__).resolve().parent
11
- if str(_TEST_DIRECTORY) not in sys.path:
12
- sys.path.insert(0, str(_TEST_DIRECTORY))
13
-
14
- from test_session_edit_stage_gate_support import ( # noqa: E402
15
- make_test_directories,
16
- make_process_repository,
17
- parse_dispatcher_decision,
18
- prepare_process_child_repository,
19
- prepare_repository_with_unstaged_edit,
20
- prepare_repository_with_two_unstaged_edits,
21
- read_tracker_paths,
22
- run_bash_dispatcher,
23
- run_tracker_event,
24
- )
25
-
26
- SESSION_ID = "tracker-production-session"
27
-
28
-
29
- def test_tracker_events_precede_dispatcher_stage_decision(tmp_path: Path) -> None:
30
- """The dispatcher sees every edit recorded before the commit event."""
31
- repository_root, temp_directory, home_directory = make_test_directories(tmp_path)
32
- tracked_file, second_file = prepare_repository_with_two_unstaged_edits(repository_root)
33
- for each_file in (tracked_file, second_file):
34
- tracker_run = run_tracker_event(
35
- each_file, SESSION_ID, repository_root, temp_directory, home_directory
36
- )
37
- assert tracker_run.returncode == 0
38
-
39
- assert read_tracker_paths(temp_directory, SESSION_ID) == [
40
- str(tracked_file.resolve()),
41
- str(second_file.resolve()),
42
- ]
43
-
44
- dispatcher_run = run_bash_dispatcher(
45
- "git commit -m update",
46
- SESSION_ID,
47
- repository_root,
48
- temp_directory,
49
- home_directory,
50
- )
51
- assert dispatcher_run.returncode == 0
52
- decision, reason = parse_dispatcher_decision(dispatcher_run.stdout)
53
- assert decision == "deny"
54
- assert "widget.py" in reason
55
- assert "second_widget.py" in reason
56
-
57
-
58
- def test_dispatcher_uses_event_cwd_when_process_runs_elsewhere(tmp_path: Path) -> None:
59
- """The dispatcher passes event cwd so the gate inspects the event repository."""
60
- repository_root, temp_directory, home_directory = make_test_directories(tmp_path)
61
- process_repository = make_process_repository(tmp_path)
62
- tracked_file = prepare_repository_with_unstaged_edit(repository_root)
63
- tracker_run = run_tracker_event(
64
- tracked_file, SESSION_ID, repository_root, temp_directory, home_directory
65
- )
66
- assert tracker_run.returncode == 0
67
-
68
- dispatcher_run = run_bash_dispatcher(
69
- "git commit -m update",
70
- SESSION_ID,
71
- repository_root,
72
- temp_directory,
73
- home_directory,
74
- process_directory=process_repository,
75
- )
76
- assert dispatcher_run.returncode == 0
77
- decision, reason = parse_dispatcher_decision(dispatcher_run.stdout)
78
- assert decision == "deny"
79
- assert "widget.py" in reason
80
-
81
-
82
- @pytest.mark.parametrize(
83
- "bash_command",
84
- [
85
- "cd child && git commit -m update",
86
- "pushd child && git commit -m update",
87
- "git -C child commit -m update",
88
- ],
89
- )
90
- def test_dispatcher_anchors_relative_command_directory_to_event_cwd(
91
- tmp_path: Path,
92
- bash_command: str,
93
- ) -> None:
94
- """Relative commit directories resolve from event cwd across command forms."""
95
- repository_root, temp_directory, home_directory = make_test_directories(tmp_path)
96
- process_repository = make_process_repository(tmp_path)
97
- prepare_process_child_repository(process_repository)
98
- (repository_root / "child").mkdir()
99
- tracked_file = prepare_repository_with_unstaged_edit(repository_root)
100
- tracker_run = run_tracker_event(
101
- tracked_file, SESSION_ID, repository_root, temp_directory, home_directory
102
- )
103
- assert tracker_run.returncode == 0
104
-
105
- dispatcher_run = run_bash_dispatcher(
106
- bash_command,
107
- SESSION_ID,
108
- repository_root,
109
- temp_directory,
110
- home_directory,
111
- process_directory=process_repository,
112
- )
113
- assert dispatcher_run.returncode == 0
114
- decision, reason = parse_dispatcher_decision(dispatcher_run.stdout)
115
- assert decision == "deny"
116
- assert "widget.py" in reason
@@ -1,318 +0,0 @@
1
- """Tests for session_handoff_blocker hook response shape."""
2
-
3
- import importlib.util
4
- import json
5
- import os
6
- import subprocess
7
- import sys
8
-
9
- HOOK_SCRIPT_PATH = os.path.join(os.path.dirname(__file__), "session_handoff_blocker.py")
10
- _HOOKS_DIR = os.path.dirname(HOOK_SCRIPT_PATH)
11
- _HOOKS_ROOT = os.path.join(_HOOKS_DIR, "..")
12
- _HOOK_CONFIG_DIR = os.path.join(_HOOKS_ROOT, "hooks_constants")
13
- if _HOOKS_DIR not in sys.path:
14
- sys.path.insert(0, _HOOKS_DIR)
15
- if _HOOKS_ROOT not in sys.path:
16
- sys.path.insert(0, _HOOKS_ROOT)
17
- import session_handoff_blocker
18
- from hooks_constants.messages import USER_FACING_CONTEXT_REASSURANCE_NOTICE
19
- from hooks_constants.text_stripping import strip_code_and_quotes
20
-
21
-
22
- def test_blocker_uses_shared_strip_code_and_quotes() -> None:
23
- assert session_handoff_blocker.strip_code_and_quotes is strip_code_and_quotes
24
-
25
-
26
- NEW_SESSION_PROPOSAL_MESSAGE = (
27
- "I recommend we continue this in a fresh session to keep things manageable."
28
- )
29
- RUNNING_LOW_ON_CONTEXT_MESSAGE = (
30
- "We are running low on context, so let me summarize where things stand."
31
- )
32
- SHORT_ON_TOKENS_MESSAGE = "I'm getting short on tokens, so I'll wrap up here."
33
- CONSERVE_CONTEXT_MESSAGE = "To conserve context, let me stop and hand off the remaining work."
34
- CONTEXT_WINDOW_HANDOFF_MESSAGE = (
35
- "The context window is filling up, so I'll wrap up and we can continue later."
36
- )
37
- BENIGN_TOPICAL_MESSAGE = "The function accepts a context manager and a token string."
38
- CLEAN_MESSAGE = "The parser handles every fixture and returns a deduplicated list."
39
- TECHNICAL_TERMINAL_SESSION_MESSAGE = (
40
- "Consider starting a new session in your terminal to pick up the env vars."
41
- )
42
- LOAD_TEST_SESSION_MESSAGE = "We can spin up a fresh session for the load test."
43
- DATABASE_SESSION_MESSAGE = "Open a new database session before running the query."
44
- HANDOFF_NEW_SESSION_MESSAGE = (
45
- "Let's wrap up and continue this in a fresh session to pick this up later."
46
- )
47
- LOW_ON_CONTEXT_WITHOUT_CUE_MESSAGE = (
48
- "I am low on context for this edge case in the parser."
49
- )
50
- SAVE_TOKENS_REPORT_MESSAGE = "To save tokens, I inlined the constant."
51
- LOW_ON_CONTEXT_WITH_HANDOFF_CUE_MESSAGE = (
52
- "I'm low on context, so let me wrap up and hand off."
53
- )
54
- NEW_SESSION_TOKEN_MESSAGE = (
55
- "To continue this task I need the new session token from the API."
56
- )
57
- RESUME_TRAFFIC_FRESH_SESSION_POOL_MESSAGE = (
58
- "After deploy, resume traffic in a fresh session pool."
59
- )
60
- THIRD_PERSON_RUNS_LOW_DESIGN_MESSAGE = (
61
- "The agent should stop when it runs low on context, per the old design."
62
- )
63
- DOCUMENT_RUNNING_LOW_MESSAGE = (
64
- "Document that agents running low on tokens should not stop."
65
- )
66
- USER_ADVICE_NEW_SESSION_MESSAGE = (
67
- "To save tokens, you could start a new session for the unrelated task."
68
- )
69
- CONTEXT_WINDOW_SUMMARIZE_MESSAGE = (
70
- "The context window is getting full, so let me summarize where we are."
71
- )
72
- BENIGN_SUMMARIZE_REPORT_MESSAGE = "I should summarize the findings for the report."
73
- BENIGN_STOP_PLUS_UNRELATED_RUNNING_LOW_MESSAGE = (
74
- "Let me pause the animation timer. The job fails when it is running low on tokens."
75
- )
76
- BENIGN_STOP_PLUS_USER_DIRECTED_NEW_SESSION_MESSAGE = (
77
- "Let me stop the timer. The user can continue this in a fresh session."
78
- )
79
- EMPTY_MESSAGE = ""
80
-
81
-
82
- def run_hook_with_message(assistant_message: str) -> subprocess.CompletedProcess:
83
- hook_input_payload = json.dumps({"last_assistant_message": assistant_message})
84
- return subprocess.run(
85
- [sys.executable, HOOK_SCRIPT_PATH],
86
- input=hook_input_payload,
87
- capture_output=True,
88
- text=True,
89
- check=False,
90
- )
91
-
92
-
93
- def run_hook_with_payload(hook_input_payload: dict) -> subprocess.CompletedProcess:
94
- return subprocess.run(
95
- [sys.executable, HOOK_SCRIPT_PATH],
96
- input=json.dumps(hook_input_payload),
97
- capture_output=True,
98
- text=True,
99
- check=False,
100
- )
101
-
102
-
103
- def test_user_facing_notice_matches_config_messages_module():
104
- config_messages_path = os.path.join(_HOOK_CONFIG_DIR, "messages.py")
105
- specification = importlib.util.spec_from_file_location("messages", config_messages_path)
106
- module = importlib.util.module_from_spec(specification)
107
- specification.loader.exec_module(module)
108
-
109
- assert module.USER_FACING_CONTEXT_REASSURANCE_NOTICE == USER_FACING_CONTEXT_REASSURANCE_NOTICE
110
- assert (
111
- session_handoff_blocker.USER_FACING_CONTEXT_REASSURANCE_NOTICE
112
- == module.USER_FACING_CONTEXT_REASSURANCE_NOTICE
113
- )
114
-
115
-
116
- def test_new_session_proposal_emits_block_with_short_user_notice():
117
- completed_process = run_hook_with_message(NEW_SESSION_PROPOSAL_MESSAGE)
118
-
119
- assert completed_process.returncode == 0
120
- parsed_response = json.loads(completed_process.stdout)
121
-
122
- assert parsed_response["decision"] == "block"
123
- assert parsed_response["systemMessage"] == USER_FACING_CONTEXT_REASSURANCE_NOTICE
124
- assert parsed_response["suppressOutput"] is True
125
- assert "ample context remaining" in parsed_response["reason"]
126
- assert "long-horizon-autonomy" in parsed_response["reason"]
127
-
128
-
129
- def test_running_low_on_context_emits_block():
130
- completed_process = run_hook_with_message(RUNNING_LOW_ON_CONTEXT_MESSAGE)
131
-
132
- assert completed_process.returncode == 0
133
- parsed_response = json.loads(completed_process.stdout)
134
-
135
- assert parsed_response["decision"] == "block"
136
- assert parsed_response["systemMessage"] == USER_FACING_CONTEXT_REASSURANCE_NOTICE
137
-
138
-
139
- def test_short_on_tokens_emits_block():
140
- completed_process = run_hook_with_message(SHORT_ON_TOKENS_MESSAGE)
141
-
142
- assert completed_process.returncode == 0
143
- parsed_response = json.loads(completed_process.stdout)
144
-
145
- assert parsed_response["decision"] == "block"
146
-
147
-
148
- def test_conserve_context_emits_block():
149
- completed_process = run_hook_with_message(CONSERVE_CONTEXT_MESSAGE)
150
-
151
- assert completed_process.returncode == 0
152
- parsed_response = json.loads(completed_process.stdout)
153
-
154
- assert parsed_response["decision"] == "block"
155
-
156
-
157
- def test_context_window_co_occurring_handoff_cue_emits_block():
158
- completed_process = run_hook_with_message(CONTEXT_WINDOW_HANDOFF_MESSAGE)
159
-
160
- assert completed_process.returncode == 0
161
- parsed_response = json.loads(completed_process.stdout)
162
-
163
- assert parsed_response["decision"] == "block"
164
-
165
-
166
- def test_benign_topical_mention_passes_through_with_no_output():
167
- completed_process = run_hook_with_message(BENIGN_TOPICAL_MESSAGE)
168
-
169
- assert completed_process.returncode == 0
170
- assert completed_process.stdout == ""
171
-
172
-
173
- def test_technical_terminal_session_passes_through_with_no_output():
174
- completed_process = run_hook_with_message(TECHNICAL_TERMINAL_SESSION_MESSAGE)
175
-
176
- assert completed_process.returncode == 0
177
- assert completed_process.stdout == ""
178
-
179
-
180
- def test_load_test_session_passes_through_with_no_output():
181
- completed_process = run_hook_with_message(LOAD_TEST_SESSION_MESSAGE)
182
-
183
- assert completed_process.returncode == 0
184
- assert completed_process.stdout == ""
185
-
186
-
187
- def test_database_session_passes_through_with_no_output():
188
- completed_process = run_hook_with_message(DATABASE_SESSION_MESSAGE)
189
-
190
- assert completed_process.returncode == 0
191
- assert completed_process.stdout == ""
192
-
193
-
194
- def test_new_session_with_handoff_framing_emits_block():
195
- completed_process = run_hook_with_message(HANDOFF_NEW_SESSION_MESSAGE)
196
-
197
- assert completed_process.returncode == 0
198
- parsed_response = json.loads(completed_process.stdout)
199
-
200
- assert parsed_response["decision"] == "block"
201
- assert parsed_response["systemMessage"] == USER_FACING_CONTEXT_REASSURANCE_NOTICE
202
-
203
-
204
- def test_low_on_context_without_handoff_cue_passes_through_with_no_output():
205
- completed_process = run_hook_with_message(LOW_ON_CONTEXT_WITHOUT_CUE_MESSAGE)
206
-
207
- assert completed_process.returncode == 0
208
- assert completed_process.stdout == ""
209
-
210
-
211
- def test_save_tokens_work_report_passes_through_with_no_output():
212
- completed_process = run_hook_with_message(SAVE_TOKENS_REPORT_MESSAGE)
213
-
214
- assert completed_process.returncode == 0
215
- assert completed_process.stdout == ""
216
-
217
-
218
- def test_low_on_context_with_handoff_cue_emits_block():
219
- completed_process = run_hook_with_message(LOW_ON_CONTEXT_WITH_HANDOFF_CUE_MESSAGE)
220
-
221
- assert completed_process.returncode == 0
222
- parsed_response = json.loads(completed_process.stdout)
223
-
224
- assert parsed_response["decision"] == "block"
225
- assert parsed_response["systemMessage"] == USER_FACING_CONTEXT_REASSURANCE_NOTICE
226
-
227
-
228
- def test_new_session_token_passes_through_with_no_output():
229
- completed_process = run_hook_with_message(NEW_SESSION_TOKEN_MESSAGE)
230
-
231
- assert completed_process.returncode == 0
232
- assert completed_process.stdout == ""
233
-
234
-
235
- def test_resume_traffic_fresh_session_pool_passes_through_with_no_output():
236
- completed_process = run_hook_with_message(RESUME_TRAFFIC_FRESH_SESSION_POOL_MESSAGE)
237
-
238
- assert completed_process.returncode == 0
239
- assert completed_process.stdout == ""
240
-
241
-
242
- def test_third_person_runs_low_description_passes_through_with_no_output():
243
- completed_process = run_hook_with_message(THIRD_PERSON_RUNS_LOW_DESIGN_MESSAGE)
244
-
245
- assert completed_process.returncode == 0
246
- assert completed_process.stdout == ""
247
-
248
-
249
- def test_document_running_low_instruction_passes_through_with_no_output():
250
- completed_process = run_hook_with_message(DOCUMENT_RUNNING_LOW_MESSAGE)
251
-
252
- assert completed_process.returncode == 0
253
- assert completed_process.stdout == ""
254
-
255
-
256
- def test_user_directed_new_session_advice_passes_through_with_no_output():
257
- completed_process = run_hook_with_message(USER_ADVICE_NEW_SESSION_MESSAGE)
258
-
259
- assert completed_process.returncode == 0
260
- assert completed_process.stdout == ""
261
-
262
-
263
- def test_context_window_summarize_handoff_emits_block():
264
- completed_process = run_hook_with_message(CONTEXT_WINDOW_SUMMARIZE_MESSAGE)
265
-
266
- assert completed_process.returncode == 0
267
- parsed_response = json.loads(completed_process.stdout)
268
-
269
- assert parsed_response["decision"] == "block"
270
- assert parsed_response["systemMessage"] == USER_FACING_CONTEXT_REASSURANCE_NOTICE
271
-
272
-
273
- def test_benign_summarize_report_passes_through_with_no_output():
274
- completed_process = run_hook_with_message(BENIGN_SUMMARIZE_REPORT_MESSAGE)
275
-
276
- assert completed_process.returncode == 0
277
- assert completed_process.stdout == ""
278
-
279
-
280
- def test_benign_stop_with_unrelated_running_low_sentence_passes_through_with_no_output():
281
- completed_process = run_hook_with_message(
282
- BENIGN_STOP_PLUS_UNRELATED_RUNNING_LOW_MESSAGE
283
- )
284
-
285
- assert completed_process.returncode == 0
286
- assert completed_process.stdout == ""
287
-
288
-
289
- def test_benign_stop_with_user_directed_new_session_sentence_passes_through_with_no_output():
290
- completed_process = run_hook_with_message(
291
- BENIGN_STOP_PLUS_USER_DIRECTED_NEW_SESSION_MESSAGE
292
- )
293
-
294
- assert completed_process.returncode == 0
295
- assert completed_process.stdout == ""
296
-
297
-
298
- def test_clean_message_passes_through_with_no_output():
299
- completed_process = run_hook_with_message(CLEAN_MESSAGE)
300
-
301
- assert completed_process.returncode == 0
302
- assert completed_process.stdout == ""
303
-
304
-
305
- def test_empty_message_passes_through_with_no_output():
306
- completed_process = run_hook_with_message(EMPTY_MESSAGE)
307
-
308
- assert completed_process.returncode == 0
309
- assert completed_process.stdout == ""
310
-
311
-
312
- def test_stop_hook_active_short_circuits_with_no_output():
313
- completed_process = run_hook_with_payload(
314
- {"last_assistant_message": NEW_SESSION_PROPOSAL_MESSAGE, "stop_hook_active": True}
315
- )
316
-
317
- assert completed_process.returncode == 0
318
- assert completed_process.stdout == ""