claude-dev-env 4.2.0 → 7.0.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 (350) 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 +7 -0
  12. package/.agents/skills/pull-request/SKILL.md +216 -0
  13. package/.agents/skills/pull-request/reference/publication-tasks.md +18 -0
  14. package/.agents/skills/pull-request/scripts/github_pr_command_constants/__init__.py +1 -0
  15. package/.agents/skills/pull-request/scripts/github_pr_command_constants/config/__init__.py +1 -0
  16. package/.agents/skills/pull-request/scripts/github_pr_command_constants/config/constants.py +69 -0
  17. package/.agents/skills/pull-request/scripts/pull_request.py +265 -0
  18. package/.agents/skills/pull-request/scripts/recover_legacy_author.py +251 -0
  19. package/.agents/skills/pull-request/scripts/test_github_pr_command_constants.py +58 -0
  20. package/.agents/skills/pull-request/scripts/test_pull_request.py +396 -0
  21. package/.agents/skills/pull-request/scripts/test_recover_legacy_author.py +221 -0
  22. package/.agents/skills/skill-builder/SKILL.md +3 -196
  23. package/.agents/skills/test-runner/SKILL.md +69 -0
  24. package/.agents/skills/test-runner/scripts/preflight_checks.py +365 -0
  25. package/.agents/skills/test-runner/scripts/run_tests.py +316 -0
  26. package/.agents/skills/test-runner/scripts/test_preflight_checks.py +185 -0
  27. package/.agents/skills/test-runner/scripts/test_run_tests.py +281 -0
  28. package/.agents/skills/test-runner/scripts/test_runner_constants/__init__.py +1 -0
  29. package/.agents/skills/test-runner/scripts/test_runner_constants/config/__init__.py +1 -0
  30. package/.agents/skills/test-runner/scripts/test_runner_constants/config/constants.py +96 -0
  31. package/.agents/skills-archived/pr-loop-cloud-transport/reference/identity-and-hooks.md +1 -1
  32. package/_shared/pr-loop/scripts/pr_loop_shared_constants/terminology_sweep_constants.py +6 -0
  33. package/_shared/pr-loop/scripts/terminology_sweep.py +64 -19
  34. package/_shared/pr-loop/scripts/tests/test_terminology_sweep.py +59 -0
  35. package/bin/ever-shipped-skills.mjs +2 -0
  36. package/bin/ever-shipped-skills.test.mjs +8 -0
  37. package/bin/install.agents-home.test.mjs +15 -13
  38. package/bin/install.mjs +37 -1
  39. package/bin/install.policy-lint.test.mjs +78 -0
  40. package/bin/install.prune.test.mjs +149 -20
  41. package/bin/install.pstack-plugin.test.mjs +114 -0
  42. package/bin/install.test.mjs +61 -7
  43. package/bin/refresh-pstack-plugin-skills.test.mjs +211 -0
  44. package/hooks/advisory/pr_done_reminder.py +342 -0
  45. package/hooks/advisory/test_pr_done_reminder.py +249 -0
  46. package/hooks/blocking/bash_post_call_dispatcher.py +53 -6
  47. package/hooks/blocking/code_rules_paired_test.py +22 -15
  48. package/hooks/blocking/pii_prevention_blocker.py +32 -51
  49. package/hooks/blocking/test_bash_post_call_dispatcher.py +55 -17
  50. package/hooks/blocking/test_bash_pre_tool_use_dispatcher.py +1 -4
  51. package/hooks/blocking/test_code_rules_command_dispatch.py +2 -2
  52. package/hooks/blocking/test_code_rules_enforcer_paired_test.py +36 -29
  53. package/hooks/blocking/test_code_rules_js_resume_task_enumeration.py +4 -4
  54. package/hooks/blocking/test_code_rules_js_returns_object_schemaless.py +5 -5
  55. package/hooks/blocking/test_pii_prevention_blocker.py +37 -89
  56. package/hooks/blocking/test_pre_tool_use_dispatcher.py +68 -133
  57. package/hooks/blocking/test_pre_tool_use_dispatcher_native.py +20 -51
  58. package/hooks/blocking/test_precommit_code_rules_gate_native_owner.py +18 -18
  59. package/hooks/gh_post_body_texts.py +195 -0
  60. package/hooks/git-hooks/git_hooks_constants/staged_policy_lint.py +12 -0
  61. package/hooks/git-hooks/pre_commit.py +52 -11
  62. package/hooks/git-hooks/test_installed_policy_lint.py +159 -0
  63. package/hooks/git-hooks/test_native_policy_commit.py +87 -0
  64. package/hooks/git-hooks/test_pre_commit.py +246 -0
  65. package/hooks/hooks.json +1 -16
  66. package/hooks/hooks_constants/bash_post_call_dispatcher_constants.py +14 -2
  67. package/hooks/hooks_constants/bash_pre_tool_use_dispatcher_constants.py +0 -8
  68. package/hooks/hooks_constants/gh_post_body_texts_constants.py +12 -0
  69. package/hooks/hooks_constants/pr_done_reminder_constants.py +98 -0
  70. package/hooks/hooks_constants/pre_tool_use_dispatcher_constants.py +10 -43
  71. package/hooks/hooks_constants/test_bash_post_call_dispatcher_constants.py +17 -7
  72. package/hooks/hooks_constants/test_bash_pre_tool_use_dispatcher_constants.py +0 -7
  73. package/hooks/hooks_constants/test_failure_recorder_constants.py +3 -3
  74. package/hooks/hooks_constants/test_gh_post_body_texts_constants.py +19 -0
  75. package/hooks/hooks_constants/test_pr_done_reminder_constants.py +40 -0
  76. package/hooks/hooks_constants/test_pre_tool_use_dispatcher_constants.py +20 -32
  77. package/hooks/observability/test_failure_recorder.py +1 -1
  78. package/hooks/pyproject.toml +1 -1
  79. package/hooks/test_gh_post_body_texts.py +79 -0
  80. package/package.json +2 -2
  81. package/rules/durable-post-artifacts.md +32 -20
  82. package/rules/gh-cli-conventions.md +23 -13
  83. package/rules/git-workflow.md +21 -8
  84. package/scripts/check.ps1 +0 -1
  85. package/{.agents/skills/run-claude-dev-env/driver.mjs → scripts/ci/installer-lifecycle.mjs} +3 -28
  86. package/scripts/ci/installer-lifecycle.test.mjs +26 -0
  87. package/scripts/ci/windows-installer-lifecycle.ps1 +1 -11
  88. package/scripts/dev_env_scripts_constants/shared_tree_constants.py +4 -5
  89. package/scripts/durable_post_lint.py +206 -0
  90. package/scripts/durable_post_lint_config/config/constants.py +96 -0
  91. package/scripts/durable_post_lint_config/config/test_constants.py +25 -0
  92. package/scripts/policy_lint/adapter_configuration.py +53 -12
  93. package/scripts/policy_lint/adapter_detectors.py +13 -6
  94. package/scripts/policy_lint/adapters.py +7 -4
  95. package/scripts/policy_lint/config/constants.py +5 -0
  96. package/scripts/policy_lint/engine.py +48 -4
  97. package/scripts/policy_lint/model.py +1 -0
  98. package/scripts/policy_lint/registry.py +1 -1
  99. package/scripts/policy_lint/selection.py +2 -1
  100. package/scripts/policy_lint/selection_git.py +2 -0
  101. package/scripts/refresh_pstack_plugin_skills.mjs +200 -0
  102. package/scripts/repository_checks/config/constants.py +0 -5
  103. package/scripts/shared_tree_paths.py +32 -3
  104. package/scripts/test_durable_post_lint.py +332 -0
  105. package/scripts/test_shared_tree_paths.py +33 -0
  106. package/scripts/tests/test_adapter_configuration.py +54 -0
  107. package/scripts/tests/test_policy_lint_rules_archive.py +120 -0
  108. package/scripts/tests/test_policy_lint_rules_engine.py +25 -4
  109. package/scripts/tests/test_policy_lint_rules_installed_loader.py +29 -0
  110. package/scripts/tests/test_policy_lint_rules_registry.py +227 -13
  111. package/scripts/tests/test_policy_lint_selection.py +25 -2
  112. package/scripts/tests/test_policy_lint_selection_native_index.py +30 -0
  113. package/scripts/tests/test_rules.py +3 -7
  114. package/.agents/skills/_shared/pr-loop/.claude/CLAUDE.md +0 -1
  115. package/.agents/skills/_shared/pr-loop/AGENTS.md +0 -1
  116. package/.agents/skills/_shared/pr-loop/audit-contract.md +0 -5
  117. package/.agents/skills/_shared/pr-loop/audit-reply-template.md +0 -5
  118. package/.agents/skills/_shared/pr-loop/code-rules-gate.md +0 -5
  119. package/.agents/skills/_shared/pr-loop/fix-protocol.md +0 -5
  120. package/.agents/skills/_shared/pr-loop/gh-payloads.md +0 -5
  121. package/.agents/skills/_shared/pr-loop/portable-driver.md +0 -149
  122. package/.agents/skills/_shared/pr-loop/post-audit-thread-contract.md +0 -5
  123. package/.agents/skills/_shared/pr-loop/precatch-rubric.md +0 -5
  124. package/.agents/skills/_shared/pr-loop/preflight-proposal.contract.test.mjs +0 -119
  125. package/.agents/skills/_shared/pr-loop/preflight-proposal.md +0 -5
  126. package/.agents/skills/_shared/pr-loop/prompts/.claude/CLAUDE.md +0 -1
  127. package/.agents/skills/_shared/pr-loop/prompts/AGENTS.md +0 -1
  128. package/.agents/skills/_shared/pr-loop/prompts/pr-consistency-audit.xml +0 -324
  129. package/.agents/skills/_shared/pr-loop/scripts/.claude/CLAUDE.md +0 -1
  130. package/.agents/skills/_shared/pr-loop/scripts/AGENTS.md +0 -1
  131. package/.agents/skills/_shared/pr-loop/scripts/RUNTIME_SCRIPTS.md +0 -29
  132. package/.agents/skills/_shared/pr-loop/scripts/_cli_utils.py +0 -22
  133. package/.agents/skills/_shared/pr-loop/scripts/_path_resolver.py +0 -186
  134. package/.agents/skills/_shared/pr-loop/scripts/_xml_utils.py +0 -20
  135. package/.agents/skills/_shared/pr-loop/scripts/audit_category_schema.py +0 -355
  136. package/.agents/skills/_shared/pr-loop/scripts/build_audit_prompt.py +0 -289
  137. package/.agents/skills/_shared/pr-loop/scripts/build_converge_task_list.py +0 -310
  138. package/.agents/skills/_shared/pr-loop/scripts/build_fix_prompt.py +0 -292
  139. package/.agents/skills/_shared/pr-loop/scripts/init_loop_state.py +0 -134
  140. package/.agents/skills/_shared/pr-loop/scripts/portable_converge_driver.py +0 -1646
  141. package/.agents/skills/_shared/pr-loop/scripts/preflight_worktree.py +0 -392
  142. package/.agents/skills/_shared/pr-loop/scripts/select_converge_pacer.py +0 -215
  143. package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/.claude/CLAUDE.md +0 -1
  144. package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/AGENTS.md +0 -1
  145. package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/__init__.py +0 -0
  146. package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/audit_category_schema_constants.py +0 -37
  147. package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/converge_task_list_constants.py +0 -56
  148. package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/handoff_constants.py +0 -45
  149. package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/pacer_constants.py +0 -47
  150. package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/path_resolver_constants.py +0 -157
  151. package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/portable_driver_constants.py +0 -177
  152. package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/preflight_constants.py +0 -70
  153. package/.agents/skills/_shared/pr-loop/scripts/teardown_worktrees.py +0 -172
  154. package/.agents/skills/_shared/pr-loop/scripts/test__path_resolver.py +0 -106
  155. package/.agents/skills/_shared/pr-loop/scripts/test_audit_category_schema.py +0 -94
  156. package/.agents/skills/_shared/pr-loop/scripts/test_build_audit_prompt.py +0 -499
  157. package/.agents/skills/_shared/pr-loop/scripts/test_build_converge_task_list.py +0 -140
  158. package/.agents/skills/_shared/pr-loop/scripts/test_build_fix_prompt.py +0 -262
  159. package/.agents/skills/_shared/pr-loop/scripts/test_init_loop_state.py +0 -71
  160. package/.agents/skills/_shared/pr-loop/scripts/test_portable_converge_driver.py +0 -1119
  161. package/.agents/skills/_shared/pr-loop/scripts/test_preflight_worktree.py +0 -287
  162. package/.agents/skills/_shared/pr-loop/scripts/test_select_converge_pacer.py +0 -207
  163. package/.agents/skills/_shared/pr-loop/scripts/test_teardown_worktrees.py +0 -59
  164. package/.agents/skills/_shared/pr-loop/scripts/test_write_handoff.py +0 -201
  165. package/.agents/skills/_shared/pr-loop/scripts/write_audit_outcomes.py +0 -182
  166. package/.agents/skills/_shared/pr-loop/scripts/write_fix_outcomes.py +0 -206
  167. package/.agents/skills/_shared/pr-loop/scripts/write_handoff.py +0 -309
  168. package/.agents/skills/_shared/pr-loop/state-schema.md +0 -5
  169. package/.agents/skills/_shared/pr-loop/worker-spawn.md +0 -5
  170. package/.agents/skills/autoconverge/.claude/CLAUDE.md +0 -1
  171. package/.agents/skills/autoconverge/AGENTS.md +0 -1
  172. package/.agents/skills/autoconverge/SKILL.md +0 -431
  173. package/.agents/skills/autoconverge/reference/.claude/CLAUDE.md +0 -1
  174. package/.agents/skills/autoconverge/reference/AGENTS.md +0 -1
  175. package/.agents/skills/autoconverge/reference/closing-report.md +0 -93
  176. package/.agents/skills/autoconverge/reference/convergence-gates.md +0 -31
  177. package/.agents/skills/autoconverge/reference/convergence.md +0 -219
  178. package/.agents/skills/autoconverge/reference/copilot-findings.md +0 -51
  179. package/.agents/skills/autoconverge/reference/gotchas.md +0 -66
  180. package/.agents/skills/autoconverge/reference/headless-safety.md +0 -44
  181. package/.agents/skills/autoconverge/reference/multi-pr.md +0 -128
  182. package/.agents/skills/autoconverge/reference/self-closing-loop.md +0 -84
  183. package/.agents/skills/autoconverge/reference/stop-conditions.md +0 -127
  184. package/.agents/skills/autoconverge/test_portable_pacer_gate.py +0 -54
  185. package/.agents/skills/autoconverge/workflow/.claude/CLAUDE.md +0 -1
  186. package/.agents/skills/autoconverge/workflow/AGENTS.md +0 -1
  187. package/.agents/skills/autoconverge/workflow/aggregate_runs.py +0 -371
  188. package/.agents/skills/autoconverge/workflow/autoconverge_report_constants/.claude/CLAUDE.md +0 -1
  189. package/.agents/skills/autoconverge/workflow/autoconverge_report_constants/AGENTS.md +0 -1
  190. package/.agents/skills/autoconverge/workflow/autoconverge_report_constants/__init__.py +0 -0
  191. package/.agents/skills/autoconverge/workflow/autoconverge_report_constants/render_report_constants.py +0 -250
  192. package/.agents/skills/autoconverge/workflow/converge.clean-audit.test.mjs +0 -665
  193. package/.agents/skills/autoconverge/workflow/converge.codex-gate.test.mjs +0 -472
  194. package/.agents/skills/autoconverge/workflow/converge.contract.test.mjs +0 -64
  195. package/.agents/skills/autoconverge/workflow/converge.copilot-gate.test.mjs +0 -1009
  196. package/.agents/skills/autoconverge/workflow/converge.fix-progress.test.mjs +0 -107
  197. package/.agents/skills/autoconverge/workflow/converge.fix-recovery.test.mjs +0 -33
  198. package/.agents/skills/autoconverge/workflow/converge.merge-conflict.test.mjs +0 -15
  199. package/.agents/skills/autoconverge/workflow/converge.mjs +0 -3132
  200. package/.agents/skills/autoconverge/workflow/converge.p2-advance.test.mjs +0 -202
  201. package/.agents/skills/autoconverge/workflow/converge.path-aware.test.mjs +0 -47
  202. package/.agents/skills/autoconverge/workflow/converge.precatch.test.mjs +0 -152
  203. package/.agents/skills/autoconverge/workflow/converge.run-input.test.mjs +0 -116
  204. package/.agents/skills/autoconverge/workflow/converge_multi.mjs +0 -169
  205. package/.agents/skills/autoconverge/workflow/converge_multi.run-input.test.mjs +0 -173
  206. package/.agents/skills/autoconverge/workflow/convergence_summary.py +0 -110
  207. package/.agents/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a11d903476b803493.jsonl +0 -2
  208. package/.agents/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a26213978adeef6fb.jsonl +0 -2
  209. package/.agents/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a3def0d15ed9d9110.jsonl +0 -2
  210. package/.agents/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a41f41b1b708ee3b7.jsonl +0 -2
  211. package/.agents/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a758b880abecc3ff7.jsonl +0 -2
  212. package/.agents/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a8897b89656b1bd16.jsonl +0 -2
  213. package/.agents/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-ab1c2d3e4f5a6b7c8.jsonl +0 -2
  214. package/.agents/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-abd463d744a1437bc.jsonl +0 -2
  215. package/.agents/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-ad19d027ae8ee1816.jsonl +0 -2
  216. package/.agents/skills/autoconverge/workflow/fixtures/wf_run/workflows/wf_881252e6-700.json +0 -266
  217. package/.agents/skills/autoconverge/workflow/render_report.py +0 -1024
  218. package/.agents/skills/autoconverge/workflow/test_aggregate_runs.py +0 -134
  219. package/.agents/skills/autoconverge/workflow/test_convergence_summary.py +0 -149
  220. package/.agents/skills/autoconverge/workflow/test_render_report.py +0 -812
  221. package/.agents/skills/hitl/SKILL.md +0 -45
  222. package/.agents/skills/pr-cleanup/SKILL.md +0 -140
  223. package/.agents/skills/pr-cleanup/reference/process-inventory.md +0 -17
  224. package/.agents/skills/pr-cleanup/reference/task-seeds.md +0 -22
  225. package/.agents/skills/pr-name-by-capability/SKILL.md +0 -73
  226. package/.agents/skills/pr-name-by-capability/reference/fetch-commands.md +0 -29
  227. package/.agents/skills/pr-name-by-capability/reference/offense-examples.md +0 -32
  228. package/.agents/skills/pr-name-by-capability/reference/report-template.md +0 -29
  229. package/.agents/skills/pr-name-by-capability/reference/rule-checklist.md +0 -38
  230. package/.agents/skills/pr-name-by-capability/reference/task-seeds.md +0 -10
  231. package/.agents/skills/pr-plain-language-cleanup/SKILL.md +0 -93
  232. package/.agents/skills/pr-refinement/SKILL.md +0 -31
  233. package/.agents/skills/pr-shared-extraction/SKILL.md +0 -177
  234. package/.agents/skills/pr-shared-extraction/reference/examples.md +0 -46
  235. package/.agents/skills/pr-shared-extraction/reference/offense-taxonomy.md +0 -100
  236. package/.agents/skills/pr-small-cl/SKILL.md +0 -52
  237. package/.agents/skills/pr-title-description/SKILL.md +0 -96
  238. package/.agents/skills/prototype/SKILL.md +0 -85
  239. package/.agents/skills/prototype/reference/honest-limitations.md +0 -23
  240. package/.agents/skills/prototype/reference/promotion-tasks.md +0 -23
  241. package/.agents/skills/prototype/scripts/build_sandbox_settings.py +0 -249
  242. package/.agents/skills/prototype/scripts/conftest.py +0 -15
  243. package/.agents/skills/prototype/scripts/launch_sandbox.py +0 -205
  244. package/.agents/skills/prototype/scripts/probe_sandbox_safety.py +0 -311
  245. package/.agents/skills/prototype/scripts/prototype_scripts_constants/__init__.py +0 -1
  246. package/.agents/skills/prototype/scripts/prototype_scripts_constants/config/__init__.py +0 -0
  247. package/.agents/skills/prototype/scripts/prototype_scripts_constants/config/build_sandbox_settings_constants.py +0 -41
  248. package/.agents/skills/prototype/scripts/prototype_scripts_constants/config/launch_sandbox_constants.py +0 -23
  249. package/.agents/skills/prototype/scripts/prototype_scripts_constants/config/probe_sandbox_safety_constants.py +0 -45
  250. package/.agents/skills/prototype/scripts/prototype_scripts_constants/config/prototype_common_constants.py +0 -10
  251. package/.agents/skills/prototype/scripts/test_build_sandbox_settings.py +0 -275
  252. package/.agents/skills/prototype/scripts/test_launch_sandbox.py +0 -303
  253. package/.agents/skills/prototype/scripts/test_probe_sandbox_safety.py +0 -312
  254. package/.agents/skills/prototype/workflows/promotion.md +0 -25
  255. package/.agents/skills/prototype/workflows/sandbox.md +0 -35
  256. package/.agents/skills/rebase/.claude/CLAUDE.md +0 -1
  257. package/.agents/skills/rebase/AGENTS.md +0 -1
  258. package/.agents/skills/rebase/SKILL.md +0 -178
  259. package/.agents/skills/review-router/SKILL.md +0 -51
  260. package/.agents/skills/review-router/reference/route-policy.json +0 -7
  261. package/.agents/skills/review-router/reference/task-seeds.md +0 -1
  262. package/.agents/skills/review-router/scripts/conftest.py +0 -4
  263. package/.agents/skills/review-router/scripts/review_router.py +0 -50
  264. package/.agents/skills/review-router/scripts/review_router_cli.py +0 -211
  265. package/.agents/skills/review-router/scripts/review_router_constants/__init__.py +0 -1
  266. package/.agents/skills/review-router/scripts/review_router_constants/config/__init__.py +0 -0
  267. package/.agents/skills/review-router/scripts/review_router_constants/config/constants.py +0 -13
  268. package/.agents/skills/review-router/scripts/test_review_router.py +0 -23
  269. package/.agents/skills/review-router/scripts/test_review_router_cli.py +0 -47
  270. package/.agents/skills/review-tier/SKILL.md +0 -56
  271. package/.agents/skills/review-tier/reference/task-seeds.md +0 -1
  272. package/.agents/skills/review-tier/reference/tier-policy.json +0 -9
  273. package/.agents/skills/review-tier/scripts/conftest.py +0 -4
  274. package/.agents/skills/review-tier/scripts/review_tier.py +0 -359
  275. package/.agents/skills/review-tier/scripts/review_tier_constants/__init__.py +0 -1
  276. package/.agents/skills/review-tier/scripts/review_tier_constants/config/__init__.py +0 -0
  277. package/.agents/skills/review-tier/scripts/review_tier_constants/config/constants.py +0 -29
  278. package/.agents/skills/review-tier/scripts/test_generation.py +0 -159
  279. package/.agents/skills/review-tier/scripts/test_review_tier.py +0 -33
  280. package/.agents/skills/run-claude-dev-env/SKILL.md +0 -84
  281. package/.agents/skills/session-log/.claude/CLAUDE.md +0 -1
  282. package/.agents/skills/session-log/AGENTS.md +0 -1
  283. package/.agents/skills/session-log/SKILL.md +0 -170
  284. package/.agents/skills/session-log/templates/frontmatter.md +0 -40
  285. package/.agents/skills/session-tidy/.claude/CLAUDE.md +0 -1
  286. package/.agents/skills/session-tidy/AGENTS.md +0 -1
  287. package/.agents/skills/session-tidy/SKILL.md +0 -191
  288. package/.agents/skills/skill-builder/references/.claude/CLAUDE.md +0 -1
  289. package/.agents/skills/skill-builder/references/AGENTS.md +0 -1
  290. package/.agents/skills/skill-builder/references/delegation-map.md +0 -130
  291. package/.agents/skills/skill-builder/references/description-field.md +0 -111
  292. package/.agents/skills/skill-builder/references/deterministic-elements.md +0 -218
  293. package/.agents/skills/skill-builder/references/progressive-disclosure.md +0 -122
  294. package/.agents/skills/skill-builder/references/self-audit-checklist.md +0 -126
  295. package/.agents/skills/skill-builder/references/skill-modularity.md +0 -111
  296. package/.agents/skills/skill-builder/references/skill-types.md +0 -232
  297. package/.agents/skills/skill-builder/references/thariq-x-post-skills.json +0 -33
  298. package/.agents/skills/skill-builder/templates/.claude/CLAUDE.md +0 -1
  299. package/.agents/skills/skill-builder/templates/AGENTS.md +0 -1
  300. package/.agents/skills/skill-builder/templates/gap-analysis.md +0 -87
  301. package/.agents/skills/skill-builder/workflows/.claude/CLAUDE.md +0 -1
  302. package/.agents/skills/skill-builder/workflows/AGENTS.md +0 -1
  303. package/.agents/skills/skill-builder/workflows/improve-skill.md +0 -136
  304. package/.agents/skills/skill-builder/workflows/new-skill.md +0 -179
  305. package/.agents/skills/skill-builder/workflows/polish-skill.md +0 -139
  306. package/.agents/skills/source-command-sr-loop/SKILL.md +0 -82
  307. package/.agents/skills/update/.claude/CLAUDE.md +0 -1
  308. package/.agents/skills/update/AGENTS.md +0 -1
  309. package/.agents/skills/update/SKILL.md +0 -190
  310. package/_shared/pr-loop/AGENTS.md +0 -1
  311. package/_shared/pr-loop/CLAUDE.md +0 -1
  312. package/_shared/pr-loop/audit-contract.md +0 -183
  313. package/_shared/pr-loop/audit-reply-template.md +0 -151
  314. package/_shared/pr-loop/code-rules-gate.md +0 -65
  315. package/_shared/pr-loop/fix-protocol.md +0 -60
  316. package/_shared/pr-loop/gh-payloads.md +0 -75
  317. package/_shared/pr-loop/post-audit-thread-contract.md +0 -51
  318. package/_shared/pr-loop/precatch-rubric.md +0 -66
  319. package/_shared/pr-loop/preflight-proposal.md +0 -56
  320. package/_shared/pr-loop/scripts/post_audit_thread.py +0 -1242
  321. package/_shared/pr-loop/scripts/pr_loop_shared_constants/post_audit_thread_constants.py +0 -199
  322. package/_shared/pr-loop/scripts/tests/test_post_audit_thread.py +0 -1115
  323. package/_shared/pr-loop/scripts/tests/test_post_audit_thread_constants.py +0 -129
  324. package/_shared/pr-loop/state-schema.md +0 -45
  325. package/_shared/pr-loop/worker-spawn.md +0 -189
  326. package/hooks/_gh_pr_author_swap_utils.py +0 -1225
  327. package/hooks/blocking/conventional_pr_title_gate.py +0 -443
  328. package/hooks/blocking/gh_body_arg_blocker.py +0 -176
  329. package/hooks/blocking/gh_pr_author_enforcer.py +0 -487
  330. package/hooks/blocking/gh_pr_author_restore.py +0 -105
  331. package/hooks/blocking/pr_description_writer_gate.py +0 -256
  332. package/hooks/blocking/test_conventional_pr_title_gate.py +0 -640
  333. package/hooks/blocking/test_gh_body_arg_blocker.py +0 -441
  334. package/hooks/blocking/test_gh_pr_author_enforcer.py +0 -1166
  335. package/hooks/blocking/test_gh_pr_author_restore.py +0 -513
  336. package/hooks/blocking/test_gh_pr_author_swap_utils.py +0 -910
  337. package/hooks/blocking/test_pr_description_writer_gate.py +0 -234
  338. package/hooks/blocking/test_preflight_check.py +0 -343
  339. package/hooks/blocking/test_test_preflight_check.py +0 -80
  340. package/hooks/blocking/test_volatile_path_in_post_blocker.py +0 -322
  341. package/hooks/blocking/volatile_path_in_post_blocker.py +0 -461
  342. package/hooks/hooks_constants/conventional_pr_title_gate_constants.py +0 -58
  343. package/hooks/hooks_constants/gh_pr_author_swap_constants.py +0 -76
  344. package/hooks/hooks_constants/pr_description_writer_gate_constants.py +0 -73
  345. package/hooks/hooks_constants/volatile_path_in_post_blocker_constants.py +0 -55
  346. package/hooks/observability/pr_description_writer_spawn_tracker.py +0 -113
  347. package/hooks/observability/test_pr_description_writer_spawn_tracker.py +0 -150
  348. package/hooks/session/gh_pr_author_session_cleanup.py +0 -175
  349. package/hooks/session/test_gh_pr_author_session_cleanup.py +0 -576
  350. package/hooks/test__gh_pr_author_swap_utils.py +0 -333
@@ -1,640 +0,0 @@
1
- """Unit tests for conventional_pr_title_gate PreToolUse hook."""
2
-
3
- import importlib.util
4
- import io
5
- import json
6
- import pathlib
7
- import subprocess
8
- import sys
9
- from contextlib import redirect_stderr, redirect_stdout
10
-
11
- _HOOK_DIR = pathlib.Path(__file__).parent
12
- if str(_HOOK_DIR) not in sys.path:
13
- sys.path.insert(0, str(_HOOK_DIR))
14
-
15
- hook_spec = importlib.util.spec_from_file_location(
16
- "conventional_pr_title_gate",
17
- _HOOK_DIR / "conventional_pr_title_gate.py",
18
- )
19
- assert hook_spec is not None
20
- assert hook_spec.loader is not None
21
- hook_module = importlib.util.module_from_spec(hook_spec)
22
- hook_spec.loader.exec_module(hook_module)
23
-
24
- _matches_gh_pr_title_subcommand = hook_module._matches_gh_pr_title_subcommand
25
- _parsed_command_tokens = hook_module._parsed_command_tokens
26
- _extract_flag_value = hook_module._extract_flag_value
27
- _is_conventional_commit_title = hook_module._is_conventional_commit_title
28
- _repo_enforces_default_conventional_pr_titles = (
29
- hook_module._repo_enforces_default_conventional_pr_titles
30
- )
31
- _workflow_customizes_semantic_types = hook_module._workflow_customizes_semantic_types
32
- _pull_request_title_to_validate = hook_module._pull_request_title_to_validate
33
-
34
- _SEMANTIC_WORKFLOW_TEXT = (
35
- "name: PR checks\n"
36
- "on:\n"
37
- " pull_request:\n"
38
- "jobs:\n"
39
- " validate:\n"
40
- " steps:\n"
41
- " - uses: amannn/action-semantic-pull-request@v5\n"
42
- )
43
-
44
- _PLAIN_WORKFLOW_TEXT = (
45
- "name: Tests\non:\n push:\njobs:\n test:\n steps:\n - run: npm test\n"
46
- )
47
-
48
- _SEMANTIC_WORKFLOW_WITH_CUSTOM_TYPES_TEXT = (
49
- "name: PR checks\n"
50
- "on:\n"
51
- " pull_request:\n"
52
- " types: [opened, edited, synchronize]\n"
53
- "jobs:\n"
54
- " validate:\n"
55
- " steps:\n"
56
- " - uses: amannn/action-semantic-pull-request@v5\n"
57
- " env:\n"
58
- " GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n"
59
- " with:\n"
60
- " types: |\n"
61
- " feat\n"
62
- " fix\n"
63
- " wip\n"
64
- )
65
-
66
- _SEMANTIC_WORKFLOW_WITH_EVENT_TYPES_ONLY_TEXT = (
67
- "name: PR checks\n"
68
- "on:\n"
69
- " pull_request:\n"
70
- " types: [opened, edited, synchronize]\n"
71
- "jobs:\n"
72
- " validate:\n"
73
- " steps:\n"
74
- " - uses: amannn/action-semantic-pull-request@v5\n"
75
- )
76
-
77
- _SEMANTIC_WORKFLOW_NAME_STEP_CUSTOM_TYPES_TEXT = (
78
- "name: PR checks\n"
79
- "on:\n"
80
- " pull_request:\n"
81
- " types: [opened, edited, synchronize]\n"
82
- "jobs:\n"
83
- " validate:\n"
84
- " steps:\n"
85
- " - name: Validate PR title\n"
86
- " uses: amannn/action-semantic-pull-request@v5\n"
87
- " with:\n"
88
- " types: |\n"
89
- " feat\n"
90
- " fix\n"
91
- " wip\n"
92
- )
93
-
94
- _SEMANTIC_WORKFLOW_TYPES_ABOVE_USES_TEXT = (
95
- "name: PR checks\n"
96
- "on:\n"
97
- " pull_request:\n"
98
- " types: [opened, edited, synchronize]\n"
99
- "jobs:\n"
100
- " validate:\n"
101
- " steps:\n"
102
- " - name: Validate PR title\n"
103
- " with:\n"
104
- " types: |\n"
105
- " feat\n"
106
- " fix\n"
107
- " wip\n"
108
- " uses: amannn/action-semantic-pull-request@v5\n"
109
- )
110
-
111
- _SEMANTIC_WORKFLOW_FLOW_STYLE_TYPES_TEXT = (
112
- "name: PR checks\n"
113
- "on:\n"
114
- " pull_request:\n"
115
- " types: [opened, edited, synchronize]\n"
116
- "jobs:\n"
117
- " validate:\n"
118
- " steps:\n"
119
- " - uses: amannn/action-semantic-pull-request@v5\n"
120
- " with: { types: [feat, fix, wip] }\n"
121
- )
122
-
123
-
124
- def _init_repo_with_workflow(repo_root: pathlib.Path, workflow_text: str) -> None:
125
- subprocess.run(["git", "init", str(repo_root)], capture_output=True, check=True)
126
- workflows_directory = repo_root / ".github" / "workflows"
127
- workflows_directory.mkdir(parents=True)
128
- (workflows_directory / "pr-check.yml").write_text(workflow_text, encoding="utf-8")
129
-
130
-
131
- def _run_hook_with_stdin_text(stdin_text: str) -> tuple[str, str, int]:
132
- captured_stdout = io.StringIO()
133
- captured_stderr = io.StringIO()
134
- exit_code = 0
135
- sys.stdin = io.StringIO(stdin_text)
136
- try:
137
- with redirect_stdout(captured_stdout), redirect_stderr(captured_stderr):
138
- try:
139
- hook_module.main()
140
- except SystemExit as exit_signal:
141
- exit_code = exit_signal.code or 0
142
- finally:
143
- sys.stdin = sys.__stdin__
144
- return captured_stdout.getvalue(), captured_stderr.getvalue(), exit_code
145
-
146
-
147
- def _run_hook(hook_input: dict) -> tuple[str, int]:
148
- stdout_text, _stderr_text, exit_code = _run_hook_with_stdin_text(json.dumps(hook_input))
149
- return stdout_text, exit_code
150
-
151
-
152
- def test_matches_gh_pr_create_with_title() -> None:
153
- assert _matches_gh_pr_title_subcommand('gh pr create --title "add x"')
154
-
155
-
156
- def test_matches_gh_pr_edit_with_title() -> None:
157
- assert _matches_gh_pr_title_subcommand('gh pr edit 10 --title "add x"')
158
-
159
-
160
- def test_does_not_match_gh_pr_comment() -> None:
161
- assert not _matches_gh_pr_title_subcommand('gh pr comment 10 --body "LGTM"')
162
-
163
-
164
- def test_does_not_match_unrelated_command() -> None:
165
- assert not _matches_gh_pr_title_subcommand("gh pr list --repo owner/repo")
166
-
167
-
168
- def test_does_not_match_echoed_gh_pr_create() -> None:
169
- assert not _matches_gh_pr_title_subcommand('echo gh pr create --title "add x"')
170
-
171
-
172
- def test_matches_gh_pr_create_when_invoked_by_executable_path() -> None:
173
- assert _matches_gh_pr_title_subcommand('/usr/bin/gh pr create --title "add x"')
174
-
175
-
176
- def test_extract_flag_value_space_form() -> None:
177
- assert (
178
- _extract_flag_value('gh pr create --title "feat: add x" --draft', "--title", "-t")
179
- == "feat: add x"
180
- )
181
-
182
-
183
- def test_extract_flag_value_equals_form() -> None:
184
- assert (
185
- _extract_flag_value('gh pr create --title="fix: broken thing" --draft', "--title", "-t")
186
- == "fix: broken thing"
187
- )
188
-
189
-
190
- def test_extract_flag_value_short_form() -> None:
191
- assert _extract_flag_value('gh pr create -t "chore: bump deps"', "--title", "-t") == (
192
- "chore: bump deps"
193
- )
194
-
195
-
196
- def test_extract_flag_value_returns_none_when_absent() -> None:
197
- assert _extract_flag_value("gh pr create --draft", "--title", "-t") is None
198
-
199
-
200
- def test_extract_flag_value_skips_title_word_embedded_in_label_value() -> None:
201
- command = 'gh pr create --label="use --title inside" --title "feat: real"'
202
- assert _extract_flag_value(command, "--title", "-t") == "feat: real"
203
-
204
-
205
- def test_extract_flag_value_reads_attached_short_repo_flag() -> None:
206
- assert (
207
- _extract_flag_value("gh pr create -Rowner/other --title x", "--repo", "-R") == "owner/other"
208
- )
209
-
210
-
211
- def test_extract_flag_value_reads_equals_short_repo_flag() -> None:
212
- assert (
213
- _extract_flag_value("gh pr create -R=owner/other --title x", "--repo", "-R")
214
- == "owner/other"
215
- )
216
-
217
-
218
- def test_parsed_command_tokens_returns_none_on_unparseable_command() -> None:
219
- assert _parsed_command_tokens("gh pr create --title 'unmatched quote here") is None
220
-
221
-
222
- def test_is_conventional_commit_title_accepts_plain_type() -> None:
223
- assert _is_conventional_commit_title("feat: add the thing")
224
-
225
-
226
- def test_is_conventional_commit_title_accepts_scope_and_breaking_marker() -> None:
227
- assert _is_conventional_commit_title("feat(hooks)!: drop the old flag")
228
-
229
-
230
- def test_is_conventional_commit_title_rejects_non_conventional_title() -> None:
231
- assert not _is_conventional_commit_title("add the thing")
232
-
233
-
234
- def test_pull_request_title_to_validate_returns_none_for_shell_variable_title() -> None:
235
- assert _pull_request_title_to_validate('gh pr create --title "$TITLE"') is None
236
-
237
-
238
- def test_pull_request_title_to_validate_returns_literal_for_plain_title() -> None:
239
- assert (
240
- _pull_request_title_to_validate('gh pr create --title "add the thing"') == "add the thing"
241
- )
242
-
243
-
244
- def test_pull_request_title_to_validate_reads_real_title_past_embedded_flag_word() -> None:
245
- command = 'gh pr create --label="use --title inside" --title "feat: x"'
246
- assert _pull_request_title_to_validate(command) == "feat: x"
247
-
248
-
249
- def test_pull_request_title_to_validate_returns_none_for_attached_repo_flag() -> None:
250
- command = 'gh pr create -Rowner/other --title "add the thing"'
251
- assert _pull_request_title_to_validate(command) is None
252
-
253
-
254
- def test_repo_enforces_default_conventional_pr_titles_true_for_marker_workflow(
255
- tmp_path: pathlib.Path,
256
- ) -> None:
257
- repo_root = tmp_path / "semantic_repo"
258
- _init_repo_with_workflow(repo_root, _SEMANTIC_WORKFLOW_TEXT)
259
- assert _repo_enforces_default_conventional_pr_titles(str(repo_root))
260
-
261
-
262
- def test_repo_enforces_default_conventional_pr_titles_false_for_plain_workflow(
263
- tmp_path: pathlib.Path,
264
- ) -> None:
265
- repo_root = tmp_path / "plain_repo"
266
- _init_repo_with_workflow(repo_root, _PLAIN_WORKFLOW_TEXT)
267
- assert not _repo_enforces_default_conventional_pr_titles(str(repo_root))
268
-
269
-
270
- def test_repo_enforces_default_conventional_pr_titles_false_when_no_workflows_directory(
271
- tmp_path: pathlib.Path,
272
- ) -> None:
273
- repo_root = tmp_path / "no_workflows_repo"
274
- subprocess.run(["git", "init", str(repo_root)], capture_output=True, check=True)
275
- assert not _repo_enforces_default_conventional_pr_titles(str(repo_root))
276
-
277
-
278
- def test_repo_enforces_default_conventional_pr_titles_false_when_action_customizes_types(
279
- tmp_path: pathlib.Path,
280
- ) -> None:
281
- repo_root = tmp_path / "custom_types_repo"
282
- _init_repo_with_workflow(repo_root, _SEMANTIC_WORKFLOW_WITH_CUSTOM_TYPES_TEXT)
283
- assert not _repo_enforces_default_conventional_pr_titles(str(repo_root))
284
-
285
-
286
- def test_repo_enforces_default_conventional_pr_titles_true_when_only_event_types_present(
287
- tmp_path: pathlib.Path,
288
- ) -> None:
289
- repo_root = tmp_path / "event_types_repo"
290
- _init_repo_with_workflow(repo_root, _SEMANTIC_WORKFLOW_WITH_EVENT_TYPES_ONLY_TEXT)
291
- assert _repo_enforces_default_conventional_pr_titles(str(repo_root))
292
-
293
-
294
- def test_repo_enforces_default_conventional_pr_titles_true_when_one_marker_workflow_keeps_default_types(
295
- tmp_path: pathlib.Path,
296
- ) -> None:
297
- repo_root = tmp_path / "mixed_types_repo"
298
- _init_repo_with_workflow(repo_root, _SEMANTIC_WORKFLOW_WITH_CUSTOM_TYPES_TEXT)
299
- workflows_directory = repo_root / ".github" / "workflows"
300
- (workflows_directory / "pr-title-default.yml").write_text(
301
- _SEMANTIC_WORKFLOW_TEXT, encoding="utf-8"
302
- )
303
- assert _repo_enforces_default_conventional_pr_titles(str(repo_root))
304
-
305
-
306
- def test_workflow_customizes_semantic_types_true_for_action_types_input() -> None:
307
- assert _workflow_customizes_semantic_types(_SEMANTIC_WORKFLOW_WITH_CUSTOM_TYPES_TEXT)
308
-
309
-
310
- def test_workflow_customizes_semantic_types_false_for_event_types_only() -> None:
311
- assert not _workflow_customizes_semantic_types(_SEMANTIC_WORKFLOW_WITH_EVENT_TYPES_ONLY_TEXT)
312
-
313
-
314
- def test_workflow_customizes_semantic_types_true_for_name_step_layout() -> None:
315
- assert _workflow_customizes_semantic_types(_SEMANTIC_WORKFLOW_NAME_STEP_CUSTOM_TYPES_TEXT)
316
-
317
-
318
- def test_repo_enforces_default_conventional_pr_titles_false_for_name_step_custom_types(
319
- tmp_path: pathlib.Path,
320
- ) -> None:
321
- repo_root = tmp_path / "name_step_custom_types_repo"
322
- _init_repo_with_workflow(repo_root, _SEMANTIC_WORKFLOW_NAME_STEP_CUSTOM_TYPES_TEXT)
323
- assert not _repo_enforces_default_conventional_pr_titles(str(repo_root))
324
-
325
-
326
- def test_workflow_customizes_semantic_types_true_when_types_above_uses() -> None:
327
- assert _workflow_customizes_semantic_types(_SEMANTIC_WORKFLOW_TYPES_ABOVE_USES_TEXT)
328
-
329
-
330
- def test_repo_enforces_default_conventional_pr_titles_false_when_types_above_uses(
331
- tmp_path: pathlib.Path,
332
- ) -> None:
333
- repo_root = tmp_path / "types_above_uses_repo"
334
- _init_repo_with_workflow(repo_root, _SEMANTIC_WORKFLOW_TYPES_ABOVE_USES_TEXT)
335
- assert not _repo_enforces_default_conventional_pr_titles(str(repo_root))
336
-
337
-
338
- def test_workflow_customizes_semantic_types_true_for_flow_style_types() -> None:
339
- assert _workflow_customizes_semantic_types(_SEMANTIC_WORKFLOW_FLOW_STYLE_TYPES_TEXT)
340
-
341
-
342
- def test_repo_enforces_default_conventional_pr_titles_false_for_flow_style_types(
343
- tmp_path: pathlib.Path,
344
- ) -> None:
345
- repo_root = tmp_path / "flow_style_types_repo"
346
- _init_repo_with_workflow(repo_root, _SEMANTIC_WORKFLOW_FLOW_STYLE_TYPES_TEXT)
347
- assert not _repo_enforces_default_conventional_pr_titles(str(repo_root))
348
-
349
-
350
- def test_main_blocks_non_conventional_title_in_semantic_ci_repo(
351
- tmp_path: pathlib.Path,
352
- ) -> None:
353
- repo_root = tmp_path / "semantic_repo"
354
- _init_repo_with_workflow(repo_root, _SEMANTIC_WORKFLOW_TEXT)
355
- stdout_text, exit_code = _run_hook(
356
- {
357
- "tool_name": "Bash",
358
- "cwd": str(repo_root),
359
- "tool_input": {"command": 'gh pr create --title "add the thing"'},
360
- }
361
- )
362
- assert exit_code == 0
363
- response_payload = json.loads(stdout_text)
364
- decision_block = response_payload["hookSpecificOutput"]
365
- assert decision_block["permissionDecision"] == "deny"
366
- assert "conventional-pr-title" in decision_block["permissionDecisionReason"]
367
-
368
-
369
- def test_main_allows_shell_variable_title_in_semantic_ci_repo(tmp_path: pathlib.Path) -> None:
370
- repo_root = tmp_path / "semantic_repo"
371
- _init_repo_with_workflow(repo_root, _SEMANTIC_WORKFLOW_TEXT)
372
- stdout_text, exit_code = _run_hook(
373
- {
374
- "tool_name": "Bash",
375
- "cwd": str(repo_root),
376
- "tool_input": {"command": 'gh pr create --title "$TITLE"'},
377
- }
378
- )
379
- assert exit_code == 0
380
- assert stdout_text == ""
381
-
382
-
383
- def test_main_allows_conventional_title_in_semantic_ci_repo(tmp_path: pathlib.Path) -> None:
384
- repo_root = tmp_path / "semantic_repo"
385
- _init_repo_with_workflow(repo_root, _SEMANTIC_WORKFLOW_TEXT)
386
- stdout_text, exit_code = _run_hook(
387
- {
388
- "tool_name": "Bash",
389
- "cwd": str(repo_root),
390
- "tool_input": {"command": 'gh pr create --title "feat(hooks): add the thing"'},
391
- }
392
- )
393
- assert exit_code == 0
394
- assert stdout_text == ""
395
-
396
-
397
- def test_main_allows_conventional_title_with_scope_and_breaking_marker(
398
- tmp_path: pathlib.Path,
399
- ) -> None:
400
- repo_root = tmp_path / "semantic_repo"
401
- _init_repo_with_workflow(repo_root, _SEMANTIC_WORKFLOW_TEXT)
402
- stdout_text, exit_code = _run_hook(
403
- {
404
- "tool_name": "Bash",
405
- "cwd": str(repo_root),
406
- "tool_input": {"command": 'gh pr create --title "feat(x)!: drop y"'},
407
- }
408
- )
409
- assert exit_code == 0
410
- assert stdout_text == ""
411
-
412
-
413
- def test_main_allows_junk_title_when_no_semantic_marker(tmp_path: pathlib.Path) -> None:
414
- repo_root = tmp_path / "plain_repo"
415
- _init_repo_with_workflow(repo_root, _PLAIN_WORKFLOW_TEXT)
416
- stdout_text, exit_code = _run_hook(
417
- {
418
- "tool_name": "Bash",
419
- "cwd": str(repo_root),
420
- "tool_input": {"command": 'gh pr create --title "add the thing"'},
421
- }
422
- )
423
- assert exit_code == 0
424
- assert stdout_text == ""
425
-
426
-
427
- def test_main_allows_custom_type_title_when_action_customizes_types(
428
- tmp_path: pathlib.Path,
429
- ) -> None:
430
- repo_root = tmp_path / "custom_types_repo"
431
- _init_repo_with_workflow(repo_root, _SEMANTIC_WORKFLOW_WITH_CUSTOM_TYPES_TEXT)
432
- stdout_text, exit_code = _run_hook(
433
- {
434
- "tool_name": "Bash",
435
- "cwd": str(repo_root),
436
- "tool_input": {"command": 'gh pr create --title "wip: iterate on the thing"'},
437
- }
438
- )
439
- assert exit_code == 0
440
- assert stdout_text == ""
441
-
442
-
443
- def test_main_blocks_non_conventional_title_when_one_marker_workflow_keeps_default_types(
444
- tmp_path: pathlib.Path,
445
- ) -> None:
446
- repo_root = tmp_path / "mixed_types_repo"
447
- _init_repo_with_workflow(repo_root, _SEMANTIC_WORKFLOW_WITH_CUSTOM_TYPES_TEXT)
448
- workflows_directory = repo_root / ".github" / "workflows"
449
- (workflows_directory / "pr-title-default.yml").write_text(
450
- _SEMANTIC_WORKFLOW_TEXT, encoding="utf-8"
451
- )
452
- stdout_text, exit_code = _run_hook(
453
- {
454
- "tool_name": "Bash",
455
- "cwd": str(repo_root),
456
- "tool_input": {"command": 'gh pr create --title "add the thing"'},
457
- }
458
- )
459
- assert exit_code == 0
460
- response_payload = json.loads(stdout_text)
461
- decision_block = response_payload["hookSpecificOutput"]
462
- assert decision_block["permissionDecision"] == "deny"
463
- assert "conventional-pr-title" in decision_block["permissionDecisionReason"]
464
-
465
-
466
- def test_main_allows_custom_type_title_for_name_step_layout(
467
- tmp_path: pathlib.Path,
468
- ) -> None:
469
- repo_root = tmp_path / "name_step_custom_types_repo"
470
- _init_repo_with_workflow(repo_root, _SEMANTIC_WORKFLOW_NAME_STEP_CUSTOM_TYPES_TEXT)
471
- stdout_text, exit_code = _run_hook(
472
- {
473
- "tool_name": "Bash",
474
- "cwd": str(repo_root),
475
- "tool_input": {"command": 'gh pr create --title "wip: iterate on the thing"'},
476
- }
477
- )
478
- assert exit_code == 0
479
- assert stdout_text == ""
480
-
481
-
482
- def test_main_allows_custom_type_title_when_types_above_uses(
483
- tmp_path: pathlib.Path,
484
- ) -> None:
485
- repo_root = tmp_path / "types_above_uses_repo"
486
- _init_repo_with_workflow(repo_root, _SEMANTIC_WORKFLOW_TYPES_ABOVE_USES_TEXT)
487
- stdout_text, exit_code = _run_hook(
488
- {
489
- "tool_name": "Bash",
490
- "cwd": str(repo_root),
491
- "tool_input": {"command": 'gh pr create --title "wip: iterate on the thing"'},
492
- }
493
- )
494
- assert exit_code == 0
495
- assert stdout_text == ""
496
-
497
-
498
- def test_main_allows_custom_type_title_for_flow_style_types(
499
- tmp_path: pathlib.Path,
500
- ) -> None:
501
- repo_root = tmp_path / "flow_style_types_repo"
502
- _init_repo_with_workflow(repo_root, _SEMANTIC_WORKFLOW_FLOW_STYLE_TYPES_TEXT)
503
- stdout_text, exit_code = _run_hook(
504
- {
505
- "tool_name": "Bash",
506
- "cwd": str(repo_root),
507
- "tool_input": {"command": 'gh pr create --title "wip: iterate on the thing"'},
508
- }
509
- )
510
- assert exit_code == 0
511
- assert stdout_text == ""
512
-
513
-
514
- def test_main_allows_conventional_title_past_embedded_flag_word_in_label(
515
- tmp_path: pathlib.Path,
516
- ) -> None:
517
- repo_root = tmp_path / "semantic_repo"
518
- _init_repo_with_workflow(repo_root, _SEMANTIC_WORKFLOW_TEXT)
519
- stdout_text, exit_code = _run_hook(
520
- {
521
- "tool_name": "Bash",
522
- "cwd": str(repo_root),
523
- "tool_input": {
524
- "command": 'gh pr create --label="use --title inside" --title "feat: add x"'
525
- },
526
- }
527
- )
528
- assert exit_code == 0
529
- assert stdout_text == ""
530
-
531
-
532
- def test_main_allows_cross_repo_title_with_attached_repo_flag(
533
- tmp_path: pathlib.Path,
534
- ) -> None:
535
- repo_root = tmp_path / "semantic_repo"
536
- _init_repo_with_workflow(repo_root, _SEMANTIC_WORKFLOW_TEXT)
537
- stdout_text, exit_code = _run_hook(
538
- {
539
- "tool_name": "Bash",
540
- "cwd": str(repo_root),
541
- "tool_input": {"command": 'gh pr create -Rowner/other --title "add the thing"'},
542
- }
543
- )
544
- assert exit_code == 0
545
- assert stdout_text == ""
546
-
547
-
548
- def test_main_blocks_non_conventional_title_when_only_event_types_present(
549
- tmp_path: pathlib.Path,
550
- ) -> None:
551
- repo_root = tmp_path / "event_types_repo"
552
- _init_repo_with_workflow(repo_root, _SEMANTIC_WORKFLOW_WITH_EVENT_TYPES_ONLY_TEXT)
553
- stdout_text, exit_code = _run_hook(
554
- {
555
- "tool_name": "Bash",
556
- "cwd": str(repo_root),
557
- "tool_input": {"command": 'gh pr create --title "add the thing"'},
558
- }
559
- )
560
- assert exit_code == 0
561
- response_payload = json.loads(stdout_text)
562
- assert response_payload["hookSpecificOutput"]["permissionDecision"] == "deny"
563
-
564
-
565
- def test_main_allows_echoed_gh_pr_create_in_semantic_ci_repo(tmp_path: pathlib.Path) -> None:
566
- repo_root = tmp_path / "semantic_repo"
567
- _init_repo_with_workflow(repo_root, _SEMANTIC_WORKFLOW_TEXT)
568
- stdout_text, exit_code = _run_hook(
569
- {
570
- "tool_name": "Bash",
571
- "cwd": str(repo_root),
572
- "tool_input": {"command": 'echo gh pr create --title "add the thing"'},
573
- }
574
- )
575
- assert exit_code == 0
576
- assert stdout_text == ""
577
-
578
-
579
- def test_main_allows_non_gh_pr_create_command(tmp_path: pathlib.Path) -> None:
580
- repo_root = tmp_path / "semantic_repo"
581
- _init_repo_with_workflow(repo_root, _SEMANTIC_WORKFLOW_TEXT)
582
- stdout_text, exit_code = _run_hook(
583
- {
584
- "tool_name": "Bash",
585
- "cwd": str(repo_root),
586
- "tool_input": {"command": "gh pr list --repo owner/repo"},
587
- }
588
- )
589
- assert exit_code == 0
590
- assert stdout_text == ""
591
-
592
-
593
- def test_main_allows_gh_pr_create_with_no_title(tmp_path: pathlib.Path) -> None:
594
- repo_root = tmp_path / "semantic_repo"
595
- _init_repo_with_workflow(repo_root, _SEMANTIC_WORKFLOW_TEXT)
596
- stdout_text, exit_code = _run_hook(
597
- {
598
- "tool_name": "Bash",
599
- "cwd": str(repo_root),
600
- "tool_input": {"command": "gh pr create --draft"},
601
- }
602
- )
603
- assert exit_code == 0
604
- assert stdout_text == ""
605
-
606
-
607
- def test_main_allows_when_repo_flag_present(tmp_path: pathlib.Path) -> None:
608
- repo_root = tmp_path / "semantic_repo"
609
- _init_repo_with_workflow(repo_root, _SEMANTIC_WORKFLOW_TEXT)
610
- stdout_text, exit_code = _run_hook(
611
- {
612
- "tool_name": "Bash",
613
- "cwd": str(repo_root),
614
- "tool_input": {"command": 'gh pr create --repo owner/other --title "add the thing"'},
615
- }
616
- )
617
- assert exit_code == 0
618
- assert stdout_text == ""
619
-
620
-
621
- def test_main_allows_non_bash_tool() -> None:
622
- stdout_text, exit_code = _run_hook(
623
- {"tool_name": "Write", "tool_input": {"content": "add the thing"}}
624
- )
625
- assert exit_code == 0
626
- assert stdout_text == ""
627
-
628
-
629
- def test_main_with_empty_stdin_exits_silently() -> None:
630
- stdout_text, stderr_text, exit_code = _run_hook_with_stdin_text("")
631
- assert exit_code == 0
632
- assert stdout_text == ""
633
- assert stderr_text == ""
634
-
635
-
636
- def test_main_with_invalid_json_stdin_exits_silently() -> None:
637
- stdout_text, stderr_text, exit_code = _run_hook_with_stdin_text("{broken")
638
- assert exit_code == 0
639
- assert stdout_text == ""
640
- assert stderr_text == ""