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,537 +0,0 @@
1
- """Behavior tests for the session_edit_stage_gate PreToolUse hook.
2
-
3
- Each test builds a real git repository in a temporary directory, records a
4
- session-edit set in a redirected temp directory, and runs the hook script as a
5
- subprocess with a PreToolUse JSON payload on stdin — the exact production
6
- invocation path. Environment overrides point ``tempfile.gettempdir`` at the
7
- per-test temp directory (so the hook reads the test's session-edit file) and
8
- point the home directory at a per-test directory (so the block log stays out of
9
- the real home).
10
- """
11
-
12
- from __future__ import annotations
13
-
14
- import json
15
- import os
16
- import subprocess
17
- import sys
18
- from pathlib import Path
19
-
20
- _HOOK_DIR = Path(__file__).resolve().parent
21
- _HOOKS_TREE = _HOOK_DIR.parent
22
- for each_path in (str(_HOOKS_TREE),):
23
- if each_path not in sys.path:
24
- sys.path.insert(0, each_path)
25
-
26
- from hooks_constants.session_edit_stage_gate_constants import ( # noqa: E402
27
- ALL_EDITED_FILE_PATHS_KEY,
28
- SESSION_EDIT_FILE_PREFIX,
29
- SESSION_EDIT_FILE_SUFFIX,
30
- )
31
-
32
- HOOK_PATH = _HOOK_DIR / "session_edit_stage_gate.py"
33
- _SESSION_ID = "gate-session-1"
34
-
35
-
36
- def _clean_git_environment() -> dict[str, str]:
37
- return {
38
- each_key: each_value
39
- for each_key, each_value in os.environ.items()
40
- if not each_key.startswith("GIT_")
41
- }
42
-
43
-
44
- def run_git(repository_root: Path, *git_arguments: str) -> None:
45
- subprocess.run(
46
- ["git", "-C", str(repository_root), *git_arguments],
47
- check=True,
48
- capture_output=True,
49
- env=_clean_git_environment(),
50
- )
51
-
52
-
53
- def initialize_repository(repository_root: Path) -> None:
54
- run_git(repository_root, "init")
55
- run_git(repository_root, "config", "user.email", "tests@example.com")
56
- run_git(repository_root, "config", "user.name", "Gate Tests")
57
-
58
-
59
- def prepare_repository_with_unstaged_edit(repository_root: Path) -> Path:
60
- initialize_repository(repository_root)
61
- tracked_file = repository_root / "widget.py"
62
- tracked_file.write_text("x = 1\n", encoding="utf-8")
63
- run_git(repository_root, "add", "widget.py")
64
- run_git(repository_root, "commit", "-m", "add widget")
65
- tracked_file.write_text("x = 2\n", encoding="utf-8")
66
- return tracked_file
67
-
68
-
69
- def write_session_edits(temp_directory: Path, session_id: str, absolute_paths: list[Path]) -> None:
70
- edit_file = temp_directory / f"{SESSION_EDIT_FILE_PREFIX}{session_id}{SESSION_EDIT_FILE_SUFFIX}"
71
- payload = {ALL_EDITED_FILE_PATHS_KEY: [str(each_path) for each_path in absolute_paths]}
72
- edit_file.write_text(json.dumps(payload), encoding="utf-8")
73
-
74
-
75
- def run_hook(
76
- command: str,
77
- session_id: str,
78
- cwd: Path,
79
- temp_directory: Path,
80
- home_directory: Path,
81
- ) -> subprocess.CompletedProcess[str]:
82
- environment = _clean_git_environment()
83
- environment["TMP"] = str(temp_directory)
84
- environment["TEMP"] = str(temp_directory)
85
- environment["TMPDIR"] = str(temp_directory)
86
- environment["USERPROFILE"] = str(home_directory)
87
- environment["HOME"] = str(home_directory)
88
- payload = json.dumps({"session_id": session_id, "tool_input": {"command": command}})
89
- return subprocess.run(
90
- [sys.executable, str(HOOK_PATH)],
91
- check=False,
92
- input=payload,
93
- capture_output=True,
94
- text=True,
95
- cwd=str(cwd),
96
- env=environment,
97
- timeout=60,
98
- )
99
-
100
-
101
- def _make_directories(tmp_path: Path) -> tuple[Path, Path, Path]:
102
- repository_root = tmp_path / "repo"
103
- repository_root.mkdir()
104
- temp_directory = tmp_path / "tmp"
105
- temp_directory.mkdir()
106
- home_directory = tmp_path / "home"
107
- home_directory.mkdir()
108
- return repository_root, temp_directory, home_directory
109
-
110
-
111
- def parse_denial(hook_stdout: str) -> dict:
112
- return json.loads(hook_stdout)["hookSpecificOutput"]
113
-
114
-
115
- def test_denies_commit_dropping_session_edited_unstaged_file(tmp_path: Path) -> None:
116
- repository_root, temp_directory, home_directory = _make_directories(tmp_path)
117
- tracked_file = prepare_repository_with_unstaged_edit(repository_root)
118
- write_session_edits(temp_directory, _SESSION_ID, [tracked_file.resolve()])
119
- completed_hook = run_hook(
120
- "git commit -m update", _SESSION_ID, repository_root, temp_directory, home_directory
121
- )
122
- assert completed_hook.returncode == 0
123
- denial = parse_denial(completed_hook.stdout)
124
- assert denial["permissionDecision"] == "deny"
125
- assert "widget.py" in denial["permissionDecisionReason"]
126
-
127
-
128
- def test_deny_writes_hook_block_log(tmp_path: Path) -> None:
129
- repository_root, temp_directory, home_directory = _make_directories(tmp_path)
130
- tracked_file = prepare_repository_with_unstaged_edit(repository_root)
131
- write_session_edits(temp_directory, _SESSION_ID, [tracked_file.resolve()])
132
- run_hook("git commit -m update", _SESSION_ID, repository_root, temp_directory, home_directory)
133
- logs_directory = home_directory / ".claude" / "logs"
134
- all_log_files = list(logs_directory.glob("*.log"))
135
- assert all_log_files
136
- all_log_text = "".join(each_file.read_text(encoding="utf-8") for each_file in all_log_files)
137
- assert "session_edit_stage_gate.py" in all_log_text
138
-
139
-
140
- def test_allows_commit_when_session_edited_file_is_staged(tmp_path: Path) -> None:
141
- repository_root, temp_directory, home_directory = _make_directories(tmp_path)
142
- tracked_file = prepare_repository_with_unstaged_edit(repository_root)
143
- run_git(repository_root, "add", "widget.py")
144
- write_session_edits(temp_directory, _SESSION_ID, [tracked_file.resolve()])
145
- completed_hook = run_hook(
146
- "git commit -m update", _SESSION_ID, repository_root, temp_directory, home_directory
147
- )
148
- assert completed_hook.returncode == 0
149
- assert completed_hook.stdout.strip() == ""
150
-
151
-
152
- def test_allows_commit_all_flag(tmp_path: Path) -> None:
153
- repository_root, temp_directory, home_directory = _make_directories(tmp_path)
154
- tracked_file = prepare_repository_with_unstaged_edit(repository_root)
155
- write_session_edits(temp_directory, _SESSION_ID, [tracked_file.resolve()])
156
- completed_hook = run_hook(
157
- "git commit -a -m update", _SESSION_ID, repository_root, temp_directory, home_directory
158
- )
159
- assert completed_hook.returncode == 0
160
- assert completed_hook.stdout.strip() == ""
161
-
162
-
163
- def test_allows_non_commit_command_containing_git_commit_substring(tmp_path: Path) -> None:
164
- repository_root, temp_directory, home_directory = _make_directories(tmp_path)
165
- tracked_file = prepare_repository_with_unstaged_edit(repository_root)
166
- write_session_edits(temp_directory, _SESSION_ID, [tracked_file.resolve()])
167
- completed_hook = run_hook(
168
- 'grep -rn "git commit" .',
169
- _SESSION_ID,
170
- repository_root,
171
- temp_directory,
172
- home_directory,
173
- )
174
- assert completed_hook.returncode == 0
175
- assert completed_hook.stdout.strip() == ""
176
-
177
-
178
- def test_allows_all_flag_commit_after_bare_commit_token_segment(tmp_path: Path) -> None:
179
- repository_root, temp_directory, home_directory = _make_directories(tmp_path)
180
- tracked_file = prepare_repository_with_unstaged_edit(repository_root)
181
- write_session_edits(temp_directory, _SESSION_ID, [tracked_file.resolve()])
182
- completed_hook = run_hook(
183
- "echo commit && git commit -a -m update",
184
- _SESSION_ID,
185
- repository_root,
186
- temp_directory,
187
- home_directory,
188
- )
189
- assert completed_hook.returncode == 0
190
- assert completed_hook.stdout.strip() == ""
191
-
192
-
193
- def test_allows_non_git_command_with_git_and_commit_as_arguments(tmp_path: Path) -> None:
194
- repository_root, temp_directory, home_directory = _make_directories(tmp_path)
195
- tracked_file = prepare_repository_with_unstaged_edit(repository_root)
196
- write_session_edits(temp_directory, _SESSION_ID, [tracked_file.resolve()])
197
- completed_hook = run_hook(
198
- "echo git commit",
199
- _SESSION_ID,
200
- repository_root,
201
- temp_directory,
202
- home_directory,
203
- )
204
- assert completed_hook.returncode == 0
205
- assert completed_hook.stdout.strip() == ""
206
-
207
-
208
- def test_denies_commit_with_leading_environment_assignment(tmp_path: Path) -> None:
209
- repository_root, temp_directory, home_directory = _make_directories(tmp_path)
210
- tracked_file = prepare_repository_with_unstaged_edit(repository_root)
211
- write_session_edits(temp_directory, _SESSION_ID, [tracked_file.resolve()])
212
- completed_hook = run_hook(
213
- "GIT_AUTHOR_NAME=x git commit -m update",
214
- _SESSION_ID,
215
- repository_root,
216
- temp_directory,
217
- home_directory,
218
- )
219
- assert completed_hook.returncode == 0
220
- denial = parse_denial(completed_hook.stdout)
221
- assert denial["permissionDecision"] == "deny"
222
- assert "widget.py" in denial["permissionDecisionReason"]
223
-
224
-
225
- def test_denies_commit_with_no_space_message_containing_letter_a(tmp_path: Path) -> None:
226
- repository_root, temp_directory, home_directory = _make_directories(tmp_path)
227
- tracked_file = prepare_repository_with_unstaged_edit(repository_root)
228
- write_session_edits(temp_directory, _SESSION_ID, [tracked_file.resolve()])
229
- completed_hook = run_hook(
230
- 'git commit -m"add feature"',
231
- _SESSION_ID,
232
- repository_root,
233
- temp_directory,
234
- home_directory,
235
- )
236
- assert completed_hook.returncode == 0
237
- denial = parse_denial(completed_hook.stdout)
238
- assert denial["permissionDecision"] == "deny"
239
- assert "widget.py" in denial["permissionDecisionReason"]
240
-
241
-
242
- def test_denies_commit_with_no_space_message_option_form(tmp_path: Path) -> None:
243
- repository_root, temp_directory, home_directory = _make_directories(tmp_path)
244
- tracked_file = prepare_repository_with_unstaged_edit(repository_root)
245
- write_session_edits(temp_directory, _SESSION_ID, [tracked_file.resolve()])
246
- completed_hook = run_hook(
247
- "git commit -mupdate", _SESSION_ID, repository_root, temp_directory, home_directory
248
- )
249
- assert completed_hook.returncode == 0
250
- denial = parse_denial(completed_hook.stdout)
251
- assert denial["permissionDecision"] == "deny"
252
- assert "widget.py" in denial["permissionDecisionReason"]
253
-
254
-
255
- def test_allows_clustered_all_and_message_flags(tmp_path: Path) -> None:
256
- repository_root, temp_directory, home_directory = _make_directories(tmp_path)
257
- tracked_file = prepare_repository_with_unstaged_edit(repository_root)
258
- write_session_edits(temp_directory, _SESSION_ID, [tracked_file.resolve()])
259
- completed_hook = run_hook(
260
- "git commit -am update", _SESSION_ID, repository_root, temp_directory, home_directory
261
- )
262
- assert completed_hook.returncode == 0
263
- assert completed_hook.stdout.strip() == ""
264
-
265
-
266
- def test_allows_commit_when_add_stages_in_same_command(tmp_path: Path) -> None:
267
- repository_root, temp_directory, home_directory = _make_directories(tmp_path)
268
- tracked_file = prepare_repository_with_unstaged_edit(repository_root)
269
- write_session_edits(temp_directory, _SESSION_ID, [tracked_file.resolve()])
270
- completed_hook = run_hook(
271
- "git add widget.py && git commit -m update",
272
- _SESSION_ID,
273
- repository_root,
274
- temp_directory,
275
- home_directory,
276
- )
277
- assert completed_hook.returncode == 0
278
- assert completed_hook.stdout.strip() == ""
279
-
280
-
281
- def test_allows_commit_when_git_dash_c_add_stages_in_same_command(tmp_path: Path) -> None:
282
- repository_root, temp_directory, home_directory = _make_directories(tmp_path)
283
- tracked_file = prepare_repository_with_unstaged_edit(repository_root)
284
- write_session_edits(temp_directory, _SESSION_ID, [tracked_file.resolve()])
285
- completed_hook = run_hook(
286
- f'git -C "{repository_root}" add widget.py && git commit -m update',
287
- _SESSION_ID,
288
- repository_root,
289
- temp_directory,
290
- home_directory,
291
- )
292
- assert completed_hook.returncode == 0
293
- assert completed_hook.stdout.strip() == ""
294
-
295
-
296
- def test_denies_commit_when_specific_add_leaves_session_edit_unstaged(tmp_path: Path) -> None:
297
- repository_root, temp_directory, home_directory = _make_directories(tmp_path)
298
- tracked_file = prepare_repository_with_unstaged_edit(repository_root)
299
- readme_file = repository_root / "README.md"
300
- readme_file.write_text("readme\n", encoding="utf-8")
301
- run_git(repository_root, "add", "README.md")
302
- run_git(repository_root, "commit", "-m", "add readme")
303
- write_session_edits(temp_directory, _SESSION_ID, [tracked_file.resolve()])
304
- completed_hook = run_hook(
305
- "git add README.md && git commit -m update",
306
- _SESSION_ID,
307
- repository_root,
308
- temp_directory,
309
- home_directory,
310
- )
311
- assert completed_hook.returncode == 0
312
- denial = parse_denial(completed_hook.stdout)
313
- assert denial["permissionDecision"] == "deny"
314
- assert "widget.py" in denial["permissionDecisionReason"]
315
-
316
-
317
- def test_allows_commit_when_stage_all_add_precedes(tmp_path: Path) -> None:
318
- repository_root, temp_directory, home_directory = _make_directories(tmp_path)
319
- tracked_file = prepare_repository_with_unstaged_edit(repository_root)
320
- write_session_edits(temp_directory, _SESSION_ID, [tracked_file.resolve()])
321
- completed_hook = run_hook(
322
- "git add -A && git commit -m update",
323
- _SESSION_ID,
324
- repository_root,
325
- temp_directory,
326
- home_directory,
327
- )
328
- assert completed_hook.returncode == 0
329
- assert completed_hook.stdout.strip() == ""
330
-
331
-
332
- def test_allows_commit_when_dash_named_path_staged_after_end_of_options(tmp_path: Path) -> None:
333
- repository_root, temp_directory, home_directory = _make_directories(tmp_path)
334
- initialize_repository(repository_root)
335
- tracked_file = repository_root / "-weird.py"
336
- tracked_file.write_text("x = 1\n", encoding="utf-8")
337
- run_git(repository_root, "add", "--", "-weird.py")
338
- run_git(repository_root, "commit", "-m", "add weird")
339
- tracked_file.write_text("x = 2\n", encoding="utf-8")
340
- write_session_edits(temp_directory, _SESSION_ID, [tracked_file.resolve()])
341
- completed_hook = run_hook(
342
- "git add -- -weird.py && git commit -m update",
343
- _SESSION_ID,
344
- repository_root,
345
- temp_directory,
346
- home_directory,
347
- )
348
- assert completed_hook.returncode == 0
349
- assert completed_hook.stdout.strip() == ""
350
-
351
-
352
- def test_denies_when_dash_a_filename_staged_after_end_of_options(tmp_path: Path) -> None:
353
- repository_root, temp_directory, home_directory = _make_directories(tmp_path)
354
- tracked_file = prepare_repository_with_unstaged_edit(repository_root)
355
- dash_a_file = repository_root / "-A"
356
- dash_a_file.write_text("a\n", encoding="utf-8")
357
- run_git(repository_root, "add", "--", "-A")
358
- run_git(repository_root, "commit", "-m", "add dash-a file")
359
- write_session_edits(temp_directory, _SESSION_ID, [tracked_file.resolve()])
360
- completed_hook = run_hook(
361
- "git add -- -A && git commit -m update",
362
- _SESSION_ID,
363
- repository_root,
364
- temp_directory,
365
- home_directory,
366
- )
367
- assert completed_hook.returncode == 0
368
- denial = parse_denial(completed_hook.stdout)
369
- assert denial["permissionDecision"] == "deny"
370
- assert "widget.py" in denial["permissionDecisionReason"]
371
-
372
-
373
- def test_denies_commit_when_add_runs_after_commit_segment(tmp_path: Path) -> None:
374
- repository_root, temp_directory, home_directory = _make_directories(tmp_path)
375
- tracked_file = prepare_repository_with_unstaged_edit(repository_root)
376
- write_session_edits(temp_directory, _SESSION_ID, [tracked_file.resolve()])
377
- completed_hook = run_hook(
378
- "git commit -m update ; git add widget.py",
379
- _SESSION_ID,
380
- repository_root,
381
- temp_directory,
382
- home_directory,
383
- )
384
- assert completed_hook.returncode == 0
385
- denial = parse_denial(completed_hook.stdout)
386
- assert denial["permissionDecision"] == "deny"
387
- assert "widget.py" in denial["permissionDecisionReason"]
388
-
389
-
390
- def test_allows_pathspec_commit(tmp_path: Path) -> None:
391
- repository_root, temp_directory, home_directory = _make_directories(tmp_path)
392
- tracked_file = prepare_repository_with_unstaged_edit(repository_root)
393
- write_session_edits(temp_directory, _SESSION_ID, [tracked_file.resolve()])
394
- completed_hook = run_hook(
395
- "git commit -m update widget.py",
396
- _SESSION_ID,
397
- repository_root,
398
- temp_directory,
399
- home_directory,
400
- )
401
- assert completed_hook.returncode == 0
402
- assert completed_hook.stdout.strip() == ""
403
-
404
-
405
- def test_allows_partial_commit_marker(tmp_path: Path) -> None:
406
- repository_root, temp_directory, home_directory = _make_directories(tmp_path)
407
- tracked_file = prepare_repository_with_unstaged_edit(repository_root)
408
- write_session_edits(temp_directory, _SESSION_ID, [tracked_file.resolve()])
409
- completed_hook = run_hook(
410
- "git commit -m update # partial-commit",
411
- _SESSION_ID,
412
- repository_root,
413
- temp_directory,
414
- home_directory,
415
- )
416
- assert completed_hook.returncode == 0
417
- assert completed_hook.stdout.strip() == ""
418
-
419
-
420
- def test_denies_when_marker_not_trailing(tmp_path: Path) -> None:
421
- repository_root, temp_directory, home_directory = _make_directories(tmp_path)
422
- tracked_file = prepare_repository_with_unstaged_edit(repository_root)
423
- write_session_edits(temp_directory, _SESSION_ID, [tracked_file.resolve()])
424
- completed_hook = run_hook(
425
- "echo # partial-commit && git commit -m update",
426
- _SESSION_ID,
427
- repository_root,
428
- temp_directory,
429
- home_directory,
430
- )
431
- assert completed_hook.returncode == 0
432
- denial = parse_denial(completed_hook.stdout)
433
- assert denial["permissionDecision"] == "deny"
434
- assert "widget.py" in denial["permissionDecisionReason"]
435
-
436
-
437
- def test_denies_when_marker_only_inside_commit_message(tmp_path: Path) -> None:
438
- repository_root, temp_directory, home_directory = _make_directories(tmp_path)
439
- tracked_file = prepare_repository_with_unstaged_edit(repository_root)
440
- write_session_edits(temp_directory, _SESSION_ID, [tracked_file.resolve()])
441
- completed_hook = run_hook(
442
- 'git commit -m "fix # partial-commit substring handling"',
443
- _SESSION_ID,
444
- repository_root,
445
- temp_directory,
446
- home_directory,
447
- )
448
- assert completed_hook.returncode == 0
449
- denial = parse_denial(completed_hook.stdout)
450
- assert denial["permissionDecision"] == "deny"
451
- assert "widget.py" in denial["permissionDecisionReason"]
452
-
453
-
454
- def test_denies_commit_dropping_non_ascii_named_file(tmp_path: Path) -> None:
455
- repository_root, temp_directory, home_directory = _make_directories(tmp_path)
456
- initialize_repository(repository_root)
457
- tracked_file = repository_root / "café.py"
458
- tracked_file.write_text("x = 1\n", encoding="utf-8")
459
- run_git(repository_root, "add", "café.py")
460
- run_git(repository_root, "commit", "-m", "add cafe")
461
- tracked_file.write_text("x = 2\n", encoding="utf-8")
462
- write_session_edits(temp_directory, _SESSION_ID, [tracked_file.resolve()])
463
- completed_hook = run_hook(
464
- "git commit -m update", _SESSION_ID, repository_root, temp_directory, home_directory
465
- )
466
- assert completed_hook.returncode == 0
467
- denial = parse_denial(completed_hook.stdout)
468
- assert denial["permissionDecision"] == "deny"
469
- assert "café.py" in denial["permissionDecisionReason"]
470
-
471
-
472
- def test_allows_amend_still_gates(tmp_path: Path) -> None:
473
- repository_root, temp_directory, home_directory = _make_directories(tmp_path)
474
- tracked_file = prepare_repository_with_unstaged_edit(repository_root)
475
- write_session_edits(temp_directory, _SESSION_ID, [tracked_file.resolve()])
476
- completed_hook = run_hook(
477
- "git commit --amend -m update",
478
- _SESSION_ID,
479
- repository_root,
480
- temp_directory,
481
- home_directory,
482
- )
483
- assert completed_hook.returncode == 0
484
- denial = parse_denial(completed_hook.stdout)
485
- assert denial["permissionDecision"] == "deny"
486
-
487
-
488
- def test_allows_when_no_tracker_file(tmp_path: Path) -> None:
489
- repository_root, temp_directory, home_directory = _make_directories(tmp_path)
490
- prepare_repository_with_unstaged_edit(repository_root)
491
- completed_hook = run_hook(
492
- "git commit -m update", _SESSION_ID, repository_root, temp_directory, home_directory
493
- )
494
- assert completed_hook.returncode == 0
495
- assert completed_hook.stdout.strip() == ""
496
-
497
-
498
- def test_allows_non_commit_command(tmp_path: Path) -> None:
499
- repository_root, temp_directory, home_directory = _make_directories(tmp_path)
500
- tracked_file = prepare_repository_with_unstaged_edit(repository_root)
501
- write_session_edits(temp_directory, _SESSION_ID, [tracked_file.resolve()])
502
- completed_hook = run_hook(
503
- "git status", _SESSION_ID, repository_root, temp_directory, home_directory
504
- )
505
- assert completed_hook.returncode == 0
506
- assert completed_hook.stdout.strip() == ""
507
-
508
-
509
- def test_allows_when_unstaged_file_not_session_edited(tmp_path: Path) -> None:
510
- repository_root, temp_directory, home_directory = _make_directories(tmp_path)
511
- prepare_repository_with_unstaged_edit(repository_root)
512
- unrelated_path = repository_root / "unrelated.py"
513
- write_session_edits(temp_directory, _SESSION_ID, [unrelated_path.resolve()])
514
- completed_hook = run_hook(
515
- "git commit -m update", _SESSION_ID, repository_root, temp_directory, home_directory
516
- )
517
- assert completed_hook.returncode == 0
518
- assert completed_hook.stdout.strip() == ""
519
-
520
-
521
- def test_git_dash_c_form_resolves_repository(tmp_path: Path) -> None:
522
- repository_root, temp_directory, home_directory = _make_directories(tmp_path)
523
- tracked_file = prepare_repository_with_unstaged_edit(repository_root)
524
- write_session_edits(temp_directory, _SESSION_ID, [tracked_file.resolve()])
525
- elsewhere = tmp_path / "elsewhere"
526
- elsewhere.mkdir()
527
- completed_hook = run_hook(
528
- f'git -C "{repository_root}" commit -m update',
529
- _SESSION_ID,
530
- elsewhere,
531
- temp_directory,
532
- home_directory,
533
- )
534
- assert completed_hook.returncode == 0
535
- denial = parse_denial(completed_hook.stdout)
536
- assert denial["permissionDecision"] == "deny"
537
- assert "widget.py" in denial["permissionDecisionReason"]
@@ -1,64 +0,0 @@
1
- """Production-path staging tests for the session-edit stage gate."""
2
-
3
- from __future__ import annotations
4
-
5
- import sys
6
- from pathlib import Path
7
-
8
- _TEST_DIRECTORY = Path(__file__).resolve().parent
9
- if str(_TEST_DIRECTORY) not in sys.path:
10
- sys.path.insert(0, str(_TEST_DIRECTORY))
11
-
12
- from test_session_edit_stage_gate_support import ( # noqa: E402
13
- make_test_directories,
14
- parse_dispatcher_decision,
15
- prepare_repository_with_unstaged_edit,
16
- run_bash_dispatcher,
17
- run_tracker_event,
18
- read_tracker_paths,
19
- )
20
-
21
- SESSION_ID = "staging-production-session"
22
-
23
-
24
- def test_dispatcher_denies_tracker_recorded_unstaged_edit(tmp_path: Path) -> None:
25
- """The Bash dispatcher denies a commit for a tracker-recorded edit."""
26
- repository_root, temp_directory, home_directory = make_test_directories(tmp_path)
27
- tracked_file = prepare_repository_with_unstaged_edit(repository_root)
28
- tracker_run = run_tracker_event(
29
- tracked_file, SESSION_ID, repository_root, temp_directory, home_directory
30
- )
31
- assert tracker_run.returncode == 0
32
- assert read_tracker_paths(temp_directory, SESSION_ID) == [str(tracked_file.resolve())]
33
-
34
- dispatcher_run = run_bash_dispatcher(
35
- "git commit -m update",
36
- SESSION_ID,
37
- repository_root,
38
- temp_directory,
39
- home_directory,
40
- )
41
- assert dispatcher_run.returncode == 0
42
- decision, reason = parse_dispatcher_decision(dispatcher_run.stdout)
43
- assert decision == "deny"
44
- assert "widget.py" in reason
45
-
46
-
47
- def test_dispatcher_allows_specific_staging_segment(tmp_path: Path) -> None:
48
- """The Bash dispatcher accepts a commit preceded by a specific git add."""
49
- repository_root, temp_directory, home_directory = make_test_directories(tmp_path)
50
- tracked_file = prepare_repository_with_unstaged_edit(repository_root)
51
- tracker_run = run_tracker_event(
52
- tracked_file, SESSION_ID, repository_root, temp_directory, home_directory
53
- )
54
- assert tracker_run.returncode == 0
55
-
56
- dispatcher_run = run_bash_dispatcher(
57
- "git add widget.py && git commit -m update",
58
- SESSION_ID,
59
- repository_root,
60
- temp_directory,
61
- home_directory,
62
- )
63
- assert dispatcher_run.returncode == 0
64
- assert parse_dispatcher_decision(dispatcher_run.stdout) == ("", "")