claude-dev-env 4.3.0 → 7.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (293) hide show
  1. package/.agents/agents/pr-description-writer.md +2 -2
  2. package/.agents/agents/test_agent_frontmatter.py +2 -2
  3. package/.agents/agents/test_pr_description_writer_style.py +1 -3
  4. package/.agents/skills/e-code-review/SKILL.md +12 -12
  5. package/.agents/skills/e-code-review/preflight-proposal.contract.test.mjs +20 -0
  6. package/.agents/skills/e-code-review/reference/fix.md +15 -17
  7. package/.agents/skills/e-code-review/reference/loop.md +35 -39
  8. package/.agents/skills/e-code-review/reference/mode-contract.test.mjs +2 -1
  9. package/.agents/skills/e-code-review/reference/preflight-proposal.md +44 -9
  10. package/.agents/skills/e-code-review/reference/runner-selection.md +13 -14
  11. package/.agents/skills/issue-tracker/SKILL.md +5 -4
  12. package/.agents/skills/pull-request/SKILL.md +11 -13
  13. package/.agents/skills/pull-request/reference/publication-tasks.md +3 -3
  14. package/.agents/skills/pull-request/scripts/github_pr_command_constants/config/constants.py +9 -1
  15. package/.agents/skills/pull-request/scripts/pull_request.py +33 -44
  16. package/.agents/skills/pull-request/scripts/test_github_pr_command_constants.py +9 -0
  17. package/.agents/skills/pull-request/scripts/test_pull_request.py +1 -3
  18. package/.agents/skills/skill-builder/SKILL.md +3 -196
  19. package/_shared/pr-loop/scripts/pr_loop_shared_constants/terminology_sweep_constants.py +6 -0
  20. package/_shared/pr-loop/scripts/terminology_sweep.py +64 -19
  21. package/_shared/pr-loop/scripts/tests/test_terminology_sweep.py +59 -0
  22. package/bin/install.agents-home.test.mjs +15 -13
  23. package/bin/install.mjs +28 -0
  24. package/bin/install.policy-lint.test.mjs +78 -0
  25. package/bin/install.prune.test.mjs +59 -20
  26. package/bin/install.pstack-plugin.test.mjs +114 -0
  27. package/bin/install.test.mjs +37 -0
  28. package/bin/refresh-pstack-plugin-skills.test.mjs +211 -0
  29. package/hooks/advisory/pr_done_reminder.py +342 -0
  30. package/hooks/advisory/test_pr_done_reminder.py +249 -0
  31. package/hooks/blocking/bash_post_call_dispatcher.py +53 -6
  32. package/hooks/blocking/code_rules_paired_test.py +22 -15
  33. package/hooks/blocking/test_bash_post_call_dispatcher.py +65 -4
  34. package/hooks/blocking/test_code_rules_enforcer_paired_test.py +36 -29
  35. package/hooks/blocking/test_code_rules_js_resume_task_enumeration.py +4 -4
  36. package/hooks/blocking/test_code_rules_js_returns_object_schemaless.py +5 -5
  37. package/hooks/blocking/test_pre_tool_use_dispatcher.py +68 -133
  38. package/hooks/blocking/test_pre_tool_use_dispatcher_native.py +20 -51
  39. package/hooks/blocking/test_precommit_code_rules_gate_native_owner.py +18 -18
  40. package/hooks/git-hooks/git_hooks_constants/staged_policy_lint.py +12 -0
  41. package/hooks/git-hooks/pre_commit.py +52 -11
  42. package/hooks/git-hooks/test_installed_policy_lint.py +159 -0
  43. package/hooks/git-hooks/test_native_policy_commit.py +87 -0
  44. package/hooks/git-hooks/test_pre_commit.py +246 -0
  45. package/hooks/hooks.json +1 -1
  46. package/hooks/hooks_constants/bash_post_call_dispatcher_constants.py +14 -1
  47. package/hooks/hooks_constants/pr_done_reminder_constants.py +98 -0
  48. package/hooks/hooks_constants/pre_tool_use_dispatcher_constants.py +10 -43
  49. package/hooks/hooks_constants/test_bash_post_call_dispatcher_constants.py +19 -2
  50. package/hooks/hooks_constants/test_pr_done_reminder_constants.py +40 -0
  51. package/hooks/hooks_constants/test_pre_tool_use_dispatcher_constants.py +20 -32
  52. package/package.json +2 -2
  53. package/rules/durable-post-artifacts.md +2 -1
  54. package/rules/git-workflow.md +6 -6
  55. package/scripts/check.ps1 +0 -1
  56. package/{.agents/skills/run-claude-dev-env/driver.mjs → scripts/ci/installer-lifecycle.mjs} +3 -28
  57. package/scripts/ci/installer-lifecycle.test.mjs +26 -0
  58. package/scripts/ci/windows-installer-lifecycle.ps1 +1 -11
  59. package/scripts/dev_env_scripts_constants/shared_tree_constants.py +4 -5
  60. package/{.agents/skills/_shared/pr-loop/scripts → scripts}/durable_post_lint.py +5 -41
  61. package/{.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/durable_post_lint_constants.py → scripts/durable_post_lint_config/config/constants.py} +0 -10
  62. package/{.agents/skills/_shared/pr-loop/scripts/test_durable_post_lint_constants.py → scripts/durable_post_lint_config/config/test_constants.py} +1 -1
  63. package/scripts/policy_lint/adapter_detectors.py +13 -6
  64. package/scripts/policy_lint/adapters.py +7 -4
  65. package/scripts/policy_lint/config/constants.py +5 -0
  66. package/scripts/policy_lint/engine.py +48 -4
  67. package/scripts/policy_lint/model.py +1 -0
  68. package/scripts/policy_lint/registry.py +1 -1
  69. package/scripts/policy_lint/selection.py +2 -1
  70. package/scripts/policy_lint/selection_git.py +2 -0
  71. package/scripts/refresh_pstack_plugin_skills.mjs +200 -0
  72. package/scripts/shared_tree_paths.py +32 -3
  73. package/scripts/test_shared_tree_paths.py +33 -0
  74. package/scripts/tests/test_policy_lint_rules_archive.py +120 -0
  75. package/scripts/tests/test_policy_lint_rules_engine.py +25 -4
  76. package/scripts/tests/test_policy_lint_rules_installed_loader.py +29 -0
  77. package/scripts/tests/test_policy_lint_rules_registry.py +227 -13
  78. package/scripts/tests/test_policy_lint_selection.py +25 -2
  79. package/scripts/tests/test_policy_lint_selection_native_index.py +30 -0
  80. package/scripts/tests/test_rules.py +3 -7
  81. package/.agents/skills/_shared/pr-loop/.claude/CLAUDE.md +0 -1
  82. package/.agents/skills/_shared/pr-loop/AGENTS.md +0 -1
  83. package/.agents/skills/_shared/pr-loop/audit-contract.md +0 -5
  84. package/.agents/skills/_shared/pr-loop/audit-reply-template.md +0 -5
  85. package/.agents/skills/_shared/pr-loop/code-rules-gate.md +0 -5
  86. package/.agents/skills/_shared/pr-loop/fix-protocol.md +0 -5
  87. package/.agents/skills/_shared/pr-loop/gh-payloads.md +0 -5
  88. package/.agents/skills/_shared/pr-loop/portable-driver.md +0 -149
  89. package/.agents/skills/_shared/pr-loop/post-audit-thread-contract.md +0 -5
  90. package/.agents/skills/_shared/pr-loop/precatch-rubric.md +0 -5
  91. package/.agents/skills/_shared/pr-loop/preflight-proposal.contract.test.mjs +0 -119
  92. package/.agents/skills/_shared/pr-loop/preflight-proposal.md +0 -5
  93. package/.agents/skills/_shared/pr-loop/prompts/.claude/CLAUDE.md +0 -1
  94. package/.agents/skills/_shared/pr-loop/prompts/AGENTS.md +0 -1
  95. package/.agents/skills/_shared/pr-loop/prompts/pr-consistency-audit.xml +0 -324
  96. package/.agents/skills/_shared/pr-loop/scripts/.claude/CLAUDE.md +0 -1
  97. package/.agents/skills/_shared/pr-loop/scripts/AGENTS.md +0 -1
  98. package/.agents/skills/_shared/pr-loop/scripts/RUNTIME_SCRIPTS.md +0 -29
  99. package/.agents/skills/_shared/pr-loop/scripts/_cli_utils.py +0 -22
  100. package/.agents/skills/_shared/pr-loop/scripts/_path_resolver.py +0 -186
  101. package/.agents/skills/_shared/pr-loop/scripts/_xml_utils.py +0 -20
  102. package/.agents/skills/_shared/pr-loop/scripts/audit_category_schema.py +0 -355
  103. package/.agents/skills/_shared/pr-loop/scripts/build_audit_prompt.py +0 -289
  104. package/.agents/skills/_shared/pr-loop/scripts/build_converge_task_list.py +0 -310
  105. package/.agents/skills/_shared/pr-loop/scripts/build_fix_prompt.py +0 -292
  106. package/.agents/skills/_shared/pr-loop/scripts/init_loop_state.py +0 -134
  107. package/.agents/skills/_shared/pr-loop/scripts/portable_converge_driver.py +0 -1646
  108. package/.agents/skills/_shared/pr-loop/scripts/preflight_worktree.py +0 -392
  109. package/.agents/skills/_shared/pr-loop/scripts/select_converge_pacer.py +0 -215
  110. package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/.claude/CLAUDE.md +0 -1
  111. package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/AGENTS.md +0 -1
  112. package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/__init__.py +0 -0
  113. package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/audit_category_schema_constants.py +0 -37
  114. package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/converge_task_list_constants.py +0 -56
  115. package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/handoff_constants.py +0 -45
  116. package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/pacer_constants.py +0 -47
  117. package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/path_resolver_constants.py +0 -157
  118. package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/portable_driver_constants.py +0 -177
  119. package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/preflight_constants.py +0 -70
  120. package/.agents/skills/_shared/pr-loop/scripts/teardown_worktrees.py +0 -172
  121. package/.agents/skills/_shared/pr-loop/scripts/test__path_resolver.py +0 -106
  122. package/.agents/skills/_shared/pr-loop/scripts/test_audit_category_schema.py +0 -94
  123. package/.agents/skills/_shared/pr-loop/scripts/test_build_audit_prompt.py +0 -499
  124. package/.agents/skills/_shared/pr-loop/scripts/test_build_converge_task_list.py +0 -140
  125. package/.agents/skills/_shared/pr-loop/scripts/test_build_fix_prompt.py +0 -262
  126. package/.agents/skills/_shared/pr-loop/scripts/test_init_loop_state.py +0 -71
  127. package/.agents/skills/_shared/pr-loop/scripts/test_portable_converge_driver.py +0 -1119
  128. package/.agents/skills/_shared/pr-loop/scripts/test_preflight_worktree.py +0 -287
  129. package/.agents/skills/_shared/pr-loop/scripts/test_select_converge_pacer.py +0 -207
  130. package/.agents/skills/_shared/pr-loop/scripts/test_teardown_worktrees.py +0 -59
  131. package/.agents/skills/_shared/pr-loop/scripts/test_write_handoff.py +0 -201
  132. package/.agents/skills/_shared/pr-loop/scripts/write_audit_outcomes.py +0 -182
  133. package/.agents/skills/_shared/pr-loop/scripts/write_fix_outcomes.py +0 -206
  134. package/.agents/skills/_shared/pr-loop/scripts/write_handoff.py +0 -309
  135. package/.agents/skills/_shared/pr-loop/state-schema.md +0 -5
  136. package/.agents/skills/_shared/pr-loop/worker-spawn.md +0 -5
  137. package/.agents/skills/autoconverge/.claude/CLAUDE.md +0 -1
  138. package/.agents/skills/autoconverge/AGENTS.md +0 -1
  139. package/.agents/skills/autoconverge/SKILL.md +0 -431
  140. package/.agents/skills/autoconverge/reference/.claude/CLAUDE.md +0 -1
  141. package/.agents/skills/autoconverge/reference/AGENTS.md +0 -1
  142. package/.agents/skills/autoconverge/reference/closing-report.md +0 -93
  143. package/.agents/skills/autoconverge/reference/convergence-gates.md +0 -31
  144. package/.agents/skills/autoconverge/reference/convergence.md +0 -219
  145. package/.agents/skills/autoconverge/reference/copilot-findings.md +0 -51
  146. package/.agents/skills/autoconverge/reference/gotchas.md +0 -66
  147. package/.agents/skills/autoconverge/reference/headless-safety.md +0 -44
  148. package/.agents/skills/autoconverge/reference/multi-pr.md +0 -128
  149. package/.agents/skills/autoconverge/reference/self-closing-loop.md +0 -84
  150. package/.agents/skills/autoconverge/reference/stop-conditions.md +0 -127
  151. package/.agents/skills/autoconverge/test_portable_pacer_gate.py +0 -54
  152. package/.agents/skills/autoconverge/workflow/.claude/CLAUDE.md +0 -1
  153. package/.agents/skills/autoconverge/workflow/AGENTS.md +0 -1
  154. package/.agents/skills/autoconverge/workflow/aggregate_runs.py +0 -371
  155. package/.agents/skills/autoconverge/workflow/autoconverge_report_constants/.claude/CLAUDE.md +0 -1
  156. package/.agents/skills/autoconverge/workflow/autoconverge_report_constants/AGENTS.md +0 -1
  157. package/.agents/skills/autoconverge/workflow/autoconverge_report_constants/__init__.py +0 -0
  158. package/.agents/skills/autoconverge/workflow/autoconverge_report_constants/render_report_constants.py +0 -250
  159. package/.agents/skills/autoconverge/workflow/converge.clean-audit.test.mjs +0 -665
  160. package/.agents/skills/autoconverge/workflow/converge.codex-gate.test.mjs +0 -472
  161. package/.agents/skills/autoconverge/workflow/converge.contract.test.mjs +0 -64
  162. package/.agents/skills/autoconverge/workflow/converge.copilot-gate.test.mjs +0 -1009
  163. package/.agents/skills/autoconverge/workflow/converge.fix-progress.test.mjs +0 -107
  164. package/.agents/skills/autoconverge/workflow/converge.fix-recovery.test.mjs +0 -33
  165. package/.agents/skills/autoconverge/workflow/converge.merge-conflict.test.mjs +0 -15
  166. package/.agents/skills/autoconverge/workflow/converge.mjs +0 -3132
  167. package/.agents/skills/autoconverge/workflow/converge.p2-advance.test.mjs +0 -202
  168. package/.agents/skills/autoconverge/workflow/converge.path-aware.test.mjs +0 -47
  169. package/.agents/skills/autoconverge/workflow/converge.precatch.test.mjs +0 -152
  170. package/.agents/skills/autoconverge/workflow/converge.run-input.test.mjs +0 -116
  171. package/.agents/skills/autoconverge/workflow/converge_multi.mjs +0 -169
  172. package/.agents/skills/autoconverge/workflow/converge_multi.run-input.test.mjs +0 -173
  173. package/.agents/skills/autoconverge/workflow/convergence_summary.py +0 -110
  174. package/.agents/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a11d903476b803493.jsonl +0 -2
  175. package/.agents/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a26213978adeef6fb.jsonl +0 -2
  176. package/.agents/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a3def0d15ed9d9110.jsonl +0 -2
  177. package/.agents/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a41f41b1b708ee3b7.jsonl +0 -2
  178. package/.agents/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a758b880abecc3ff7.jsonl +0 -2
  179. package/.agents/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a8897b89656b1bd16.jsonl +0 -2
  180. package/.agents/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-ab1c2d3e4f5a6b7c8.jsonl +0 -2
  181. package/.agents/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-abd463d744a1437bc.jsonl +0 -2
  182. package/.agents/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-ad19d027ae8ee1816.jsonl +0 -2
  183. package/.agents/skills/autoconverge/workflow/fixtures/wf_run/workflows/wf_881252e6-700.json +0 -266
  184. package/.agents/skills/autoconverge/workflow/render_report.py +0 -1024
  185. package/.agents/skills/autoconverge/workflow/test_aggregate_runs.py +0 -134
  186. package/.agents/skills/autoconverge/workflow/test_convergence_summary.py +0 -149
  187. package/.agents/skills/autoconverge/workflow/test_render_report.py +0 -812
  188. package/.agents/skills/hitl/SKILL.md +0 -45
  189. package/.agents/skills/pr-cleanup/SKILL.md +0 -140
  190. package/.agents/skills/pr-cleanup/reference/process-inventory.md +0 -17
  191. package/.agents/skills/pr-cleanup/reference/task-seeds.md +0 -22
  192. package/.agents/skills/pr-name-by-capability/SKILL.md +0 -73
  193. package/.agents/skills/pr-name-by-capability/reference/fetch-commands.md +0 -29
  194. package/.agents/skills/pr-name-by-capability/reference/offense-examples.md +0 -32
  195. package/.agents/skills/pr-name-by-capability/reference/report-template.md +0 -29
  196. package/.agents/skills/pr-name-by-capability/reference/rule-checklist.md +0 -38
  197. package/.agents/skills/pr-name-by-capability/reference/task-seeds.md +0 -10
  198. package/.agents/skills/pr-plain-language-cleanup/SKILL.md +0 -93
  199. package/.agents/skills/pr-refinement/SKILL.md +0 -31
  200. package/.agents/skills/pr-shared-extraction/SKILL.md +0 -177
  201. package/.agents/skills/pr-shared-extraction/reference/examples.md +0 -46
  202. package/.agents/skills/pr-shared-extraction/reference/offense-taxonomy.md +0 -100
  203. package/.agents/skills/pr-small-cl/SKILL.md +0 -52
  204. package/.agents/skills/pr-title-description/SKILL.md +0 -96
  205. package/.agents/skills/prototype/SKILL.md +0 -85
  206. package/.agents/skills/prototype/reference/honest-limitations.md +0 -23
  207. package/.agents/skills/prototype/reference/promotion-tasks.md +0 -23
  208. package/.agents/skills/prototype/scripts/build_sandbox_settings.py +0 -249
  209. package/.agents/skills/prototype/scripts/conftest.py +0 -15
  210. package/.agents/skills/prototype/scripts/launch_sandbox.py +0 -205
  211. package/.agents/skills/prototype/scripts/probe_sandbox_safety.py +0 -311
  212. package/.agents/skills/prototype/scripts/prototype_scripts_constants/__init__.py +0 -1
  213. package/.agents/skills/prototype/scripts/prototype_scripts_constants/config/__init__.py +0 -0
  214. package/.agents/skills/prototype/scripts/prototype_scripts_constants/config/build_sandbox_settings_constants.py +0 -41
  215. package/.agents/skills/prototype/scripts/prototype_scripts_constants/config/launch_sandbox_constants.py +0 -23
  216. package/.agents/skills/prototype/scripts/prototype_scripts_constants/config/probe_sandbox_safety_constants.py +0 -45
  217. package/.agents/skills/prototype/scripts/prototype_scripts_constants/config/prototype_common_constants.py +0 -10
  218. package/.agents/skills/prototype/scripts/test_build_sandbox_settings.py +0 -275
  219. package/.agents/skills/prototype/scripts/test_launch_sandbox.py +0 -303
  220. package/.agents/skills/prototype/scripts/test_probe_sandbox_safety.py +0 -312
  221. package/.agents/skills/prototype/workflows/promotion.md +0 -25
  222. package/.agents/skills/prototype/workflows/sandbox.md +0 -35
  223. package/.agents/skills/rebase/.claude/CLAUDE.md +0 -1
  224. package/.agents/skills/rebase/AGENTS.md +0 -1
  225. package/.agents/skills/rebase/SKILL.md +0 -178
  226. package/.agents/skills/review-router/SKILL.md +0 -51
  227. package/.agents/skills/review-router/reference/route-policy.json +0 -7
  228. package/.agents/skills/review-router/reference/task-seeds.md +0 -1
  229. package/.agents/skills/review-router/scripts/conftest.py +0 -4
  230. package/.agents/skills/review-router/scripts/review_router.py +0 -50
  231. package/.agents/skills/review-router/scripts/review_router_cli.py +0 -211
  232. package/.agents/skills/review-router/scripts/review_router_constants/__init__.py +0 -1
  233. package/.agents/skills/review-router/scripts/review_router_constants/config/__init__.py +0 -0
  234. package/.agents/skills/review-router/scripts/review_router_constants/config/constants.py +0 -13
  235. package/.agents/skills/review-router/scripts/test_review_router.py +0 -23
  236. package/.agents/skills/review-router/scripts/test_review_router_cli.py +0 -47
  237. package/.agents/skills/review-tier/SKILL.md +0 -56
  238. package/.agents/skills/review-tier/reference/task-seeds.md +0 -1
  239. package/.agents/skills/review-tier/reference/tier-policy.json +0 -9
  240. package/.agents/skills/review-tier/scripts/conftest.py +0 -4
  241. package/.agents/skills/review-tier/scripts/review_tier.py +0 -359
  242. package/.agents/skills/review-tier/scripts/review_tier_constants/__init__.py +0 -1
  243. package/.agents/skills/review-tier/scripts/review_tier_constants/config/__init__.py +0 -0
  244. package/.agents/skills/review-tier/scripts/review_tier_constants/config/constants.py +0 -29
  245. package/.agents/skills/review-tier/scripts/test_generation.py +0 -159
  246. package/.agents/skills/review-tier/scripts/test_review_tier.py +0 -33
  247. package/.agents/skills/run-claude-dev-env/SKILL.md +0 -84
  248. package/.agents/skills/session-log/.claude/CLAUDE.md +0 -1
  249. package/.agents/skills/session-log/AGENTS.md +0 -1
  250. package/.agents/skills/session-log/SKILL.md +0 -170
  251. package/.agents/skills/session-log/templates/frontmatter.md +0 -40
  252. package/.agents/skills/session-tidy/.claude/CLAUDE.md +0 -1
  253. package/.agents/skills/session-tidy/AGENTS.md +0 -1
  254. package/.agents/skills/session-tidy/SKILL.md +0 -191
  255. package/.agents/skills/skill-builder/references/.claude/CLAUDE.md +0 -1
  256. package/.agents/skills/skill-builder/references/AGENTS.md +0 -1
  257. package/.agents/skills/skill-builder/references/delegation-map.md +0 -130
  258. package/.agents/skills/skill-builder/references/description-field.md +0 -111
  259. package/.agents/skills/skill-builder/references/deterministic-elements.md +0 -218
  260. package/.agents/skills/skill-builder/references/progressive-disclosure.md +0 -122
  261. package/.agents/skills/skill-builder/references/self-audit-checklist.md +0 -126
  262. package/.agents/skills/skill-builder/references/skill-modularity.md +0 -111
  263. package/.agents/skills/skill-builder/references/skill-types.md +0 -232
  264. package/.agents/skills/skill-builder/references/thariq-x-post-skills.json +0 -33
  265. package/.agents/skills/skill-builder/templates/.claude/CLAUDE.md +0 -1
  266. package/.agents/skills/skill-builder/templates/AGENTS.md +0 -1
  267. package/.agents/skills/skill-builder/templates/gap-analysis.md +0 -87
  268. package/.agents/skills/skill-builder/workflows/.claude/CLAUDE.md +0 -1
  269. package/.agents/skills/skill-builder/workflows/AGENTS.md +0 -1
  270. package/.agents/skills/skill-builder/workflows/improve-skill.md +0 -136
  271. package/.agents/skills/skill-builder/workflows/new-skill.md +0 -179
  272. package/.agents/skills/skill-builder/workflows/polish-skill.md +0 -139
  273. package/.agents/skills/source-command-sr-loop/SKILL.md +0 -82
  274. package/.agents/skills/update/.claude/CLAUDE.md +0 -1
  275. package/.agents/skills/update/AGENTS.md +0 -1
  276. package/.agents/skills/update/SKILL.md +0 -190
  277. package/_shared/pr-loop/AGENTS.md +0 -1
  278. package/_shared/pr-loop/CLAUDE.md +0 -1
  279. package/_shared/pr-loop/audit-contract.md +0 -183
  280. package/_shared/pr-loop/audit-reply-template.md +0 -151
  281. package/_shared/pr-loop/code-rules-gate.md +0 -65
  282. package/_shared/pr-loop/fix-protocol.md +0 -60
  283. package/_shared/pr-loop/gh-payloads.md +0 -75
  284. package/_shared/pr-loop/post-audit-thread-contract.md +0 -51
  285. package/_shared/pr-loop/precatch-rubric.md +0 -66
  286. package/_shared/pr-loop/preflight-proposal.md +0 -56
  287. package/_shared/pr-loop/scripts/post_audit_thread.py +0 -1242
  288. package/_shared/pr-loop/scripts/pr_loop_shared_constants/post_audit_thread_constants.py +0 -199
  289. package/_shared/pr-loop/scripts/tests/test_post_audit_thread.py +0 -1115
  290. package/_shared/pr-loop/scripts/tests/test_post_audit_thread_constants.py +0 -129
  291. package/_shared/pr-loop/state-schema.md +0 -45
  292. package/_shared/pr-loop/worker-spawn.md +0 -189
  293. /package/{.agents/skills/_shared/pr-loop/scripts → scripts}/test_durable_post_lint.py +0 -0
@@ -1,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())