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,127 +0,0 @@
1
- # Stop conditions
2
-
3
- The workflow ends one of two ways: converged (PR marked ready) or blocked. A
4
- blocker exit returns `{ converged: false, rounds, finalSha, blocker }`, and the
5
- skill still runs teardown (revoke permissions, final report).
6
-
7
- ## Blockers (end the run short of ready)
8
-
9
- - **Budget stop** — on `pacer=workflow`, the workflow's `budget` API is the
10
- pacing signal: when a usage target is set, `converge.mjs` checks
11
- `budget.remaining()` before each round and stops at the round boundary when
12
- one full round (three parallel lenses + one fix commit + re-verify) does not
13
- fit. The run returns `blocker: "budget"` with the run id; resume with
14
- `Workflow({scriptPath, resumeFromRunId})` — completed rounds replay from the
15
- journal. The workflow never starts a round the budget cannot finish: a
16
- half-run round records nothing resumable and replays dirty. On
17
- `pacer=portable`, stop at a tick boundary when the session cannot cover a
18
- full clean tick; write handoff and resume with `/autoconverge <PR URL>`
19
- ([`../../_shared/pr-loop/portable-driver.md`](../../_shared/pr-loop/portable-driver.md)).
20
- - **Iteration cap** — 20 loop iterations pass without a full convergence-check
21
- pass. The iteration counter increments on every pass through any phase, so a
22
- convergence-check gate that no round can clear (for example a `mergeable_state`
23
- stuck at `blocked`, `behind`, or `unknown` that a rebase does not fix) and a
24
- Copilot gate agent that keeps dying and retrying on the same HEAD both reach
25
- the cap this way. `blocker` reports `iteration cap reached`.
26
- - **Fix stalled** — the fix lens reports no push (`pushed: false`) without
27
- resolving every finding thread, returns a SHA equal to the prior HEAD on a
28
- case-folded common prefix (a full or abbreviated SHA of the unchanged commit
29
- both count), or returns null for a round's findings. HEAD did not move and the
30
- threads were not all resolved, so the next round would re-raise the same
31
- findings. The run ends with a `blocker` that names the finding count and the
32
- stalled HEAD. A round whose every finding carries no GitHub thread
33
- (`replyToCommentId: null` on each) and whose fix reports
34
- `resolvedWithoutCommit: true` is also a stall: it moves no code and resolves no
35
- thread, so re-converging on the unchanged HEAD would loop the same finding to
36
- the iteration cap. The `blocker` names the in-memory finding count and the
37
- stalled HEAD. An all-stale round that makes no commit but resolves every
38
- finding thread (`resolvedWithoutCommit: true` with at least one thread-bearing
39
- finding) is not a stall — the run re-converges on the unchanged HEAD and
40
- reaches the terminal Bugbot, Copilot, Codex, and convergence gates.
41
- - **Static-sweep stalled** — the deterministic static sweep (`code_rules_gate.py
42
- --base origin/main`, `ruff`, `mypy`, stem-matched `pytest`) raises gate or test
43
- failures the fixer cannot clear on the current HEAD, so HEAD does not move. The
44
- reading lenses never run on a sweep-dirty HEAD, so the run ends with a
45
- static-sweep stall `blocker` naming the failure count and the stalled HEAD
46
- rather than looping to the iteration cap.
47
- - **Mark-ready failed** — the convergence check passes but the mark-ready step
48
- cannot confirm the PR left draft state (`gh pr ready` errored, or the draft
49
- re-query still reports true). The workflow does not report `converged: true`;
50
- the run ends with a `blocker` naming the failed ready transition.
51
- - **No review lens reviewed HEAD** — a round can end with no lens having reviewed
52
- the HEAD three ways: the preflight resolves no SHA, every lens agent dies, or
53
- every lens is down or disabled. A single such round retries on the next round.
54
- Three consecutive no-lens-reviewed rounds (any mix of the three causes) reach
55
- `CONFIG.maxConsecutiveNoLensRounds` and stop the run with a `blocker` that names
56
- the consecutive count and only the causes that actually occurred, rather than
57
- looping to the iteration cap. Any round in which at least one lens reviews the
58
- HEAD resets the consecutive count.
59
-
60
- ## Not a blocker (the run continues)
61
-
62
- Each reviewer-down condition below skips its own convergence-check gate. The flag and the matching `CLAUDE_REVIEWS_DISABLED` token for each condition are the single flag-per-condition table in [`../../skills-archived/reviewer-gates/SKILL.md`](../../skills-archived/reviewer-gates/SKILL.md) — "Convergence-check bypass flags"; the token carries the bypass into the mark-ready blocker hook's no-flag re-check.
63
-
64
- - **Clean-audit post bypassed** — every review lens is clean on HEAD, but the
65
- environment refuses the CLEAN bugteam review post (the `post_audit_thread.py`
66
- post is denied, errors, or its agent never runs). The lens results already show
67
- this HEAD is clean, so the CLEAN post is a record-keeping artifact, not the
68
- safety-bearing gate. The run records a `cleanAuditNote` naming the HEAD and the
69
- reason, logs the bypass, and proceeds to the terminal Bugbot gate — the same
70
- shape as the Bugbot-down and Copilot-down paths. The convergence check runs with
71
- `--bugteam-post-blocked` so its bugteam CLEAN-review gate is skipped and the run
72
- closes on the remaining signals. A round where no lens actually reviewed HEAD is
73
- separate: that re-converges under the no-review-lens rule above, since no lens
74
- grounded a post.
75
- - **Terminal Bugbot gate down or disabled** — the terminal Bugbot gate runs once
76
- the internal lenses are clean. When Cursor Bugbot is off for the run (the
77
- default unless `CLAUDE_REVIEWS_ENABLED` lists `bugbot`) or opted out via
78
- `CLAUDE_REVIEWS_DISABLED`, the gate spawns no agent and passes to the Copilot
79
- gate with `bugbotDown` set. When Bugbot is enabled but never produces a check
80
- run or review after the gate poll budget, the gate returns down the same way.
81
- The run continues, and the convergence check runs with `--bugbot-down` so its
82
- Bugbot gate is bypassed.
83
- - **Copilot down or out of quota** — when Copilot posts an out-of-usage notice on
84
- the current HEAD (the user who requested the review reached their quota limit)
85
- rather than a code review, or surfaces no review at all after the configured cap, the
86
- Copilot gate returns `down: true`. The run logs a notice, sets `copilotDown`,
87
- and proceeds to the Codex gate. The later convergence check receives
88
- `--copilot-down` (the Copilot review gate and the pending-requested-reviews
89
- gate bypassed), then mark-ready. `copilotNote` records the bypass for the
90
- final report.
91
- - **Terminal Codex gate skipped (no opt-in, opt-out, usage, or `codex_down`)** — the
92
- conditional-required Codex gate runs after Bugbot and Copilot. When
93
- `reviews_disabled.py --reviewer codex` exits 0 — which it does whenever
94
- `CLAUDE_REVIEWS_ENABLED` omits `codex`, the default, and whenever
95
- `CLAUDE_REVIEWS_DISABLED` lists it — the gate sets `codexDown` and advances
96
- with no review. When the weekly
97
- usage probe reports `percent_left` null or at/below the shared threshold
98
- (`is_codex_review_required` false), the gate skips without a stamp; the
99
- convergence check applies the same rule. When the codex-review wrapper
100
- classifies `codex_down` — a Codex CLI error, or a review that ran past its
101
- `CONFIG.codexReviewTimeoutSeconds` budget — the gate skips the same way: it sets
102
- `codexDown`, records a `codexNote` so the skip stays visible in the final
103
- report, clears `codexCleanAt`, and advances to `FINALIZE` (mark-ready with the
104
- gate bypassed) so a Codex outage does not block convergence; Codex runs again on
105
- the next convergence. A clean required run stamps `codexCleanAt` for
106
- `--codex-clean-at`. Non-code-standard findings re-enter `CONVERGE` through the
107
- existing fix path. Standards-only findings defer a follow-up, stamp
108
- `codexCleanAt`, and advance to `FINALIZE` (no fix push).
109
- - **A lens agent dies** — when one parallel reading lens returns null (a terminal
110
- agent failure), the round proceeds on the surviving lenses. A real defect it
111
- would have caught surfaces in a later round or at the convergence check. A dead
112
- terminal Bugbot gate agent (null result) is a retry rather than an approval, so
113
- the gate re-runs on the same HEAD rather than treating a dead agent as a clean
114
- Bugbot verdict.
115
- - **Every lens agent dies (a single round)** — when all three parallel reading
116
- lenses return null in the same round, the round is a failure, not a clean: the
117
- workflow posts no CLEAN bugteam artifact and does not advance to the terminal
118
- gates. It re-resolves HEAD and retries on the next round. This is a
119
- no-lens-reviewed round, so consecutive occurrences are bounded by the
120
- no-review-lens cap in the blockers above, not just the iteration cap.
121
-
122
- ## User stop
123
-
124
- Stopping the background workflow (`TaskStop`, or the user halting the run) ends
125
- it where it stands. Re-launching `/autoconverge` starts a fresh run; the
126
- workflow journal allows resuming the prior run from its last completed step with
127
- `Workflow({ scriptPath, resumeFromRunId })`.
@@ -1,54 +0,0 @@
1
- """Contract checks: autoconverge selects a portable pacer when Workflow is absent."""
2
-
3
- from __future__ import annotations
4
-
5
- import re
6
- from pathlib import Path
7
-
8
- SKILL_ROOT = Path(__file__).resolve().parent
9
- SKILL_MARKDOWN_PATH = SKILL_ROOT / "SKILL.md"
10
- MULTI_PR_MARKDOWN_PATH = SKILL_ROOT / "reference" / "multi-pr.md"
11
- PORTABLE_DRIVER_PATH = (
12
- SKILL_ROOT.parent / "_shared" / "pr-loop" / "portable-driver.md"
13
- )
14
-
15
- SELECT_CONVERGE_PACER_SCRIPT = "select_converge_pacer.py"
16
- PACER_PORTABLE_TOKEN = "pacer=portable"
17
- PACER_WORKFLOW_TOKEN = "pacer=workflow"
18
- ABORT_ONLY_PHRASE = "autoconverge requires the Workflow tool"
19
- PORTABLE_DRIVER_DOC = "portable-driver.md"
20
- PORTABLE_DRIVER_LINK_PATTERN = re.compile(
21
- r"\((?P<relative>(?:\.\./)+_shared/pr-loop/portable-driver\.md)\)"
22
- )
23
-
24
-
25
- def test_skill_selects_pacer_and_forbids_abort_only_workflow() -> None:
26
- skill_text = SKILL_MARKDOWN_PATH.read_text(encoding="utf-8")
27
- assert SELECT_CONVERGE_PACER_SCRIPT in skill_text
28
- assert PACER_PORTABLE_TOKEN in skill_text
29
- assert PACER_WORKFLOW_TOKEN in skill_text
30
- assert PORTABLE_DRIVER_DOC in skill_text
31
- assert ABORT_ONLY_PHRASE not in skill_text
32
-
33
-
34
- def test_skill_portable_driver_links_resolve_on_disk() -> None:
35
- skill_text = SKILL_MARKDOWN_PATH.read_text(encoding="utf-8")
36
- all_relative_links = PORTABLE_DRIVER_LINK_PATTERN.findall(skill_text)
37
- assert all_relative_links, "SKILL.md must link portable-driver.md"
38
- for each_relative_link in all_relative_links:
39
- resolved_path = (SKILL_MARKDOWN_PATH.parent / each_relative_link).resolve()
40
- assert resolved_path.is_file(), (
41
- f"portable-driver link must resolve on disk: "
42
- f"{each_relative_link} -> {resolved_path}"
43
- )
44
- assert resolved_path == PORTABLE_DRIVER_PATH.resolve()
45
-
46
-
47
- def test_multi_pr_documents_portable_launch_and_teardown() -> None:
48
- multi_pr_text = MULTI_PR_MARKDOWN_PATH.read_text(encoding="utf-8")
49
- assert PACER_PORTABLE_TOKEN in multi_pr_text
50
- assert "Do **not** call `Workflow`" in multi_pr_text or (
51
- "Do not call `Workflow`" in multi_pr_text
52
- )
53
- assert "pacer=portable" in multi_pr_text
54
- assert PORTABLE_DRIVER_DOC in multi_pr_text
@@ -1 +0,0 @@
1
- @../AGENTS.md
@@ -1,371 +0,0 @@
1
- """Merge every autoconverge run journal for one PR into a single combined journal."""
2
-
3
- import argparse
4
- import json
5
- import os
6
- import re
7
- import shutil
8
- import stat
9
- import sys
10
- from collections.abc import Callable
11
- from dataclasses import dataclass
12
- from pathlib import Path
13
- from typing import TextIO
14
-
15
- import convergence_summary
16
- import render_report
17
- from autoconverge_report_constants.render_report_constants import (
18
- ARGS_FIELD_OWNER,
19
- ARGS_FIELD_PR_NUMBER,
20
- ARGS_FIELD_REPO,
21
- COMBINED_RUN_ID_PREFIX,
22
- JOURNAL_FIELD_ARGS,
23
- JOURNAL_FIELD_RESULT,
24
- JOURNAL_FIELD_RUN_ID,
25
- JOURNAL_FIELD_TIMESTAMP,
26
- JOURNAL_FIELD_WORKFLOW_NAME,
27
- JOURNAL_FIELD_WORKFLOW_PROGRESS,
28
- JOURNAL_SIBLING_SUBAGENTS,
29
- JOURNAL_SIBLING_WORKFLOWS,
30
- LABEL_RESOLVE_HEAD,
31
- ONEXC_PYTHON_MAJOR_VERSION,
32
- ONEXC_PYTHON_MINOR_VERSION,
33
- PROGRESS_FIELD_AGENT_ID,
34
- PROGRESS_FIELD_LABEL,
35
- PROJECTS_DIR_NAME,
36
- RESULT_FIELD_FINAL_SHA,
37
- SUMMARY_DETAIL_MAX_CHARS,
38
- WORKFLOW_NAME_AUTOCONVERGE,
39
- )
40
-
41
-
42
- @dataclass(frozen=True)
43
- class AggregateResult:
44
- """The combined journal plus the aggregated inputs a closing report needs."""
45
-
46
- combined_journal_path: Path
47
- findings: list[dict]
48
- fix_summaries: list[str]
49
- round_count: int
50
- final_sha: str
51
-
52
-
53
- def _parse_args_object(journal: dict) -> dict:
54
- """Return the journal's args as a dict, parsing a JSON string when needed.
55
-
56
- Args:
57
- journal: A parsed run-journal object.
58
-
59
- Returns:
60
- The args object as a dict, or an empty dict when absent or unparseable.
61
- """
62
- raw_args = journal.get(JOURNAL_FIELD_ARGS, "")
63
- if isinstance(raw_args, dict):
64
- return raw_args
65
- try:
66
- parsed = json.loads(raw_args)
67
- except (ValueError, TypeError):
68
- return {}
69
- return parsed if isinstance(parsed, dict) else {}
70
-
71
-
72
- def _resolve_projects_root(seed_journal_path: Path) -> Path:
73
- """Return the projects directory that contains the seed run journal.
74
-
75
- Args:
76
- seed_journal_path: Path to one of the PR's wf_<runId>.json journals.
77
-
78
- Returns:
79
- The nearest ancestor directory named 'projects', or the seed's
80
- four-levels-up ancestor when no such ancestor exists.
81
- """
82
- for each_ancestor in seed_journal_path.parents:
83
- if each_ancestor.name == PROJECTS_DIR_NAME:
84
- return each_ancestor
85
- return seed_journal_path.parents[3]
86
-
87
-
88
- def _discover_pr_runs(
89
- projects_root: Path, owner: str, repo: str, pr_number: int
90
- ) -> list[tuple[Path, dict]]:
91
- """Return every autoconverge (journal path, journal) pair for the PR, oldest first.
92
-
93
- Args:
94
- projects_root: The projects directory holding all run trees.
95
- owner: The PR's repository owner.
96
- repo: The PR's repository name.
97
- pr_number: The PR number.
98
-
99
- Returns:
100
- A timestamp-sorted list of (journal path, parsed journal) pairs.
101
- """
102
- runs: list[tuple[Path, dict]] = []
103
- for each_journal_path in projects_root.glob("*/*/workflows/wf_*.json"):
104
- try:
105
- journal = json.loads(each_journal_path.read_text(encoding="utf-8"))
106
- except (ValueError, OSError):
107
- continue
108
- if journal.get(JOURNAL_FIELD_WORKFLOW_NAME) != WORKFLOW_NAME_AUTOCONVERGE:
109
- continue
110
- args_object = _parse_args_object(journal)
111
- matches_pr = (
112
- args_object.get(ARGS_FIELD_OWNER) == owner
113
- and args_object.get(ARGS_FIELD_REPO) == repo
114
- and args_object.get(ARGS_FIELD_PR_NUMBER) == pr_number
115
- )
116
- if matches_pr:
117
- runs.append((each_journal_path, journal))
118
- runs.sort(key=lambda pair: pair[1].get(JOURNAL_FIELD_TIMESTAMP, ""))
119
- return runs
120
-
121
-
122
- def discover_pr_journals(
123
- projects_root: Path, owner: str, repo: str, pr_number: int
124
- ) -> list[Path]:
125
- """Return every autoconverge journal path for the PR, oldest first.
126
-
127
- Args:
128
- projects_root: The projects directory holding all run trees.
129
- owner: The PR's repository owner.
130
- repo: The PR's repository name.
131
- pr_number: The PR number.
132
-
133
- Returns:
134
- A timestamp-sorted list of journal paths matching the PR.
135
- """
136
- return [
137
- path
138
- for path, _journal in _discover_pr_runs(projects_root, owner, repo, pr_number)
139
- ]
140
-
141
-
142
- def _retry_after_chmod(
143
- remove_func: Callable[[str], None], failing_path: str, *_exc_info: object
144
- ) -> None:
145
- """Clear the Windows read-only bit on a path, then retry the removal that failed.
146
-
147
- Args:
148
- remove_func: The os removal call rmtree was attempting when it failed.
149
- failing_path: The path the failed removal call could not delete.
150
- _exc_info: The exception or exc_info tuple the rmtree handler passes.
151
- """
152
- os.chmod(failing_path, stat.S_IWRITE)
153
- remove_func(failing_path)
154
-
155
-
156
- def _select_rmtree_handler_keyword() -> dict[str, Callable[..., None]]:
157
- """Return the rmtree retry-handler keyword argument for the running Python.
158
-
159
- Returns:
160
- A single-entry dict using the 'onexc' keyword on the Python versions that
161
- accept it and 'onerror' on the earlier versions that do not.
162
- """
163
- onexc_required_version = (ONEXC_PYTHON_MAJOR_VERSION, ONEXC_PYTHON_MINOR_VERSION)
164
- if sys.version_info >= onexc_required_version:
165
- return {"onexc": _retry_after_chmod}
166
- return {"onerror": _retry_after_chmod}
167
-
168
-
169
- def _force_remove(target_path: Path) -> None:
170
- """Remove a directory tree, clearing the Windows read-only bit on failure.
171
-
172
- Args:
173
- target_path: The directory tree to remove when it exists.
174
- """
175
- if not target_path.exists():
176
- return
177
- handler_keyword = _select_rmtree_handler_keyword()
178
- if "onexc" in handler_keyword:
179
- shutil.rmtree(target_path, onexc=_retry_after_chmod)
180
- return
181
- shutil.rmtree(target_path, onerror=_retry_after_chmod)
182
-
183
-
184
- def aggregate_pr_journals(
185
- seed_journal_path: Path, owner: str, repo: str, pr_number: int, work_dir: Path
186
- ) -> AggregateResult:
187
- """Merge every autoconverge journal for the PR into one combined journal.
188
-
189
- Args:
190
- seed_journal_path: One of the PR's run journals, used to locate the rest.
191
- owner: The PR's repository owner.
192
- repo: The PR's repository name.
193
- pr_number: The PR number.
194
- work_dir: A directory the combined run tree is written under.
195
-
196
- Returns:
197
- An AggregateResult carrying the combined journal path, the deduped
198
- findings, the fix summaries, the resolve-head round count, and the
199
- final commit sha drawn from the latest run's result.
200
- """
201
- projects_root = _resolve_projects_root(seed_journal_path)
202
- runs = _discover_pr_runs(projects_root, owner, repo, pr_number)
203
-
204
- combined_run_id = f"{COMBINED_RUN_ID_PREFIX}{pr_number}"
205
- dest_base = work_dir / combined_run_id
206
- _force_remove(dest_base)
207
- combined_workflows_dir = dest_base / JOURNAL_SIBLING_WORKFLOWS
208
- combined_workflows_dir.mkdir(parents=True)
209
- combined_agents_dir = (
210
- dest_base
211
- / JOURNAL_SIBLING_SUBAGENTS
212
- / JOURNAL_SIBLING_WORKFLOWS
213
- / combined_run_id
214
- )
215
- combined_agents_dir.mkdir(parents=True)
216
-
217
- combined_progress: list[dict] = []
218
- final_sha = ""
219
- latest_timestamp = ""
220
- for each_journal_path, each_journal in runs:
221
- source_agents_dir = (
222
- each_journal_path.parent.parent
223
- / JOURNAL_SIBLING_SUBAGENTS
224
- / JOURNAL_SIBLING_WORKFLOWS
225
- / each_journal_path.stem
226
- )
227
- for each_entry in each_journal.get(JOURNAL_FIELD_WORKFLOW_PROGRESS, []):
228
- agent_id = each_entry.get(PROGRESS_FIELD_AGENT_ID)
229
- if agent_id:
230
- source_transcript = source_agents_dir / f"agent-{agent_id}.jsonl"
231
- if source_transcript.exists():
232
- shutil.copy(
233
- source_transcript,
234
- combined_agents_dir / f"agent-{agent_id}.jsonl",
235
- )
236
- combined_progress.append(each_entry)
237
- result_block = each_journal.get(JOURNAL_FIELD_RESULT) or {}
238
- if result_block.get(RESULT_FIELD_FINAL_SHA):
239
- final_sha = result_block[RESULT_FIELD_FINAL_SHA]
240
- timestamp = each_journal.get(JOURNAL_FIELD_TIMESTAMP, "")
241
- if timestamp > latest_timestamp:
242
- latest_timestamp = timestamp
243
-
244
- round_count = sum(
245
- 1
246
- for each_entry in combined_progress
247
- if each_entry.get(PROGRESS_FIELD_LABEL) == LABEL_RESOLVE_HEAD
248
- )
249
- combined_journal = {
250
- JOURNAL_FIELD_RUN_ID: combined_run_id,
251
- JOURNAL_FIELD_TIMESTAMP: latest_timestamp,
252
- JOURNAL_FIELD_WORKFLOW_NAME: WORKFLOW_NAME_AUTOCONVERGE,
253
- JOURNAL_FIELD_ARGS: json.dumps(
254
- {
255
- ARGS_FIELD_OWNER: owner,
256
- ARGS_FIELD_REPO: repo,
257
- ARGS_FIELD_PR_NUMBER: pr_number,
258
- }
259
- ),
260
- JOURNAL_FIELD_RESULT: {RESULT_FIELD_FINAL_SHA: final_sha},
261
- JOURNAL_FIELD_WORKFLOW_PROGRESS: combined_progress,
262
- }
263
- combined_journal_path = combined_workflows_dir / f"{combined_run_id}.json"
264
- combined_journal_path.write_text(json.dumps(combined_journal), encoding="utf-8")
265
-
266
- run_data = render_report.load_run_data(combined_journal_path)
267
- findings = [
268
- {
269
- "severity": each_finding.severity,
270
- "category": each_finding.category,
271
- "file": each_finding.file,
272
- "line": each_finding.line,
273
- "title": each_finding.title,
274
- "detail": (each_finding.detail or "")[:SUMMARY_DETAIL_MAX_CHARS],
275
- }
276
- for each_finding in run_data.all_distinct_findings
277
- ]
278
- fix_summaries = [
279
- each_fix.summary
280
- for each_fix in run_data.fix_by_round.values()
281
- if each_fix.summary
282
- ]
283
- return AggregateResult(
284
- combined_journal_path=combined_journal_path,
285
- findings=findings,
286
- fix_summaries=fix_summaries,
287
- round_count=round_count,
288
- final_sha=final_sha,
289
- )
290
-
291
-
292
- def main(out_stream: TextIO = sys.stdout, err_stream: TextIO = sys.stderr) -> int:
293
- """Aggregate a PR's journals, write the summary prompt, print the combined facts.
294
-
295
- Args:
296
- out_stream: Stream the result JSON is written to on success.
297
- err_stream: Stream error messages are written to.
298
-
299
- Returns:
300
- Exit code (0 on success, 1 on argument error).
301
- """
302
- argument_parser = argparse.ArgumentParser(
303
- description="Aggregate every autoconverge journal for a PR into one journal."
304
- )
305
- argument_parser.add_argument(
306
- "--journal", required=True, help="Path to one of the PR's wf_<runId>.json files"
307
- )
308
- argument_parser.add_argument("--pr", required=True, help="owner/repo#number")
309
- argument_parser.add_argument(
310
- "--work-dir",
311
- required=True,
312
- help="Directory the combined run tree is written under",
313
- )
314
- argument_parser.add_argument(
315
- "--out-prompt",
316
- required=True,
317
- help="Path the summary agent prompt is written to",
318
- )
319
- argument_parser.add_argument(
320
- "--standards-note", default=None, help="Deferred code-standard note, when any"
321
- )
322
- argument_parser.add_argument(
323
- "--copilot-note", default=None, help="Copilot gate outage note, when any"
324
- )
325
- parsed_args = argument_parser.parse_args()
326
-
327
- pr_arg_pattern = r"(?P<owner>[^/]+)/(?P<repo>[^#]+)#(?P<number>\d+)"
328
- pr_match = re.fullmatch(pr_arg_pattern, parsed_args.pr)
329
- if pr_match is None:
330
- err_stream.write(
331
- f"Invalid --pr format: {parsed_args.pr!r}. Expected owner/repo#number.\n"
332
- )
333
- return 1
334
- owner = pr_match.group("owner")
335
- repo = pr_match.group("repo")
336
- pr_number = int(pr_match.group("number"))
337
-
338
- work_dir = Path(parsed_args.work_dir)
339
- work_dir.mkdir(parents=True, exist_ok=True)
340
- aggregation = aggregate_pr_journals(
341
- Path(parsed_args.journal).resolve(), owner, repo, pr_number, work_dir
342
- )
343
-
344
- prompt = convergence_summary.build_summary_prompt(
345
- owner,
346
- repo,
347
- pr_number,
348
- aggregation.round_count,
349
- aggregation.findings,
350
- aggregation.fix_summaries,
351
- parsed_args.standards_note,
352
- parsed_args.copilot_note,
353
- )
354
- Path(parsed_args.out_prompt).write_text(prompt, encoding="utf-8")
355
-
356
- out_stream.write(
357
- json.dumps(
358
- {
359
- "combinedJournal": str(aggregation.combined_journal_path),
360
- "roundCount": aggregation.round_count,
361
- "finalSha": aggregation.final_sha,
362
- "findingCount": len(aggregation.findings),
363
- }
364
- )
365
- + "\n"
366
- )
367
- return 0
368
-
369
-
370
- if __name__ == "__main__":
371
- sys.exit(main())