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,355 +0,0 @@
1
- """Load and validate the A-Q audit-category schema.
2
-
3
- One machine-readable source under audit-rubrics/audit-categories.json holds
4
- each category id, title, slug, and sub-bucket id/axis pairs. Worked examples
5
- stay in the rubric markdown files only.
6
-
7
- ::
8
-
9
- schema = load_audit_category_schema()
10
- entries = category_id_title_entries()
11
- # entries[0] == ("A", "API contract verification")
12
- findings = validate_projections()
13
- # findings == [] when rubrics and prompt skeletons match the schema
14
-
15
- Use validate_projections before shipping a rubric or prompt change so the
16
- three surfaces cannot drift.
17
- """
18
-
19
- from __future__ import annotations
20
-
21
- import argparse
22
- import json
23
- import re
24
- import sys
25
- from pathlib import Path
26
-
27
- from skills_pr_loop_constants.audit_category_schema_constants import (
28
- CATEGORY_ID_KEY,
29
- CATEGORY_RUBRICS_DIRECTORY,
30
- CATEGORY_SLUG_KEY,
31
- CATEGORY_SLUG_PREFIX_TEMPLATE,
32
- CATEGORY_SUB_BUCKETS_KEY,
33
- CATEGORY_TITLE_KEY,
34
- EXPECTED_CATEGORY_IDS,
35
- HEADING_LETTER_GROUP,
36
- HEADING_PATTERN,
37
- HEADING_TITLE_GROUP,
38
- JSON_INDENT,
39
- NEWLINE,
40
- PACKAGE_ROOT,
41
- PROMPTS_DIRECTORY,
42
- RUBRIC_SUB_BUCKET_ROW_TEMPLATE,
43
- SCHEMA_CATEGORIES_KEY,
44
- SCHEMA_RELATIVE_PATH,
45
- SCHEMA_VERSION,
46
- SCHEMA_VERSION_KEY,
47
- SKELETON_COUNT_PATTERN,
48
- SKELETON_PLACEHOLDER_FRAGMENT,
49
- SKELETON_SEPARATOR_LINE,
50
- SUB_BUCKET_AXIS_KEY,
51
- UTF8_ENCODING,
52
- )
53
-
54
- CategoryMapping = dict[str, object]
55
- SchemaMapping = dict[str, object]
56
-
57
-
58
- def audit_category_schema_path() -> Path:
59
- """Return the path to the committed A-Q schema JSON file.
60
-
61
- Returns:
62
- Absolute path to audit-categories.json under the package root.
63
- """
64
- return PACKAGE_ROOT / SCHEMA_RELATIVE_PATH
65
-
66
-
67
- def load_audit_category_schema() -> SchemaMapping:
68
- """Load and structurally check the A-Q schema document.
69
-
70
- Returns:
71
- The schema object with schema_version and categories.
72
-
73
- Raises:
74
- FileNotFoundError: When the schema file is missing.
75
- ValueError: When required fields or order are wrong.
76
- json.JSONDecodeError: When the schema file is not valid JSON.
77
- """
78
- schema_path = audit_category_schema_path()
79
- loaded_document = json.loads(schema_path.read_text(encoding=UTF8_ENCODING))
80
- if not isinstance(loaded_document, dict):
81
- raise ValueError("schema root must be an object")
82
- if loaded_document.get(SCHEMA_VERSION_KEY) != SCHEMA_VERSION:
83
- raise ValueError(
84
- f"schema_version must be {SCHEMA_VERSION}, "
85
- f"got {loaded_document.get(SCHEMA_VERSION_KEY)!r}"
86
- )
87
- all_categories = loaded_document.get(SCHEMA_CATEGORIES_KEY)
88
- if not isinstance(all_categories, list) or not all_categories:
89
- raise ValueError("categories must be a non-empty list")
90
- all_ids = [
91
- each_category.get(CATEGORY_ID_KEY)
92
- for each_category in all_categories
93
- if isinstance(each_category, dict)
94
- ]
95
- if all_ids != list(EXPECTED_CATEGORY_IDS):
96
- raise ValueError(f"categories must list A-Q in order, got {all_ids!r}")
97
- all_checked_categories: list[CategoryMapping] = []
98
- for each_category in all_categories:
99
- if not isinstance(each_category, dict):
100
- raise ValueError("each category must be an object")
101
- all_checked_categories.append(_require_category_shape(each_category))
102
- return {
103
- SCHEMA_VERSION_KEY: SCHEMA_VERSION,
104
- SCHEMA_CATEGORIES_KEY: all_checked_categories,
105
- }
106
-
107
-
108
- def _require_category_shape(all_category_fields: CategoryMapping) -> CategoryMapping:
109
- category_id = all_category_fields.get(CATEGORY_ID_KEY)
110
- if not isinstance(category_id, str) or len(category_id) != 1:
111
- raise ValueError(f"category id must be a single letter, got {category_id!r}")
112
- title = all_category_fields.get(CATEGORY_TITLE_KEY)
113
- if not isinstance(title, str) or not title.strip():
114
- raise ValueError(f"category {category_id} title must be a non-empty string")
115
- slug = all_category_fields.get(CATEGORY_SLUG_KEY)
116
- expected_slug_prefix = CATEGORY_SLUG_PREFIX_TEMPLATE.format(letter=category_id.lower())
117
- if not isinstance(slug, str) or not slug.startswith(expected_slug_prefix):
118
- raise ValueError(
119
- f"category {category_id} slug must start with {expected_slug_prefix!r}, "
120
- f"got {slug!r}"
121
- )
122
- all_sub_bucket_fields = all_category_fields.get(CATEGORY_SUB_BUCKETS_KEY)
123
- if not isinstance(all_sub_bucket_fields, list) or not all_sub_bucket_fields:
124
- raise ValueError(f"category {category_id} needs a non-empty sub_buckets list")
125
- all_sub_buckets: list[CategoryMapping] = []
126
- for each_index, each_sub_bucket in enumerate(all_sub_bucket_fields):
127
- if not isinstance(each_sub_bucket, dict):
128
- raise ValueError(f"category {category_id} sub_bucket {each_index} must be object")
129
- expected_id = f"{category_id}{each_index + 1}"
130
- sub_bucket_id = each_sub_bucket.get(CATEGORY_ID_KEY)
131
- if sub_bucket_id != expected_id:
132
- raise ValueError(
133
- f"category {category_id} sub_bucket {each_index} id must be "
134
- f"{expected_id}, got {sub_bucket_id!r}"
135
- )
136
- axis_name = each_sub_bucket.get(SUB_BUCKET_AXIS_KEY)
137
- if not isinstance(axis_name, str) or not axis_name.strip():
138
- raise ValueError(
139
- f"category {category_id} sub_bucket {sub_bucket_id} needs axis_name"
140
- )
141
- all_sub_buckets.append(
142
- {CATEGORY_ID_KEY: expected_id, SUB_BUCKET_AXIS_KEY: axis_name}
143
- )
144
- return {
145
- CATEGORY_ID_KEY: category_id,
146
- CATEGORY_TITLE_KEY: title,
147
- CATEGORY_SLUG_KEY: slug,
148
- CATEGORY_SUB_BUCKETS_KEY: all_sub_buckets,
149
- }
150
-
151
-
152
- def category_id_title_entries() -> list[tuple[str, str]]:
153
- """Return (id, title) pairs in A-Q order from the schema.
154
-
155
- Returns:
156
- List of (category letter, title) tuples from the schema file.
157
- """
158
- all_schema = load_audit_category_schema()
159
- all_categories = all_schema[SCHEMA_CATEGORIES_KEY]
160
- assert isinstance(all_categories, list)
161
- all_entries: list[tuple[str, str]] = []
162
- for each_category in all_categories:
163
- assert isinstance(each_category, dict)
164
- category_id = each_category[CATEGORY_ID_KEY]
165
- title = each_category[CATEGORY_TITLE_KEY]
166
- assert isinstance(category_id, str)
167
- assert isinstance(title, str)
168
- all_entries.append((category_id, title))
169
- return all_entries
170
-
171
-
172
- def render_skeleton_projections(all_schema: SchemaMapping) -> dict[str, str]:
173
- """Build deterministic skeleton text per category from the schema only.
174
-
175
- Args:
176
- all_schema: Loaded audit-category schema.
177
-
178
- Returns:
179
- Map of category letter to a stable multi-line skeleton projection.
180
- """
181
- projection_by_letter: dict[str, str] = {}
182
- all_categories = all_schema[SCHEMA_CATEGORIES_KEY]
183
- assert isinstance(all_categories, list)
184
- for each_category in all_categories:
185
- assert isinstance(each_category, dict)
186
- category_id = each_category[CATEGORY_ID_KEY]
187
- title = each_category[CATEGORY_TITLE_KEY]
188
- slug = each_category[CATEGORY_SLUG_KEY]
189
- all_sub_buckets = each_category[CATEGORY_SUB_BUCKETS_KEY]
190
- assert isinstance(category_id, str)
191
- assert isinstance(title, str)
192
- assert isinstance(slug, str)
193
- assert isinstance(all_sub_buckets, list)
194
- sub_bucket_count = len(all_sub_buckets)
195
- all_lines = [
196
- f"Category {category_id} — {title}",
197
- f"slug: {slug}",
198
- f"decomposed into {sub_bucket_count} sub-buckets",
199
- f"For each sub-bucket {category_id}1-{category_id}{sub_bucket_count}:",
200
- ]
201
- for each_sub_bucket in all_sub_buckets:
202
- assert isinstance(each_sub_bucket, dict)
203
- sub_bucket_id = each_sub_bucket[CATEGORY_ID_KEY]
204
- axis_name = each_sub_bucket[SUB_BUCKET_AXIS_KEY]
205
- all_lines.append(f"{sub_bucket_id}. {axis_name}")
206
- projection_by_letter[category_id] = NEWLINE.join(all_lines) + NEWLINE
207
- return projection_by_letter
208
-
209
-
210
- def _validate_one_category(each_category: CategoryMapping) -> list[str]:
211
- category_id = each_category[CATEGORY_ID_KEY]
212
- slug = each_category[CATEGORY_SLUG_KEY]
213
- title = each_category[CATEGORY_TITLE_KEY]
214
- all_sub_buckets = each_category[CATEGORY_SUB_BUCKETS_KEY]
215
- assert isinstance(category_id, str)
216
- assert isinstance(slug, str)
217
- assert isinstance(title, str)
218
- assert isinstance(all_sub_buckets, list)
219
- all_findings: list[str] = []
220
- rubric_path = CATEGORY_RUBRICS_DIRECTORY / f"{slug}.md"
221
- prompt_path = PROMPTS_DIRECTORY / f"{slug}.md"
222
- if not rubric_path.is_file():
223
- return [f"{category_id}: missing rubric {rubric_path.name}"]
224
- if not prompt_path.is_file():
225
- return [f"{category_id}: missing prompt {prompt_path.name}"]
226
- rubric_text = rubric_path.read_text(encoding=UTF8_ENCODING)
227
- all_rubric_lines = rubric_text.splitlines()
228
- if not all_rubric_lines:
229
- return [f"{category_id}: empty rubric"]
230
- heading_match = HEADING_PATTERN.match(all_rubric_lines[0])
231
- if heading_match is None:
232
- return [f"{category_id}: rubric heading does not match pattern"]
233
- heading_letter = heading_match.group(HEADING_LETTER_GROUP)
234
- heading_title = heading_match.group(HEADING_TITLE_GROUP)
235
- if heading_letter != category_id:
236
- all_findings.append(f"{category_id}: rubric heading letter {heading_letter!r}")
237
- if heading_title != title:
238
- all_findings.append(
239
- f"{category_id}: rubric title {heading_title!r} != schema {title!r}"
240
- )
241
- row_pattern = re.compile(
242
- RUBRIC_SUB_BUCKET_ROW_TEMPLATE.format(category_id=re.escape(category_id)),
243
- re.MULTILINE,
244
- )
245
- all_rubric_rows = row_pattern.findall(rubric_text)
246
- all_schema_rows: list[tuple[str, str]] = []
247
- for each_sub_bucket in all_sub_buckets:
248
- assert isinstance(each_sub_bucket, dict)
249
- sub_bucket_id = each_sub_bucket[CATEGORY_ID_KEY]
250
- axis_name = each_sub_bucket[SUB_BUCKET_AXIS_KEY]
251
- assert isinstance(sub_bucket_id, str)
252
- assert isinstance(axis_name, str)
253
- all_schema_rows.append((sub_bucket_id, axis_name))
254
- all_rubric_pairs = [(row_id, axis.strip()) for row_id, axis in all_rubric_rows]
255
- if all_rubric_pairs != all_schema_rows:
256
- all_findings.append(
257
- f"{category_id}: rubric sub-buckets {all_rubric_pairs!r} "
258
- f"!= schema {all_schema_rows!r}"
259
- )
260
- all_findings.extend(
261
- _validate_prompt_skeleton_count(category_id, prompt_path, len(all_sub_buckets))
262
- )
263
- return all_findings
264
-
265
-
266
- def _validate_prompt_skeleton_count(
267
- category_id: str,
268
- prompt_path: Path,
269
- sub_bucket_count: int,
270
- ) -> list[str]:
271
- prompt_text = prompt_path.read_text(encoding=UTF8_ENCODING)
272
- all_skeleton_lines: list[str] = []
273
- for each_line in prompt_text.splitlines():
274
- if each_line == SKELETON_SEPARATOR_LINE:
275
- break
276
- all_skeleton_lines.append(each_line)
277
- skeleton_text = NEWLINE.join(all_skeleton_lines)
278
- if SKELETON_PLACEHOLDER_FRAGMENT in skeleton_text:
279
- return [
280
- f"{category_id}: prompt skeleton still uses [N] placeholder; "
281
- f"use numeric count {sub_bucket_count}"
282
- ]
283
- count_match = SKELETON_COUNT_PATTERN.search(skeleton_text)
284
- if count_match is None:
285
- return [f"{category_id}: prompt skeleton missing sub-bucket count form"]
286
- skeleton_count = int(count_match.group(HEADING_LETTER_GROUP))
287
- if skeleton_count != sub_bucket_count:
288
- return [
289
- f"{category_id}: prompt skeleton count {skeleton_count} "
290
- f"!= schema {sub_bucket_count}"
291
- ]
292
- return []
293
-
294
-
295
- def validate_projections() -> list[str]:
296
- """Compare schema against on-disk rubric and prompt skeleton projections.
297
-
298
- Returns:
299
- Finding strings; empty when every category is in parity.
300
- """
301
- all_schema = load_audit_category_schema()
302
- all_categories = all_schema[SCHEMA_CATEGORIES_KEY]
303
- assert isinstance(all_categories, list)
304
- all_findings: list[str] = []
305
- for each_category in all_categories:
306
- assert isinstance(each_category, dict)
307
- all_findings.extend(_validate_one_category(each_category))
308
- return all_findings
309
-
310
-
311
- def main(all_argv: list[str]) -> int:
312
- """CLI: validate projections or print deterministic skeleton projections.
313
-
314
- Args:
315
- all_argv: Argument list without the program name.
316
-
317
- Returns:
318
- Process exit code (0 success, 1 validation findings).
319
- """
320
- parser = argparse.ArgumentParser(description=__doc__)
321
- parser.add_argument(
322
- "--validate",
323
- action="store_true",
324
- help="Validate rubric and prompt projections against the schema.",
325
- )
326
- parser.add_argument(
327
- "--render-skeletons",
328
- action="store_true",
329
- help="Print deterministic skeleton projections as JSON.",
330
- )
331
- arguments = parser.parse_args(all_argv)
332
- if arguments.validate:
333
- all_findings = validate_projections()
334
- if all_findings:
335
- for each_finding in all_findings:
336
- print(each_finding, file=sys.stderr)
337
- return 1
338
- print("OK")
339
- return 0
340
- if arguments.render_skeletons:
341
- all_schema = load_audit_category_schema()
342
- print(
343
- json.dumps(
344
- render_skeleton_projections(all_schema),
345
- indent=JSON_INDENT,
346
- ensure_ascii=False,
347
- )
348
- )
349
- return 0
350
- parser.print_help()
351
- return 0
352
-
353
-
354
- if __name__ == "__main__":
355
- raise SystemExit(main(sys.argv[1:]))
@@ -1,289 +0,0 @@
1
- """Emit the complete AUDIT spawn prompt XML to stdout.
2
-
3
- Builds <context> and <scope> from CLI args; <bug_categories>,
4
- <rubric_reference>, and <constraints> come from the shared constants in
5
- skills_pr_loop_constants; <comment_posting> and <output_format> follow
6
- ``--flavor`` (agent or headless). <pr_description> carries the PR body
7
- text read from --pr-body-file, and stays empty when that argument is
8
- absent or the file cannot be read.
9
-
10
- Usage:
11
- python scripts/build_audit_prompt.py --owner jl-cmd --repo claude-dev-env --pr-number 422 --loop 1 --head-ref feat/branch --base-ref main --worktree-path <PATH> --run-temp-dir <PATH> [--flavor agent|headless]
12
- """
13
-
14
- from __future__ import annotations
15
-
16
- import argparse
17
- import sys
18
- from xml.etree.ElementTree import Element, SubElement
19
- from pathlib import Path
20
-
21
- _self_dir = Path(__file__).resolve().parent
22
- if str(_self_dir) not in sys.path:
23
- sys.path.insert(0, str(_self_dir))
24
-
25
- from _path_resolver import outcome_xml_path
26
- from _xml_utils import emit_pretty_xml
27
- from skills_pr_loop_constants.path_resolver_constants import (
28
- ALL_AUDIT_CATEGORY_ENTRIES,
29
- ALL_AUDIT_CONSTRAINT_TEXTS,
30
- ALL_AUDIT_PROMPT_FLAVORS,
31
- AUDIT_COMMENT_POSTING_AGENT_TEXT,
32
- AUDIT_COMMENT_POSTING_HEADLESS_TEXT,
33
- AUDIT_OUTPUT_FORMAT_AGENT_TEXT,
34
- AUDIT_OUTPUT_FORMAT_HEADLESS_TEMPLATE,
35
- AUDIT_PROMPT_FLAVOR_AGENT,
36
- AUDIT_PROMPT_FLAVOR_HEADLESS,
37
- AUDIT_RUBRIC_REFERENCE_TEXT,
38
- )
39
-
40
-
41
- def read_pr_body_text(pr_body_file: Path | None) -> str | None:
42
- """Read the PR description body from a file when given and readable.
43
-
44
- Args:
45
- pr_body_file: Path to a file holding the PR description body, or None.
46
-
47
- Returns:
48
- The file's text when the path is given and readable, otherwise None.
49
- """
50
- if pr_body_file is None:
51
- return None
52
- try:
53
- return pr_body_file.read_text(encoding="utf-8")
54
- except OSError:
55
- return None
56
-
57
-
58
- def _append_pr_description(root: Element, pr_body_text: str | None) -> None:
59
- """Append a <pr_description> element carrying the PR body text.
60
-
61
- Args:
62
- root: Root element the <pr_description> child is appended to.
63
- pr_body_text: PR description body text, or None when unavailable.
64
-
65
- Returns:
66
- None.
67
- """
68
- pr_description = SubElement(root, "pr_description")
69
- if pr_body_text:
70
- pr_description.text = pr_body_text
71
-
72
-
73
- def _comment_posting_text(flavor: str) -> str:
74
- """Return the <comment_posting> body for the given prompt flavor.
75
-
76
- Args:
77
- flavor: ``agent`` or ``headless`` prompt flavor.
78
-
79
- Returns:
80
- Comment-posting instruction text for that flavor.
81
- """
82
- if flavor == AUDIT_PROMPT_FLAVOR_HEADLESS:
83
- return AUDIT_COMMENT_POSTING_HEADLESS_TEXT
84
- return AUDIT_COMMENT_POSTING_AGENT_TEXT
85
-
86
-
87
- def _format_instruction_text(
88
- *,
89
- flavor: str,
90
- worktree_path: Path,
91
- pr_number: int,
92
- loop: int,
93
- ) -> str:
94
- """Return the <output_format> body for the given prompt flavor.
95
-
96
- Args:
97
- flavor: ``agent`` or ``headless`` prompt flavor.
98
- worktree_path: Path to the git worktree.
99
- pr_number: Pull request number.
100
- loop: Loop iteration number.
101
-
102
- Returns:
103
- Format-instruction text for that flavor.
104
- """
105
- if flavor == AUDIT_PROMPT_FLAVOR_HEADLESS:
106
- outcome_path = outcome_xml_path(worktree_path, pr_number, loop)
107
- return AUDIT_OUTPUT_FORMAT_HEADLESS_TEMPLATE.format(
108
- outcome_path=outcome_path.as_posix(),
109
- )
110
- return AUDIT_OUTPUT_FORMAT_AGENT_TEXT
111
-
112
-
113
- def build_audit_prompt_xml(
114
- *,
115
- owner: str,
116
- repo: str,
117
- pr_number: int,
118
- loop: int,
119
- head_ref: str,
120
- base_ref: str,
121
- worktree_path: Path,
122
- run_temp_dir: Path,
123
- pr_body_text: str | None = None,
124
- flavor: str = AUDIT_PROMPT_FLAVOR_AGENT,
125
- ) -> Element:
126
- """Build the complete AUDIT spawn prompt XML.
127
-
128
- Args:
129
- owner: GitHub repository owner.
130
- repo: GitHub repository name.
131
- pr_number: Pull request number.
132
- loop: Loop iteration number.
133
- head_ref: Head branch ref.
134
- base_ref: Base branch ref.
135
- worktree_path: Path to the git worktree.
136
- run_temp_dir: Path to the run temp directory.
137
- pr_body_text: PR description body text, or None when unavailable.
138
- flavor: Prompt flavor — ``agent`` (MCP posting) or ``headless``
139
- (outcome file, lead-owned posting).
140
-
141
- Returns:
142
- Root <spawn_prompt> element.
143
- """
144
- root = Element("spawn_prompt", {"role": "audit", "loop": str(loop)})
145
-
146
- context = SubElement(root, "context")
147
- SubElement(context, "owner").text = owner
148
- SubElement(context, "repo").text = repo
149
- SubElement(context, "pr_number").text = str(pr_number)
150
- SubElement(context, "head_ref").text = head_ref
151
- SubElement(context, "base_ref").text = base_ref
152
- SubElement(context, "worktree_path").text = worktree_path.as_posix()
153
- SubElement(context, "run_temp_dir").text = run_temp_dir.as_posix()
154
-
155
- scope = SubElement(root, "scope")
156
- scope.text = (
157
- f"Audit the full diff of {owner}/{repo}#{pr_number} "
158
- f"({head_ref} against {base_ref}) for CODE_RULES violations, "
159
- f"bugs, and anti-patterns. Work in {worktree_path.as_posix()}."
160
- )
161
-
162
- _append_pr_description(root, pr_body_text)
163
-
164
- bug_categories = SubElement(root, "bug_categories")
165
- for each_category_id, each_category_label in ALL_AUDIT_CATEGORY_ENTRIES:
166
- cat_elem = SubElement(bug_categories, "category", {"id": each_category_id})
167
- cat_elem.text = each_category_label
168
-
169
- rubric_reference = SubElement(root, "rubric_reference")
170
- rubric_reference.text = AUDIT_RUBRIC_REFERENCE_TEXT
171
-
172
- constraints = SubElement(root, "constraints")
173
- for each_constraint in ALL_AUDIT_CONSTRAINT_TEXTS:
174
- SubElement(constraints, "constraint").text = each_constraint
175
-
176
- comment_posting = SubElement(root, "comment_posting")
177
- comment_posting.text = _comment_posting_text(flavor)
178
-
179
- format_section = SubElement(root, "output_format")
180
- format_section.text = _format_instruction_text(
181
- flavor=flavor,
182
- worktree_path=worktree_path,
183
- pr_number=pr_number,
184
- loop=loop,
185
- )
186
-
187
- return root
188
-
189
-
190
- def emit_audit_prompt(
191
- *,
192
- owner: str,
193
- repo: str,
194
- pr_number: int,
195
- loop: int,
196
- head_ref: str,
197
- base_ref: str,
198
- worktree_path: Path,
199
- run_temp_dir: Path,
200
- pr_body_text: str | None = None,
201
- flavor: str = AUDIT_PROMPT_FLAVOR_AGENT,
202
- ) -> str:
203
- """Build and serialize the AUDIT spawn prompt to a pretty-printed XML string.
204
-
205
- Args:
206
- owner: GitHub repository owner.
207
- repo: GitHub repository name.
208
- pr_number: Pull request number.
209
- loop: Loop iteration number.
210
- head_ref: Head branch ref.
211
- base_ref: Base branch ref.
212
- worktree_path: Path to the git worktree.
213
- run_temp_dir: Path to the run temp directory.
214
- pr_body_text: PR description body text, or None when unavailable.
215
- flavor: Prompt flavor — ``agent`` or ``headless``.
216
-
217
- Returns:
218
- Pretty-printed XML string.
219
- """
220
- root = build_audit_prompt_xml(
221
- owner=owner,
222
- repo=repo,
223
- pr_number=pr_number,
224
- loop=loop,
225
- head_ref=head_ref,
226
- base_ref=base_ref,
227
- worktree_path=worktree_path,
228
- run_temp_dir=run_temp_dir,
229
- pr_body_text=pr_body_text,
230
- flavor=flavor,
231
- )
232
- return emit_pretty_xml(root)
233
-
234
-
235
- def parse_arguments(all_argv: list[str]) -> argparse.Namespace:
236
- """Parse command-line arguments.
237
-
238
- Args:
239
- all_argv: Command-line argument list.
240
-
241
- Returns:
242
- Parsed namespace with all required audit prompt parameters.
243
- """
244
- parser = argparse.ArgumentParser(description=__doc__)
245
- parser.add_argument("--owner", required=True)
246
- parser.add_argument("--repo", required=True)
247
- parser.add_argument("--pr-number", type=int, required=True)
248
- parser.add_argument("--loop", type=int, required=True)
249
- parser.add_argument("--head-ref", required=True)
250
- parser.add_argument("--base-ref", required=True)
251
- parser.add_argument("--worktree-path", type=Path, required=True)
252
- parser.add_argument("--run-temp-dir", type=Path, required=True)
253
- parser.add_argument("--pr-body-file", type=Path, default=None)
254
- parser.add_argument(
255
- "--flavor",
256
- choices=sorted(ALL_AUDIT_PROMPT_FLAVORS),
257
- default=AUDIT_PROMPT_FLAVOR_AGENT,
258
- )
259
- return parser.parse_args(all_argv)
260
-
261
-
262
- def main(all_arguments: list[str]) -> int:
263
- """Entry point: emit AUDIT spawn prompt XML to stdout.
264
-
265
- Args:
266
- all_arguments: Command-line arguments.
267
-
268
- Returns:
269
- 0 on success.
270
- """
271
- arguments = parse_arguments(all_arguments)
272
- xml_output = emit_audit_prompt(
273
- owner=arguments.owner,
274
- repo=arguments.repo,
275
- pr_number=arguments.pr_number,
276
- loop=arguments.loop,
277
- head_ref=arguments.head_ref,
278
- base_ref=arguments.base_ref,
279
- worktree_path=arguments.worktree_path,
280
- run_temp_dir=arguments.run_temp_dir,
281
- pr_body_text=read_pr_body_text(arguments.pr_body_file),
282
- flavor=arguments.flavor,
283
- )
284
- sys.stdout.write(xml_output)
285
- return 0
286
-
287
-
288
- if __name__ == "__main__":
289
- raise SystemExit(main(sys.argv[1:]))