claude-dev-env 4.3.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 (293) 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 +33 -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 +1 -3
  18. package/.agents/skills/skill-builder/SKILL.md +3 -196
  19. package/_shared/pr-loop/scripts/pr_loop_shared_constants/terminology_sweep_constants.py +6 -0
  20. package/_shared/pr-loop/scripts/terminology_sweep.py +64 -19
  21. package/_shared/pr-loop/scripts/tests/test_terminology_sweep.py +59 -0
  22. package/bin/install.agents-home.test.mjs +15 -13
  23. package/bin/install.mjs +28 -0
  24. package/bin/install.policy-lint.test.mjs +78 -0
  25. package/bin/install.prune.test.mjs +59 -20
  26. package/bin/install.pstack-plugin.test.mjs +114 -0
  27. package/bin/install.test.mjs +37 -0
  28. package/bin/refresh-pstack-plugin-skills.test.mjs +211 -0
  29. package/hooks/advisory/pr_done_reminder.py +342 -0
  30. package/hooks/advisory/test_pr_done_reminder.py +249 -0
  31. package/hooks/blocking/bash_post_call_dispatcher.py +53 -6
  32. package/hooks/blocking/code_rules_paired_test.py +22 -15
  33. package/hooks/blocking/test_bash_post_call_dispatcher.py +65 -4
  34. package/hooks/blocking/test_code_rules_enforcer_paired_test.py +36 -29
  35. package/hooks/blocking/test_code_rules_js_resume_task_enumeration.py +4 -4
  36. package/hooks/blocking/test_code_rules_js_returns_object_schemaless.py +5 -5
  37. package/hooks/blocking/test_pre_tool_use_dispatcher.py +68 -133
  38. package/hooks/blocking/test_pre_tool_use_dispatcher_native.py +20 -51
  39. package/hooks/blocking/test_precommit_code_rules_gate_native_owner.py +18 -18
  40. package/hooks/git-hooks/git_hooks_constants/staged_policy_lint.py +12 -0
  41. package/hooks/git-hooks/pre_commit.py +52 -11
  42. package/hooks/git-hooks/test_installed_policy_lint.py +159 -0
  43. package/hooks/git-hooks/test_native_policy_commit.py +87 -0
  44. package/hooks/git-hooks/test_pre_commit.py +246 -0
  45. package/hooks/hooks.json +1 -1
  46. package/hooks/hooks_constants/bash_post_call_dispatcher_constants.py +14 -1
  47. package/hooks/hooks_constants/pr_done_reminder_constants.py +98 -0
  48. package/hooks/hooks_constants/pre_tool_use_dispatcher_constants.py +10 -43
  49. package/hooks/hooks_constants/test_bash_post_call_dispatcher_constants.py +19 -2
  50. package/hooks/hooks_constants/test_pr_done_reminder_constants.py +40 -0
  51. package/hooks/hooks_constants/test_pre_tool_use_dispatcher_constants.py +20 -32
  52. package/package.json +2 -2
  53. package/rules/durable-post-artifacts.md +2 -1
  54. package/rules/git-workflow.md +6 -6
  55. package/scripts/check.ps1 +0 -1
  56. package/{.agents/skills/run-claude-dev-env/driver.mjs → scripts/ci/installer-lifecycle.mjs} +3 -28
  57. package/scripts/ci/installer-lifecycle.test.mjs +26 -0
  58. package/scripts/ci/windows-installer-lifecycle.ps1 +1 -11
  59. package/scripts/dev_env_scripts_constants/shared_tree_constants.py +4 -5
  60. package/{.agents/skills/_shared/pr-loop/scripts → scripts}/durable_post_lint.py +5 -41
  61. package/{.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/durable_post_lint_constants.py → scripts/durable_post_lint_config/config/constants.py} +0 -10
  62. package/{.agents/skills/_shared/pr-loop/scripts/test_durable_post_lint_constants.py → scripts/durable_post_lint_config/config/test_constants.py} +1 -1
  63. package/scripts/policy_lint/adapter_detectors.py +13 -6
  64. package/scripts/policy_lint/adapters.py +7 -4
  65. package/scripts/policy_lint/config/constants.py +5 -0
  66. package/scripts/policy_lint/engine.py +48 -4
  67. package/scripts/policy_lint/model.py +1 -0
  68. package/scripts/policy_lint/registry.py +1 -1
  69. package/scripts/policy_lint/selection.py +2 -1
  70. package/scripts/policy_lint/selection_git.py +2 -0
  71. package/scripts/refresh_pstack_plugin_skills.mjs +200 -0
  72. package/scripts/shared_tree_paths.py +32 -3
  73. package/scripts/test_shared_tree_paths.py +33 -0
  74. package/scripts/tests/test_policy_lint_rules_archive.py +120 -0
  75. package/scripts/tests/test_policy_lint_rules_engine.py +25 -4
  76. package/scripts/tests/test_policy_lint_rules_installed_loader.py +29 -0
  77. package/scripts/tests/test_policy_lint_rules_registry.py +227 -13
  78. package/scripts/tests/test_policy_lint_selection.py +25 -2
  79. package/scripts/tests/test_policy_lint_selection_native_index.py +30 -0
  80. package/scripts/tests/test_rules.py +3 -7
  81. package/.agents/skills/_shared/pr-loop/.claude/CLAUDE.md +0 -1
  82. package/.agents/skills/_shared/pr-loop/AGENTS.md +0 -1
  83. package/.agents/skills/_shared/pr-loop/audit-contract.md +0 -5
  84. package/.agents/skills/_shared/pr-loop/audit-reply-template.md +0 -5
  85. package/.agents/skills/_shared/pr-loop/code-rules-gate.md +0 -5
  86. package/.agents/skills/_shared/pr-loop/fix-protocol.md +0 -5
  87. package/.agents/skills/_shared/pr-loop/gh-payloads.md +0 -5
  88. package/.agents/skills/_shared/pr-loop/portable-driver.md +0 -149
  89. package/.agents/skills/_shared/pr-loop/post-audit-thread-contract.md +0 -5
  90. package/.agents/skills/_shared/pr-loop/precatch-rubric.md +0 -5
  91. package/.agents/skills/_shared/pr-loop/preflight-proposal.contract.test.mjs +0 -119
  92. package/.agents/skills/_shared/pr-loop/preflight-proposal.md +0 -5
  93. package/.agents/skills/_shared/pr-loop/prompts/.claude/CLAUDE.md +0 -1
  94. package/.agents/skills/_shared/pr-loop/prompts/AGENTS.md +0 -1
  95. package/.agents/skills/_shared/pr-loop/prompts/pr-consistency-audit.xml +0 -324
  96. package/.agents/skills/_shared/pr-loop/scripts/.claude/CLAUDE.md +0 -1
  97. package/.agents/skills/_shared/pr-loop/scripts/AGENTS.md +0 -1
  98. package/.agents/skills/_shared/pr-loop/scripts/RUNTIME_SCRIPTS.md +0 -29
  99. package/.agents/skills/_shared/pr-loop/scripts/_cli_utils.py +0 -22
  100. package/.agents/skills/_shared/pr-loop/scripts/_path_resolver.py +0 -186
  101. package/.agents/skills/_shared/pr-loop/scripts/_xml_utils.py +0 -20
  102. package/.agents/skills/_shared/pr-loop/scripts/audit_category_schema.py +0 -355
  103. package/.agents/skills/_shared/pr-loop/scripts/build_audit_prompt.py +0 -289
  104. package/.agents/skills/_shared/pr-loop/scripts/build_converge_task_list.py +0 -310
  105. package/.agents/skills/_shared/pr-loop/scripts/build_fix_prompt.py +0 -292
  106. package/.agents/skills/_shared/pr-loop/scripts/init_loop_state.py +0 -134
  107. package/.agents/skills/_shared/pr-loop/scripts/portable_converge_driver.py +0 -1646
  108. package/.agents/skills/_shared/pr-loop/scripts/preflight_worktree.py +0 -392
  109. package/.agents/skills/_shared/pr-loop/scripts/select_converge_pacer.py +0 -215
  110. package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/.claude/CLAUDE.md +0 -1
  111. package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/AGENTS.md +0 -1
  112. package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/__init__.py +0 -0
  113. package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/audit_category_schema_constants.py +0 -37
  114. package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/converge_task_list_constants.py +0 -56
  115. package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/handoff_constants.py +0 -45
  116. package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/pacer_constants.py +0 -47
  117. package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/path_resolver_constants.py +0 -157
  118. package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/portable_driver_constants.py +0 -177
  119. package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/preflight_constants.py +0 -70
  120. package/.agents/skills/_shared/pr-loop/scripts/teardown_worktrees.py +0 -172
  121. package/.agents/skills/_shared/pr-loop/scripts/test__path_resolver.py +0 -106
  122. package/.agents/skills/_shared/pr-loop/scripts/test_audit_category_schema.py +0 -94
  123. package/.agents/skills/_shared/pr-loop/scripts/test_build_audit_prompt.py +0 -499
  124. package/.agents/skills/_shared/pr-loop/scripts/test_build_converge_task_list.py +0 -140
  125. package/.agents/skills/_shared/pr-loop/scripts/test_build_fix_prompt.py +0 -262
  126. package/.agents/skills/_shared/pr-loop/scripts/test_init_loop_state.py +0 -71
  127. package/.agents/skills/_shared/pr-loop/scripts/test_portable_converge_driver.py +0 -1119
  128. package/.agents/skills/_shared/pr-loop/scripts/test_preflight_worktree.py +0 -287
  129. package/.agents/skills/_shared/pr-loop/scripts/test_select_converge_pacer.py +0 -207
  130. package/.agents/skills/_shared/pr-loop/scripts/test_teardown_worktrees.py +0 -59
  131. package/.agents/skills/_shared/pr-loop/scripts/test_write_handoff.py +0 -201
  132. package/.agents/skills/_shared/pr-loop/scripts/write_audit_outcomes.py +0 -182
  133. package/.agents/skills/_shared/pr-loop/scripts/write_fix_outcomes.py +0 -206
  134. package/.agents/skills/_shared/pr-loop/scripts/write_handoff.py +0 -309
  135. package/.agents/skills/_shared/pr-loop/state-schema.md +0 -5
  136. package/.agents/skills/_shared/pr-loop/worker-spawn.md +0 -5
  137. package/.agents/skills/autoconverge/.claude/CLAUDE.md +0 -1
  138. package/.agents/skills/autoconverge/AGENTS.md +0 -1
  139. package/.agents/skills/autoconverge/SKILL.md +0 -431
  140. package/.agents/skills/autoconverge/reference/.claude/CLAUDE.md +0 -1
  141. package/.agents/skills/autoconverge/reference/AGENTS.md +0 -1
  142. package/.agents/skills/autoconverge/reference/closing-report.md +0 -93
  143. package/.agents/skills/autoconverge/reference/convergence-gates.md +0 -31
  144. package/.agents/skills/autoconverge/reference/convergence.md +0 -219
  145. package/.agents/skills/autoconverge/reference/copilot-findings.md +0 -51
  146. package/.agents/skills/autoconverge/reference/gotchas.md +0 -66
  147. package/.agents/skills/autoconverge/reference/headless-safety.md +0 -44
  148. package/.agents/skills/autoconverge/reference/multi-pr.md +0 -128
  149. package/.agents/skills/autoconverge/reference/self-closing-loop.md +0 -84
  150. package/.agents/skills/autoconverge/reference/stop-conditions.md +0 -127
  151. package/.agents/skills/autoconverge/test_portable_pacer_gate.py +0 -54
  152. package/.agents/skills/autoconverge/workflow/.claude/CLAUDE.md +0 -1
  153. package/.agents/skills/autoconverge/workflow/AGENTS.md +0 -1
  154. package/.agents/skills/autoconverge/workflow/aggregate_runs.py +0 -371
  155. package/.agents/skills/autoconverge/workflow/autoconverge_report_constants/.claude/CLAUDE.md +0 -1
  156. package/.agents/skills/autoconverge/workflow/autoconverge_report_constants/AGENTS.md +0 -1
  157. package/.agents/skills/autoconverge/workflow/autoconverge_report_constants/__init__.py +0 -0
  158. package/.agents/skills/autoconverge/workflow/autoconverge_report_constants/render_report_constants.py +0 -250
  159. package/.agents/skills/autoconverge/workflow/converge.clean-audit.test.mjs +0 -665
  160. package/.agents/skills/autoconverge/workflow/converge.codex-gate.test.mjs +0 -472
  161. package/.agents/skills/autoconverge/workflow/converge.contract.test.mjs +0 -64
  162. package/.agents/skills/autoconverge/workflow/converge.copilot-gate.test.mjs +0 -1009
  163. package/.agents/skills/autoconverge/workflow/converge.fix-progress.test.mjs +0 -107
  164. package/.agents/skills/autoconverge/workflow/converge.fix-recovery.test.mjs +0 -33
  165. package/.agents/skills/autoconverge/workflow/converge.merge-conflict.test.mjs +0 -15
  166. package/.agents/skills/autoconverge/workflow/converge.mjs +0 -3132
  167. package/.agents/skills/autoconverge/workflow/converge.p2-advance.test.mjs +0 -202
  168. package/.agents/skills/autoconverge/workflow/converge.path-aware.test.mjs +0 -47
  169. package/.agents/skills/autoconverge/workflow/converge.precatch.test.mjs +0 -152
  170. package/.agents/skills/autoconverge/workflow/converge.run-input.test.mjs +0 -116
  171. package/.agents/skills/autoconverge/workflow/converge_multi.mjs +0 -169
  172. package/.agents/skills/autoconverge/workflow/converge_multi.run-input.test.mjs +0 -173
  173. package/.agents/skills/autoconverge/workflow/convergence_summary.py +0 -110
  174. package/.agents/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a11d903476b803493.jsonl +0 -2
  175. package/.agents/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a26213978adeef6fb.jsonl +0 -2
  176. package/.agents/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a3def0d15ed9d9110.jsonl +0 -2
  177. package/.agents/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a41f41b1b708ee3b7.jsonl +0 -2
  178. package/.agents/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a758b880abecc3ff7.jsonl +0 -2
  179. package/.agents/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a8897b89656b1bd16.jsonl +0 -2
  180. package/.agents/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-ab1c2d3e4f5a6b7c8.jsonl +0 -2
  181. package/.agents/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-abd463d744a1437bc.jsonl +0 -2
  182. package/.agents/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-ad19d027ae8ee1816.jsonl +0 -2
  183. package/.agents/skills/autoconverge/workflow/fixtures/wf_run/workflows/wf_881252e6-700.json +0 -266
  184. package/.agents/skills/autoconverge/workflow/render_report.py +0 -1024
  185. package/.agents/skills/autoconverge/workflow/test_aggregate_runs.py +0 -134
  186. package/.agents/skills/autoconverge/workflow/test_convergence_summary.py +0 -149
  187. package/.agents/skills/autoconverge/workflow/test_render_report.py +0 -812
  188. package/.agents/skills/hitl/SKILL.md +0 -45
  189. package/.agents/skills/pr-cleanup/SKILL.md +0 -140
  190. package/.agents/skills/pr-cleanup/reference/process-inventory.md +0 -17
  191. package/.agents/skills/pr-cleanup/reference/task-seeds.md +0 -22
  192. package/.agents/skills/pr-name-by-capability/SKILL.md +0 -73
  193. package/.agents/skills/pr-name-by-capability/reference/fetch-commands.md +0 -29
  194. package/.agents/skills/pr-name-by-capability/reference/offense-examples.md +0 -32
  195. package/.agents/skills/pr-name-by-capability/reference/report-template.md +0 -29
  196. package/.agents/skills/pr-name-by-capability/reference/rule-checklist.md +0 -38
  197. package/.agents/skills/pr-name-by-capability/reference/task-seeds.md +0 -10
  198. package/.agents/skills/pr-plain-language-cleanup/SKILL.md +0 -93
  199. package/.agents/skills/pr-refinement/SKILL.md +0 -31
  200. package/.agents/skills/pr-shared-extraction/SKILL.md +0 -177
  201. package/.agents/skills/pr-shared-extraction/reference/examples.md +0 -46
  202. package/.agents/skills/pr-shared-extraction/reference/offense-taxonomy.md +0 -100
  203. package/.agents/skills/pr-small-cl/SKILL.md +0 -52
  204. package/.agents/skills/pr-title-description/SKILL.md +0 -96
  205. package/.agents/skills/prototype/SKILL.md +0 -85
  206. package/.agents/skills/prototype/reference/honest-limitations.md +0 -23
  207. package/.agents/skills/prototype/reference/promotion-tasks.md +0 -23
  208. package/.agents/skills/prototype/scripts/build_sandbox_settings.py +0 -249
  209. package/.agents/skills/prototype/scripts/conftest.py +0 -15
  210. package/.agents/skills/prototype/scripts/launch_sandbox.py +0 -205
  211. package/.agents/skills/prototype/scripts/probe_sandbox_safety.py +0 -311
  212. package/.agents/skills/prototype/scripts/prototype_scripts_constants/__init__.py +0 -1
  213. package/.agents/skills/prototype/scripts/prototype_scripts_constants/config/__init__.py +0 -0
  214. package/.agents/skills/prototype/scripts/prototype_scripts_constants/config/build_sandbox_settings_constants.py +0 -41
  215. package/.agents/skills/prototype/scripts/prototype_scripts_constants/config/launch_sandbox_constants.py +0 -23
  216. package/.agents/skills/prototype/scripts/prototype_scripts_constants/config/probe_sandbox_safety_constants.py +0 -45
  217. package/.agents/skills/prototype/scripts/prototype_scripts_constants/config/prototype_common_constants.py +0 -10
  218. package/.agents/skills/prototype/scripts/test_build_sandbox_settings.py +0 -275
  219. package/.agents/skills/prototype/scripts/test_launch_sandbox.py +0 -303
  220. package/.agents/skills/prototype/scripts/test_probe_sandbox_safety.py +0 -312
  221. package/.agents/skills/prototype/workflows/promotion.md +0 -25
  222. package/.agents/skills/prototype/workflows/sandbox.md +0 -35
  223. package/.agents/skills/rebase/.claude/CLAUDE.md +0 -1
  224. package/.agents/skills/rebase/AGENTS.md +0 -1
  225. package/.agents/skills/rebase/SKILL.md +0 -178
  226. package/.agents/skills/review-router/SKILL.md +0 -51
  227. package/.agents/skills/review-router/reference/route-policy.json +0 -7
  228. package/.agents/skills/review-router/reference/task-seeds.md +0 -1
  229. package/.agents/skills/review-router/scripts/conftest.py +0 -4
  230. package/.agents/skills/review-router/scripts/review_router.py +0 -50
  231. package/.agents/skills/review-router/scripts/review_router_cli.py +0 -211
  232. package/.agents/skills/review-router/scripts/review_router_constants/__init__.py +0 -1
  233. package/.agents/skills/review-router/scripts/review_router_constants/config/__init__.py +0 -0
  234. package/.agents/skills/review-router/scripts/review_router_constants/config/constants.py +0 -13
  235. package/.agents/skills/review-router/scripts/test_review_router.py +0 -23
  236. package/.agents/skills/review-router/scripts/test_review_router_cli.py +0 -47
  237. package/.agents/skills/review-tier/SKILL.md +0 -56
  238. package/.agents/skills/review-tier/reference/task-seeds.md +0 -1
  239. package/.agents/skills/review-tier/reference/tier-policy.json +0 -9
  240. package/.agents/skills/review-tier/scripts/conftest.py +0 -4
  241. package/.agents/skills/review-tier/scripts/review_tier.py +0 -359
  242. package/.agents/skills/review-tier/scripts/review_tier_constants/__init__.py +0 -1
  243. package/.agents/skills/review-tier/scripts/review_tier_constants/config/__init__.py +0 -0
  244. package/.agents/skills/review-tier/scripts/review_tier_constants/config/constants.py +0 -29
  245. package/.agents/skills/review-tier/scripts/test_generation.py +0 -159
  246. package/.agents/skills/review-tier/scripts/test_review_tier.py +0 -33
  247. package/.agents/skills/run-claude-dev-env/SKILL.md +0 -84
  248. package/.agents/skills/session-log/.claude/CLAUDE.md +0 -1
  249. package/.agents/skills/session-log/AGENTS.md +0 -1
  250. package/.agents/skills/session-log/SKILL.md +0 -170
  251. package/.agents/skills/session-log/templates/frontmatter.md +0 -40
  252. package/.agents/skills/session-tidy/.claude/CLAUDE.md +0 -1
  253. package/.agents/skills/session-tidy/AGENTS.md +0 -1
  254. package/.agents/skills/session-tidy/SKILL.md +0 -191
  255. package/.agents/skills/skill-builder/references/.claude/CLAUDE.md +0 -1
  256. package/.agents/skills/skill-builder/references/AGENTS.md +0 -1
  257. package/.agents/skills/skill-builder/references/delegation-map.md +0 -130
  258. package/.agents/skills/skill-builder/references/description-field.md +0 -111
  259. package/.agents/skills/skill-builder/references/deterministic-elements.md +0 -218
  260. package/.agents/skills/skill-builder/references/progressive-disclosure.md +0 -122
  261. package/.agents/skills/skill-builder/references/self-audit-checklist.md +0 -126
  262. package/.agents/skills/skill-builder/references/skill-modularity.md +0 -111
  263. package/.agents/skills/skill-builder/references/skill-types.md +0 -232
  264. package/.agents/skills/skill-builder/references/thariq-x-post-skills.json +0 -33
  265. package/.agents/skills/skill-builder/templates/.claude/CLAUDE.md +0 -1
  266. package/.agents/skills/skill-builder/templates/AGENTS.md +0 -1
  267. package/.agents/skills/skill-builder/templates/gap-analysis.md +0 -87
  268. package/.agents/skills/skill-builder/workflows/.claude/CLAUDE.md +0 -1
  269. package/.agents/skills/skill-builder/workflows/AGENTS.md +0 -1
  270. package/.agents/skills/skill-builder/workflows/improve-skill.md +0 -136
  271. package/.agents/skills/skill-builder/workflows/new-skill.md +0 -179
  272. package/.agents/skills/skill-builder/workflows/polish-skill.md +0 -139
  273. package/.agents/skills/source-command-sr-loop/SKILL.md +0 -82
  274. package/.agents/skills/update/.claude/CLAUDE.md +0 -1
  275. package/.agents/skills/update/AGENTS.md +0 -1
  276. package/.agents/skills/update/SKILL.md +0 -190
  277. package/_shared/pr-loop/AGENTS.md +0 -1
  278. package/_shared/pr-loop/CLAUDE.md +0 -1
  279. package/_shared/pr-loop/audit-contract.md +0 -183
  280. package/_shared/pr-loop/audit-reply-template.md +0 -151
  281. package/_shared/pr-loop/code-rules-gate.md +0 -65
  282. package/_shared/pr-loop/fix-protocol.md +0 -60
  283. package/_shared/pr-loop/gh-payloads.md +0 -75
  284. package/_shared/pr-loop/post-audit-thread-contract.md +0 -51
  285. package/_shared/pr-loop/precatch-rubric.md +0 -66
  286. package/_shared/pr-loop/preflight-proposal.md +0 -56
  287. package/_shared/pr-loop/scripts/post_audit_thread.py +0 -1242
  288. package/_shared/pr-loop/scripts/pr_loop_shared_constants/post_audit_thread_constants.py +0 -199
  289. package/_shared/pr-loop/scripts/tests/test_post_audit_thread.py +0 -1115
  290. package/_shared/pr-loop/scripts/tests/test_post_audit_thread_constants.py +0 -129
  291. package/_shared/pr-loop/state-schema.md +0 -45
  292. package/_shared/pr-loop/worker-spawn.md +0 -189
  293. /package/{.agents/skills/_shared/pr-loop/scripts → scripts}/test_durable_post_lint.py +0 -0
@@ -1,287 +0,0 @@
1
- """Tests for preflight_worktree against real git working trees."""
2
-
3
- from __future__ import annotations
4
-
5
- import importlib.util
6
- import subprocess
7
- import sys
8
- from pathlib import Path
9
- from types import ModuleType
10
-
11
- import pytest
12
-
13
- _SCRIPTS_DIR = Path(__file__).resolve().parent
14
- if str(_SCRIPTS_DIR) not in sys.path:
15
- sys.path.insert(0, str(_SCRIPTS_DIR))
16
-
17
-
18
- def _load_preflight() -> ModuleType:
19
- module_path = _SCRIPTS_DIR / "preflight_worktree.py"
20
- spec = importlib.util.spec_from_file_location("preflight_worktree", module_path)
21
- assert spec is not None
22
- assert spec.loader is not None
23
- module = importlib.util.module_from_spec(spec)
24
- sys.modules["preflight_worktree"] = module
25
- spec.loader.exec_module(module)
26
- return module
27
-
28
-
29
- preflight = _load_preflight()
30
-
31
- GIT_TIMEOUT = 30
32
- CLAUDE_REMOTE = "https://github.com/jl-cmd/claude-dev-env.git"
33
- GIT_CEILING_DIRECTORIES = "GIT_CEILING_DIRECTORIES"
34
-
35
-
36
- @pytest.fixture(autouse=True)
37
- def _isolate_git_from_ancestor_repos(
38
- tmp_path: Path, monkeypatch: pytest.MonkeyPatch
39
- ) -> None:
40
- monkeypatch.setenv(GIT_CEILING_DIRECTORIES, str(tmp_path))
41
-
42
-
43
- def _git(repo_dir: Path, *args: str) -> None:
44
- subprocess.run(
45
- ["git", "-C", str(repo_dir), *args],
46
- check=True,
47
- capture_output=True,
48
- text=True,
49
- timeout=GIT_TIMEOUT,
50
- )
51
-
52
-
53
- def _init_repo(repo_dir: Path, origin_url: str | None) -> Path:
54
- repo_dir.mkdir(parents=True, exist_ok=True)
55
- subprocess.run(
56
- ["git", "init", "-q", str(repo_dir)],
57
- check=True,
58
- capture_output=True,
59
- text=True,
60
- timeout=GIT_TIMEOUT,
61
- )
62
- if origin_url is not None:
63
- _git(repo_dir, "remote", "add", "origin", origin_url)
64
- return repo_dir
65
-
66
-
67
- @pytest.mark.parametrize(
68
- ("remote_url", "expected_owner", "expected_repo"),
69
- [
70
- (
71
- "https://github.com/jl-cmd/claude-dev-env.git",
72
- "jl-cmd",
73
- "claude-dev-env",
74
- ),
75
- (
76
- "https://github.com/jl-cmd/claude-dev-env",
77
- "jl-cmd",
78
- "claude-dev-env",
79
- ),
80
- ("git@github.com:Example/llm-settings.git", "example", "llm-settings"),
81
- (
82
- "ssh://git@github.com/jl-cmd/Claude-Dev-Env",
83
- "jl-cmd",
84
- "claude-dev-env",
85
- ),
86
- ("https://github.com/jl-cmd/repo/", "jl-cmd", "repo"),
87
- ],
88
- )
89
- def test_parse_repo_identity_accepts_every_github_remote_form(
90
- remote_url: str, expected_owner: str, expected_repo: str
91
- ) -> None:
92
- identity = preflight.parse_repo_identity(remote_url)
93
- assert identity is not None
94
- assert identity.owner == expected_owner
95
- assert identity.repo == expected_repo
96
-
97
-
98
- @pytest.mark.parametrize(
99
- "remote_url",
100
- ["https://gitlab.com/foo/bar.git", "", "not-a-url"],
101
- )
102
- def test_parse_repo_identity_rejects_non_github_remotes(remote_url: str) -> None:
103
- assert preflight.parse_repo_identity(remote_url) is None
104
-
105
-
106
- def test_is_inside_work_tree_true_in_git_repo(tmp_path: Path) -> None:
107
- repo_dir = _init_repo(tmp_path / "session", None)
108
- assert preflight.is_inside_work_tree(repo_dir) is True
109
-
110
-
111
- def test_is_inside_work_tree_false_in_plain_directory(tmp_path: Path) -> None:
112
- plain_dir = tmp_path / "home"
113
- plain_dir.mkdir()
114
- assert preflight.is_inside_work_tree(plain_dir) is False
115
-
116
-
117
- def test_worktree_machinery_is_healthy_true_in_git_repo(tmp_path: Path) -> None:
118
- repo_dir = _init_repo(tmp_path / "session", None)
119
- assert preflight.worktree_machinery_is_healthy(repo_dir) is True
120
-
121
-
122
- def test_worktree_machinery_is_healthy_false_in_plain_directory(
123
- tmp_path: Path,
124
- ) -> None:
125
- plain_dir = tmp_path / "home"
126
- plain_dir.mkdir()
127
- assert preflight.worktree_machinery_is_healthy(plain_dir) is False
128
-
129
-
130
- def test_classify_same_repo_when_origin_matches_pr(tmp_path: Path) -> None:
131
- repo_dir = _init_repo(tmp_path / "session", CLAUDE_REMOTE)
132
- pr_identity = preflight.RepoIdentity("jl-cmd", "claude-dev-env")
133
- verdict = preflight.classify_environment(repo_dir, pr_identity)
134
- assert verdict.outcome == preflight.OUTCOME_SAME_REPO
135
- assert verdict.cwd_identity == pr_identity
136
- assert verdict.has_healthy_worktree_machinery is True
137
-
138
-
139
- def test_classify_different_repo_when_origin_is_another_github_repo(
140
- tmp_path: Path,
141
- ) -> None:
142
- repo_dir = _init_repo(
143
- tmp_path / "session", "https://github.com/example/llm-settings.git"
144
- )
145
- pr_identity = preflight.RepoIdentity("jl-cmd", "claude-dev-env")
146
- verdict = preflight.classify_environment(repo_dir, pr_identity)
147
- assert verdict.outcome == preflight.OUTCOME_DIFFERENT_REPO
148
- assert verdict.cwd_identity == preflight.RepoIdentity("example", "llm-settings")
149
-
150
-
151
- def test_classify_different_repo_when_origin_is_non_github(tmp_path: Path) -> None:
152
- repo_dir = _init_repo(tmp_path / "session", "https://gitlab.com/foo/bar.git")
153
- pr_identity = preflight.RepoIdentity("jl-cmd", "claude-dev-env")
154
- verdict = preflight.classify_environment(repo_dir, pr_identity)
155
- assert verdict.outcome == preflight.OUTCOME_DIFFERENT_REPO
156
- assert verdict.cwd_identity is None
157
-
158
-
159
- def test_classify_re_rooted_when_origin_is_absent(tmp_path: Path) -> None:
160
- repo_dir = _init_repo(tmp_path / "session", None)
161
- pr_identity = preflight.RepoIdentity("jl-cmd", "claude-dev-env")
162
- verdict = preflight.classify_environment(repo_dir, pr_identity)
163
- assert verdict.outcome == preflight.OUTCOME_RE_ROOTED
164
-
165
-
166
- def test_classify_re_rooted_when_directory_is_not_a_work_tree(
167
- tmp_path: Path,
168
- ) -> None:
169
- plain_dir = tmp_path / "home"
170
- plain_dir.mkdir()
171
- pr_identity = preflight.RepoIdentity("jl-cmd", "claude-dev-env")
172
- verdict = preflight.classify_environment(plain_dir, pr_identity)
173
- assert verdict.outcome == preflight.OUTCOME_RE_ROOTED
174
- assert verdict.has_healthy_worktree_machinery is False
175
-
176
-
177
- @pytest.mark.parametrize(
178
- ("outcome", "is_healthy", "mode", "expected_exit"),
179
- [
180
- ("same_repo", True, "strict", 0),
181
- ("same_repo", True, "classify", 0),
182
- ("same_repo", False, "strict", 1),
183
- ("same_repo", False, "classify", 1),
184
- ("different_repo", True, "strict", 1),
185
- ("different_repo", True, "classify", 0),
186
- ("re_rooted", False, "strict", 1),
187
- ("re_rooted", False, "classify", 1),
188
- ],
189
- )
190
- def test_decide_exit_code_matrix(
191
- outcome: str, is_healthy: bool, mode: str, expected_exit: int
192
- ) -> None:
193
- verdict = preflight.PreflightVerdict(
194
- outcome=outcome,
195
- cwd_identity=None,
196
- has_healthy_worktree_machinery=is_healthy,
197
- )
198
- assert preflight.decide_exit_code(verdict, mode) == expected_exit
199
-
200
-
201
- def test_build_report_lines_marks_outcome_and_routes_cross_repo() -> None:
202
- verdict = preflight.PreflightVerdict(
203
- outcome=preflight.OUTCOME_DIFFERENT_REPO,
204
- cwd_identity=preflight.RepoIdentity("example", "llm-settings"),
205
- has_healthy_worktree_machinery=True,
206
- )
207
- pr_identity = preflight.RepoIdentity("jl-cmd", "claude-dev-env")
208
- classify_lines = preflight.build_report_lines(
209
- verdict, "classify", Path("/tmp/x"), pr_identity
210
- )
211
- assert classify_lines[0] == "PREFLIGHT_OUTCOME=different_repo"
212
- assert any("ROUTE" in line for line in classify_lines)
213
- strict_lines = preflight.build_report_lines(
214
- verdict, "strict", Path("/tmp/x"), pr_identity
215
- )
216
- assert any("ABORT" in line for line in strict_lines)
217
-
218
-
219
- def test_build_report_lines_aborts_on_broken_worktree_machinery() -> None:
220
- verdict = preflight.PreflightVerdict(
221
- outcome=preflight.OUTCOME_SAME_REPO,
222
- cwd_identity=preflight.RepoIdentity("jl-cmd", "claude-dev-env"),
223
- has_healthy_worktree_machinery=False,
224
- )
225
- pr_identity = preflight.RepoIdentity("jl-cmd", "claude-dev-env")
226
- lines = preflight.build_report_lines(verdict, "strict", Path("/tmp/x"), pr_identity)
227
- assert lines[0] == "PREFLIGHT_OUTCOME=same_repo"
228
- assert any("git worktree prune" in line for line in lines)
229
-
230
-
231
- def test_main_strict_passes_in_matching_repo(
232
- tmp_path: Path, monkeypatch: pytest.MonkeyPatch, capsys: pytest.CaptureFixture[str]
233
- ) -> None:
234
- repo_dir = _init_repo(tmp_path / "session", CLAUDE_REMOTE)
235
- monkeypatch.chdir(repo_dir)
236
- exit_code = preflight.main(
237
- ["--owner", "jl-cmd", "--repo", "claude-dev-env", "--mode", "strict"]
238
- )
239
- captured = capsys.readouterr()
240
- assert exit_code == preflight.EXIT_PREFLIGHT_OK
241
- assert "PREFLIGHT_OUTCOME=same_repo" in captured.out
242
-
243
-
244
- def test_main_strict_aborts_when_session_rooted_in_other_repo(
245
- tmp_path: Path, monkeypatch: pytest.MonkeyPatch, capsys: pytest.CaptureFixture[str]
246
- ) -> None:
247
- repo_dir = _init_repo(
248
- tmp_path / "session", "https://github.com/example/llm-settings.git"
249
- )
250
- monkeypatch.chdir(repo_dir)
251
- exit_code = preflight.main(
252
- ["--owner", "jl-cmd", "--repo", "claude-dev-env", "--mode", "strict"]
253
- )
254
- captured = capsys.readouterr()
255
- assert exit_code == preflight.EXIT_PREFLIGHT_ABORT
256
- assert "PREFLIGHT_OUTCOME=different_repo" in captured.out
257
- assert "ABORT" in captured.out
258
-
259
-
260
- def test_main_classify_routes_cross_repo_without_abort(
261
- tmp_path: Path, monkeypatch: pytest.MonkeyPatch, capsys: pytest.CaptureFixture[str]
262
- ) -> None:
263
- repo_dir = _init_repo(
264
- tmp_path / "session", "https://github.com/example/llm-settings.git"
265
- )
266
- monkeypatch.chdir(repo_dir)
267
- exit_code = preflight.main(
268
- ["--owner", "jl-cmd", "--repo", "claude-dev-env", "--mode", "classify"]
269
- )
270
- captured = capsys.readouterr()
271
- assert exit_code == preflight.EXIT_PREFLIGHT_OK
272
- assert "PREFLIGHT_OUTCOME=different_repo" in captured.out
273
- assert "ROUTE" in captured.out
274
-
275
-
276
- def test_main_classify_aborts_when_re_rooted(
277
- tmp_path: Path, monkeypatch: pytest.MonkeyPatch, capsys: pytest.CaptureFixture[str]
278
- ) -> None:
279
- plain_dir = tmp_path / "home"
280
- plain_dir.mkdir()
281
- monkeypatch.chdir(plain_dir)
282
- exit_code = preflight.main(
283
- ["--owner", "jl-cmd", "--repo", "claude-dev-env", "--mode", "classify"]
284
- )
285
- captured = capsys.readouterr()
286
- assert exit_code == preflight.EXIT_PREFLIGHT_ABORT
287
- assert "PREFLIGHT_OUTCOME=re_rooted" in captured.out
@@ -1,207 +0,0 @@
1
- """Tests for select_converge_pacer — host tool surface → pacer mapping."""
2
-
3
- from __future__ import annotations
4
-
5
- import json
6
- import subprocess
7
- import sys
8
- from pathlib import Path
9
-
10
- import pytest
11
-
12
- _SCRIPTS_DIR = Path(__file__).resolve().parent
13
- if str(_SCRIPTS_DIR) not in sys.path:
14
- sys.path.insert(0, str(_SCRIPTS_DIR))
15
-
16
- import select_converge_pacer as pacer_module # noqa: E402
17
- from skills_pr_loop_constants.pacer_constants import ( # noqa: E402
18
- CLI_HAS_SCHEDULE_WAKEUP_FLAG,
19
- CLI_HAS_WORKFLOW_FLAG,
20
- CLI_SKILL_FLAG,
21
- ENTRY_SKILL_AUTOCONVERGE,
22
- ENTRY_SKILL_PR_CONVERGE,
23
- EXIT_SUCCESS,
24
- EXIT_USAGE_ERROR,
25
- PACER_PORTABLE,
26
- PACER_SCHEDULE_WAKEUP,
27
- PACER_WORKFLOW,
28
- RESULT_KEY_ENTRY_SKILL,
29
- RESULT_KEY_HAS_SCHEDULE_WAKEUP,
30
- RESULT_KEY_HAS_WORKFLOW,
31
- RESULT_KEY_PACER,
32
- )
33
-
34
- SCRIPT_PATH = _SCRIPTS_DIR / "select_converge_pacer.py"
35
-
36
-
37
- def test_autoconverge_with_workflow_selects_workflow() -> None:
38
- selection = pacer_module.select_converge_pacer(
39
- entry_skill=ENTRY_SKILL_AUTOCONVERGE,
40
- has_workflow=True,
41
- has_schedule_wakeup=False,
42
- )
43
- assert selection.pacer == PACER_WORKFLOW
44
- assert selection.entry_skill == ENTRY_SKILL_AUTOCONVERGE
45
-
46
-
47
- def test_autoconverge_without_workflow_selects_portable() -> None:
48
- selection = pacer_module.select_converge_pacer(
49
- entry_skill=ENTRY_SKILL_AUTOCONVERGE,
50
- has_workflow=False,
51
- has_schedule_wakeup=True,
52
- )
53
- assert selection.pacer == PACER_PORTABLE
54
-
55
-
56
- def test_pr_converge_with_schedule_wakeup_selects_schedule_wakeup() -> None:
57
- selection = pacer_module.select_converge_pacer(
58
- entry_skill=ENTRY_SKILL_PR_CONVERGE,
59
- has_workflow=False,
60
- has_schedule_wakeup=True,
61
- )
62
- assert selection.pacer == PACER_SCHEDULE_WAKEUP
63
- assert selection.entry_skill == ENTRY_SKILL_PR_CONVERGE
64
-
65
-
66
- def test_pr_converge_without_schedule_wakeup_selects_portable() -> None:
67
- selection = pacer_module.select_converge_pacer(
68
- entry_skill=ENTRY_SKILL_PR_CONVERGE,
69
- has_workflow=True,
70
- has_schedule_wakeup=False,
71
- )
72
- assert selection.pacer == PACER_PORTABLE
73
-
74
-
75
- def test_third_party_surface_selects_portable_for_both_entries() -> None:
76
- for each_skill in (ENTRY_SKILL_AUTOCONVERGE, ENTRY_SKILL_PR_CONVERGE):
77
- selection = pacer_module.select_converge_pacer(
78
- entry_skill=each_skill,
79
- has_workflow=False,
80
- has_schedule_wakeup=False,
81
- )
82
- assert selection.pacer == PACER_PORTABLE, each_skill
83
-
84
-
85
- def test_unknown_entry_skill_raises() -> None:
86
- with pytest.raises(ValueError, match="entry skill must be one of"):
87
- pacer_module.select_converge_pacer(
88
- entry_skill="bugteam",
89
- has_workflow=False,
90
- has_schedule_wakeup=False,
91
- )
92
-
93
-
94
- def test_parse_bool_flag_accepts_common_tokens() -> None:
95
- assert pacer_module.parse_bool_flag("1") is True
96
- assert pacer_module.parse_bool_flag("true") is True
97
- assert pacer_module.parse_bool_flag("YES") is True
98
- assert pacer_module.parse_bool_flag("0") is False
99
- assert pacer_module.parse_bool_flag("false") is False
100
- assert pacer_module.parse_bool_flag("OFF") is False
101
-
102
-
103
- def test_parse_bool_flag_rejects_unknown_token() -> None:
104
- with pytest.raises(ValueError, match="boolean token"):
105
- pacer_module.parse_bool_flag("maybe")
106
-
107
-
108
- def test_selection_as_json_dict_uses_stable_keys() -> None:
109
- selection = pacer_module.select_converge_pacer(
110
- entry_skill=ENTRY_SKILL_PR_CONVERGE,
111
- has_workflow=False,
112
- has_schedule_wakeup=False,
113
- )
114
- payload = pacer_module.selection_as_json_dict(selection)
115
- assert payload[RESULT_KEY_PACER] == PACER_PORTABLE
116
- assert payload[RESULT_KEY_ENTRY_SKILL] == ENTRY_SKILL_PR_CONVERGE
117
- assert payload[RESULT_KEY_HAS_WORKFLOW] is False
118
- assert payload[RESULT_KEY_HAS_SCHEDULE_WAKEUP] is False
119
-
120
-
121
- def test_cli_prints_json_and_exits_zero() -> None:
122
- completed = subprocess.run(
123
- [
124
- sys.executable,
125
- str(SCRIPT_PATH),
126
- "--skill",
127
- ENTRY_SKILL_AUTOCONVERGE,
128
- "--has-workflow",
129
- "0",
130
- "--has-schedule-wakeup",
131
- "0",
132
- ],
133
- check=False,
134
- capture_output=True,
135
- text=True,
136
- )
137
- assert completed.returncode == EXIT_SUCCESS, completed.stderr
138
- payload = json.loads(completed.stdout)
139
- assert payload[RESULT_KEY_PACER] == PACER_PORTABLE
140
- assert payload[RESULT_KEY_ENTRY_SKILL] == ENTRY_SKILL_AUTOCONVERGE
141
-
142
-
143
- def test_cli_rejects_bad_bool_with_usage_exit() -> None:
144
- completed = subprocess.run(
145
- [
146
- sys.executable,
147
- str(SCRIPT_PATH),
148
- "--skill",
149
- ENTRY_SKILL_PR_CONVERGE,
150
- "--has-workflow",
151
- "nope",
152
- "--has-schedule-wakeup",
153
- "0",
154
- ],
155
- check=False,
156
- capture_output=True,
157
- text=True,
158
- )
159
- assert completed.returncode == EXIT_USAGE_ERROR
160
- assert "boolean token" in completed.stderr
161
-
162
-
163
- def test_main_returns_usage_error_on_value_error(
164
- monkeypatch: pytest.MonkeyPatch,
165
- ) -> None:
166
- def raise_value_error(**_kwargs: object) -> object:
167
- raise ValueError("entry skill must be one of")
168
-
169
- monkeypatch.setattr(
170
- pacer_module, "select_converge_pacer", raise_value_error
171
- )
172
- exit_code = pacer_module.main(
173
- [
174
- "--skill",
175
- ENTRY_SKILL_PR_CONVERGE,
176
- "--has-workflow",
177
- "0",
178
- "--has-schedule-wakeup",
179
- "0",
180
- ]
181
- )
182
- assert exit_code == EXIT_USAGE_ERROR
183
-
184
-
185
- def test_build_argument_parser_requires_skill_and_host_flags() -> None:
186
- parser = pacer_module.build_argument_parser()
187
- all_option_strings = {
188
- each_option
189
- for each_action in parser._actions
190
- for each_option in each_action.option_strings
191
- }
192
- assert CLI_SKILL_FLAG in all_option_strings
193
- assert CLI_HAS_WORKFLOW_FLAG in all_option_strings
194
- assert CLI_HAS_SCHEDULE_WAKEUP_FLAG in all_option_strings
195
- parsed_namespace = parser.parse_args(
196
- [
197
- CLI_SKILL_FLAG,
198
- ENTRY_SKILL_AUTOCONVERGE,
199
- CLI_HAS_WORKFLOW_FLAG,
200
- "1",
201
- CLI_HAS_SCHEDULE_WAKEUP_FLAG,
202
- "0",
203
- ]
204
- )
205
- assert parsed_namespace.skill == ENTRY_SKILL_AUTOCONVERGE
206
- assert parsed_namespace.has_workflow == "1"
207
- assert parsed_namespace.has_schedule_wakeup == "0"
@@ -1,59 +0,0 @@
1
- """Tests for teardown_worktrees.teardown_run consuming the typed workspace."""
2
-
3
- from __future__ import annotations
4
-
5
- import importlib.util
6
- import sys
7
- from pathlib import Path
8
- from types import ModuleType
9
-
10
- _SCRIPTS_DIR = Path(__file__).resolve().parent
11
- if str(_SCRIPTS_DIR) not in sys.path:
12
- sys.path.insert(0, str(_SCRIPTS_DIR))
13
-
14
-
15
- def _load_teardown_module() -> ModuleType:
16
- module_path = _SCRIPTS_DIR / "teardown_worktrees.py"
17
- spec = importlib.util.spec_from_file_location("teardown_worktrees", module_path)
18
- assert spec is not None
19
- assert spec.loader is not None
20
- module = importlib.util.module_from_spec(spec)
21
- spec.loader.exec_module(module)
22
- return module
23
-
24
-
25
- teardown_worktrees = _load_teardown_module()
26
-
27
-
28
- def test_teardown_run_returns_zero_when_no_worktrees_exist(tmp_path: Path) -> None:
29
- """With absent worktrees, teardown_run removes nothing and reports zero,
30
- reading each worktree path from the typed PerPrWorkspace.worktree attribute
31
- rather than a dict lookup."""
32
- run_temp_dir = tmp_path / "run"
33
- run_temp_dir.mkdir()
34
- all_pr_entries: list[dict[str, object]] = [
35
- {"number": 7, "owner": "owner", "repo": "repo"},
36
- ]
37
- removed_count = teardown_worktrees.teardown_run(
38
- run_temp_dir=run_temp_dir,
39
- all_pr_entries=all_pr_entries,
40
- )
41
- assert removed_count == 0
42
- assert not run_temp_dir.exists()
43
-
44
-
45
- def test_teardown_run_skips_entries_without_integer_number(tmp_path: Path) -> None:
46
- """A PR entry whose number is not an integer is skipped before any workspace
47
- resolution, so teardown_run reports zero removals and still clears the run
48
- temp directory."""
49
- run_temp_dir = tmp_path / "run"
50
- run_temp_dir.mkdir()
51
- all_pr_entries: list[dict[str, object]] = [
52
- {"number": "not-an-int", "owner": "owner", "repo": "repo"},
53
- ]
54
- removed_count = teardown_worktrees.teardown_run(
55
- run_temp_dir=run_temp_dir,
56
- all_pr_entries=all_pr_entries,
57
- )
58
- assert removed_count == 0
59
- assert not run_temp_dir.exists()