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.
- package/.agents/agents/pr-description-writer.md +2 -2
- package/.agents/agents/test_agent_frontmatter.py +2 -2
- package/.agents/agents/test_pr_description_writer_style.py +1 -3
- package/.agents/skills/e-code-review/SKILL.md +12 -12
- package/.agents/skills/e-code-review/preflight-proposal.contract.test.mjs +20 -0
- package/.agents/skills/e-code-review/reference/fix.md +15 -17
- package/.agents/skills/e-code-review/reference/loop.md +35 -39
- package/.agents/skills/e-code-review/reference/mode-contract.test.mjs +2 -1
- package/.agents/skills/e-code-review/reference/preflight-proposal.md +44 -9
- package/.agents/skills/e-code-review/reference/runner-selection.md +13 -14
- package/.agents/skills/issue-tracker/SKILL.md +5 -4
- package/.agents/skills/pull-request/SKILL.md +11 -13
- package/.agents/skills/pull-request/reference/publication-tasks.md +3 -3
- package/.agents/skills/pull-request/scripts/github_pr_command_constants/config/constants.py +9 -1
- package/.agents/skills/pull-request/scripts/pull_request.py +33 -44
- package/.agents/skills/pull-request/scripts/test_github_pr_command_constants.py +9 -0
- package/.agents/skills/pull-request/scripts/test_pull_request.py +1 -3
- package/.agents/skills/skill-builder/SKILL.md +3 -196
- package/_shared/pr-loop/scripts/pr_loop_shared_constants/terminology_sweep_constants.py +6 -0
- package/_shared/pr-loop/scripts/terminology_sweep.py +64 -19
- package/_shared/pr-loop/scripts/tests/test_terminology_sweep.py +59 -0
- package/bin/install.agents-home.test.mjs +15 -13
- package/bin/install.mjs +28 -0
- package/bin/install.policy-lint.test.mjs +78 -0
- package/bin/install.prune.test.mjs +59 -20
- package/bin/install.pstack-plugin.test.mjs +114 -0
- package/bin/install.test.mjs +37 -0
- package/bin/refresh-pstack-plugin-skills.test.mjs +211 -0
- package/hooks/advisory/pr_done_reminder.py +342 -0
- package/hooks/advisory/test_pr_done_reminder.py +249 -0
- package/hooks/blocking/bash_post_call_dispatcher.py +53 -6
- package/hooks/blocking/code_rules_paired_test.py +22 -15
- package/hooks/blocking/test_bash_post_call_dispatcher.py +65 -4
- package/hooks/blocking/test_code_rules_enforcer_paired_test.py +36 -29
- package/hooks/blocking/test_code_rules_js_resume_task_enumeration.py +4 -4
- package/hooks/blocking/test_code_rules_js_returns_object_schemaless.py +5 -5
- package/hooks/blocking/test_pre_tool_use_dispatcher.py +68 -133
- package/hooks/blocking/test_pre_tool_use_dispatcher_native.py +20 -51
- package/hooks/blocking/test_precommit_code_rules_gate_native_owner.py +18 -18
- package/hooks/git-hooks/git_hooks_constants/staged_policy_lint.py +12 -0
- package/hooks/git-hooks/pre_commit.py +52 -11
- package/hooks/git-hooks/test_installed_policy_lint.py +159 -0
- package/hooks/git-hooks/test_native_policy_commit.py +87 -0
- package/hooks/git-hooks/test_pre_commit.py +246 -0
- package/hooks/hooks.json +1 -1
- package/hooks/hooks_constants/bash_post_call_dispatcher_constants.py +14 -1
- package/hooks/hooks_constants/pr_done_reminder_constants.py +98 -0
- package/hooks/hooks_constants/pre_tool_use_dispatcher_constants.py +10 -43
- package/hooks/hooks_constants/test_bash_post_call_dispatcher_constants.py +19 -2
- package/hooks/hooks_constants/test_pr_done_reminder_constants.py +40 -0
- package/hooks/hooks_constants/test_pre_tool_use_dispatcher_constants.py +20 -32
- package/package.json +2 -2
- package/rules/durable-post-artifacts.md +2 -1
- package/rules/git-workflow.md +6 -6
- package/scripts/check.ps1 +0 -1
- package/{.agents/skills/run-claude-dev-env/driver.mjs → scripts/ci/installer-lifecycle.mjs} +3 -28
- package/scripts/ci/installer-lifecycle.test.mjs +26 -0
- package/scripts/ci/windows-installer-lifecycle.ps1 +1 -11
- package/scripts/dev_env_scripts_constants/shared_tree_constants.py +4 -5
- package/{.agents/skills/_shared/pr-loop/scripts → scripts}/durable_post_lint.py +5 -41
- 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
- package/{.agents/skills/_shared/pr-loop/scripts/test_durable_post_lint_constants.py → scripts/durable_post_lint_config/config/test_constants.py} +1 -1
- package/scripts/policy_lint/adapter_detectors.py +13 -6
- package/scripts/policy_lint/adapters.py +7 -4
- package/scripts/policy_lint/config/constants.py +5 -0
- package/scripts/policy_lint/engine.py +48 -4
- package/scripts/policy_lint/model.py +1 -0
- package/scripts/policy_lint/registry.py +1 -1
- package/scripts/policy_lint/selection.py +2 -1
- package/scripts/policy_lint/selection_git.py +2 -0
- package/scripts/refresh_pstack_plugin_skills.mjs +200 -0
- package/scripts/shared_tree_paths.py +32 -3
- package/scripts/test_shared_tree_paths.py +33 -0
- package/scripts/tests/test_policy_lint_rules_archive.py +120 -0
- package/scripts/tests/test_policy_lint_rules_engine.py +25 -4
- package/scripts/tests/test_policy_lint_rules_installed_loader.py +29 -0
- package/scripts/tests/test_policy_lint_rules_registry.py +227 -13
- package/scripts/tests/test_policy_lint_selection.py +25 -2
- package/scripts/tests/test_policy_lint_selection_native_index.py +30 -0
- package/scripts/tests/test_rules.py +3 -7
- package/.agents/skills/_shared/pr-loop/.claude/CLAUDE.md +0 -1
- package/.agents/skills/_shared/pr-loop/AGENTS.md +0 -1
- package/.agents/skills/_shared/pr-loop/audit-contract.md +0 -5
- package/.agents/skills/_shared/pr-loop/audit-reply-template.md +0 -5
- package/.agents/skills/_shared/pr-loop/code-rules-gate.md +0 -5
- package/.agents/skills/_shared/pr-loop/fix-protocol.md +0 -5
- package/.agents/skills/_shared/pr-loop/gh-payloads.md +0 -5
- package/.agents/skills/_shared/pr-loop/portable-driver.md +0 -149
- package/.agents/skills/_shared/pr-loop/post-audit-thread-contract.md +0 -5
- package/.agents/skills/_shared/pr-loop/precatch-rubric.md +0 -5
- package/.agents/skills/_shared/pr-loop/preflight-proposal.contract.test.mjs +0 -119
- package/.agents/skills/_shared/pr-loop/preflight-proposal.md +0 -5
- package/.agents/skills/_shared/pr-loop/prompts/.claude/CLAUDE.md +0 -1
- package/.agents/skills/_shared/pr-loop/prompts/AGENTS.md +0 -1
- package/.agents/skills/_shared/pr-loop/prompts/pr-consistency-audit.xml +0 -324
- package/.agents/skills/_shared/pr-loop/scripts/.claude/CLAUDE.md +0 -1
- package/.agents/skills/_shared/pr-loop/scripts/AGENTS.md +0 -1
- package/.agents/skills/_shared/pr-loop/scripts/RUNTIME_SCRIPTS.md +0 -29
- package/.agents/skills/_shared/pr-loop/scripts/_cli_utils.py +0 -22
- package/.agents/skills/_shared/pr-loop/scripts/_path_resolver.py +0 -186
- package/.agents/skills/_shared/pr-loop/scripts/_xml_utils.py +0 -20
- package/.agents/skills/_shared/pr-loop/scripts/audit_category_schema.py +0 -355
- package/.agents/skills/_shared/pr-loop/scripts/build_audit_prompt.py +0 -289
- package/.agents/skills/_shared/pr-loop/scripts/build_converge_task_list.py +0 -310
- package/.agents/skills/_shared/pr-loop/scripts/build_fix_prompt.py +0 -292
- package/.agents/skills/_shared/pr-loop/scripts/init_loop_state.py +0 -134
- package/.agents/skills/_shared/pr-loop/scripts/portable_converge_driver.py +0 -1646
- package/.agents/skills/_shared/pr-loop/scripts/preflight_worktree.py +0 -392
- package/.agents/skills/_shared/pr-loop/scripts/select_converge_pacer.py +0 -215
- package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/.claude/CLAUDE.md +0 -1
- package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/AGENTS.md +0 -1
- package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/__init__.py +0 -0
- package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/audit_category_schema_constants.py +0 -37
- package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/converge_task_list_constants.py +0 -56
- package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/handoff_constants.py +0 -45
- package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/pacer_constants.py +0 -47
- package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/path_resolver_constants.py +0 -157
- package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/portable_driver_constants.py +0 -177
- package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/preflight_constants.py +0 -70
- package/.agents/skills/_shared/pr-loop/scripts/teardown_worktrees.py +0 -172
- package/.agents/skills/_shared/pr-loop/scripts/test__path_resolver.py +0 -106
- package/.agents/skills/_shared/pr-loop/scripts/test_audit_category_schema.py +0 -94
- package/.agents/skills/_shared/pr-loop/scripts/test_build_audit_prompt.py +0 -499
- package/.agents/skills/_shared/pr-loop/scripts/test_build_converge_task_list.py +0 -140
- package/.agents/skills/_shared/pr-loop/scripts/test_build_fix_prompt.py +0 -262
- package/.agents/skills/_shared/pr-loop/scripts/test_init_loop_state.py +0 -71
- package/.agents/skills/_shared/pr-loop/scripts/test_portable_converge_driver.py +0 -1119
- package/.agents/skills/_shared/pr-loop/scripts/test_preflight_worktree.py +0 -287
- package/.agents/skills/_shared/pr-loop/scripts/test_select_converge_pacer.py +0 -207
- package/.agents/skills/_shared/pr-loop/scripts/test_teardown_worktrees.py +0 -59
- package/.agents/skills/_shared/pr-loop/scripts/test_write_handoff.py +0 -201
- package/.agents/skills/_shared/pr-loop/scripts/write_audit_outcomes.py +0 -182
- package/.agents/skills/_shared/pr-loop/scripts/write_fix_outcomes.py +0 -206
- package/.agents/skills/_shared/pr-loop/scripts/write_handoff.py +0 -309
- package/.agents/skills/_shared/pr-loop/state-schema.md +0 -5
- package/.agents/skills/_shared/pr-loop/worker-spawn.md +0 -5
- package/.agents/skills/autoconverge/.claude/CLAUDE.md +0 -1
- package/.agents/skills/autoconverge/AGENTS.md +0 -1
- package/.agents/skills/autoconverge/SKILL.md +0 -431
- package/.agents/skills/autoconverge/reference/.claude/CLAUDE.md +0 -1
- package/.agents/skills/autoconverge/reference/AGENTS.md +0 -1
- package/.agents/skills/autoconverge/reference/closing-report.md +0 -93
- package/.agents/skills/autoconverge/reference/convergence-gates.md +0 -31
- package/.agents/skills/autoconverge/reference/convergence.md +0 -219
- package/.agents/skills/autoconverge/reference/copilot-findings.md +0 -51
- package/.agents/skills/autoconverge/reference/gotchas.md +0 -66
- package/.agents/skills/autoconverge/reference/headless-safety.md +0 -44
- package/.agents/skills/autoconverge/reference/multi-pr.md +0 -128
- package/.agents/skills/autoconverge/reference/self-closing-loop.md +0 -84
- package/.agents/skills/autoconverge/reference/stop-conditions.md +0 -127
- package/.agents/skills/autoconverge/test_portable_pacer_gate.py +0 -54
- package/.agents/skills/autoconverge/workflow/.claude/CLAUDE.md +0 -1
- package/.agents/skills/autoconverge/workflow/AGENTS.md +0 -1
- package/.agents/skills/autoconverge/workflow/aggregate_runs.py +0 -371
- package/.agents/skills/autoconverge/workflow/autoconverge_report_constants/.claude/CLAUDE.md +0 -1
- package/.agents/skills/autoconverge/workflow/autoconverge_report_constants/AGENTS.md +0 -1
- package/.agents/skills/autoconverge/workflow/autoconverge_report_constants/__init__.py +0 -0
- package/.agents/skills/autoconverge/workflow/autoconverge_report_constants/render_report_constants.py +0 -250
- package/.agents/skills/autoconverge/workflow/converge.clean-audit.test.mjs +0 -665
- package/.agents/skills/autoconverge/workflow/converge.codex-gate.test.mjs +0 -472
- package/.agents/skills/autoconverge/workflow/converge.contract.test.mjs +0 -64
- package/.agents/skills/autoconverge/workflow/converge.copilot-gate.test.mjs +0 -1009
- package/.agents/skills/autoconverge/workflow/converge.fix-progress.test.mjs +0 -107
- package/.agents/skills/autoconverge/workflow/converge.fix-recovery.test.mjs +0 -33
- package/.agents/skills/autoconverge/workflow/converge.merge-conflict.test.mjs +0 -15
- package/.agents/skills/autoconverge/workflow/converge.mjs +0 -3132
- package/.agents/skills/autoconverge/workflow/converge.p2-advance.test.mjs +0 -202
- package/.agents/skills/autoconverge/workflow/converge.path-aware.test.mjs +0 -47
- package/.agents/skills/autoconverge/workflow/converge.precatch.test.mjs +0 -152
- package/.agents/skills/autoconverge/workflow/converge.run-input.test.mjs +0 -116
- package/.agents/skills/autoconverge/workflow/converge_multi.mjs +0 -169
- package/.agents/skills/autoconverge/workflow/converge_multi.run-input.test.mjs +0 -173
- package/.agents/skills/autoconverge/workflow/convergence_summary.py +0 -110
- package/.agents/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a11d903476b803493.jsonl +0 -2
- package/.agents/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a26213978adeef6fb.jsonl +0 -2
- package/.agents/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a3def0d15ed9d9110.jsonl +0 -2
- package/.agents/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a41f41b1b708ee3b7.jsonl +0 -2
- package/.agents/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a758b880abecc3ff7.jsonl +0 -2
- package/.agents/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a8897b89656b1bd16.jsonl +0 -2
- package/.agents/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-ab1c2d3e4f5a6b7c8.jsonl +0 -2
- package/.agents/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-abd463d744a1437bc.jsonl +0 -2
- package/.agents/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-ad19d027ae8ee1816.jsonl +0 -2
- package/.agents/skills/autoconverge/workflow/fixtures/wf_run/workflows/wf_881252e6-700.json +0 -266
- package/.agents/skills/autoconverge/workflow/render_report.py +0 -1024
- package/.agents/skills/autoconverge/workflow/test_aggregate_runs.py +0 -134
- package/.agents/skills/autoconverge/workflow/test_convergence_summary.py +0 -149
- package/.agents/skills/autoconverge/workflow/test_render_report.py +0 -812
- package/.agents/skills/hitl/SKILL.md +0 -45
- package/.agents/skills/pr-cleanup/SKILL.md +0 -140
- package/.agents/skills/pr-cleanup/reference/process-inventory.md +0 -17
- package/.agents/skills/pr-cleanup/reference/task-seeds.md +0 -22
- package/.agents/skills/pr-name-by-capability/SKILL.md +0 -73
- package/.agents/skills/pr-name-by-capability/reference/fetch-commands.md +0 -29
- package/.agents/skills/pr-name-by-capability/reference/offense-examples.md +0 -32
- package/.agents/skills/pr-name-by-capability/reference/report-template.md +0 -29
- package/.agents/skills/pr-name-by-capability/reference/rule-checklist.md +0 -38
- package/.agents/skills/pr-name-by-capability/reference/task-seeds.md +0 -10
- package/.agents/skills/pr-plain-language-cleanup/SKILL.md +0 -93
- package/.agents/skills/pr-refinement/SKILL.md +0 -31
- package/.agents/skills/pr-shared-extraction/SKILL.md +0 -177
- package/.agents/skills/pr-shared-extraction/reference/examples.md +0 -46
- package/.agents/skills/pr-shared-extraction/reference/offense-taxonomy.md +0 -100
- package/.agents/skills/pr-small-cl/SKILL.md +0 -52
- package/.agents/skills/pr-title-description/SKILL.md +0 -96
- package/.agents/skills/prototype/SKILL.md +0 -85
- package/.agents/skills/prototype/reference/honest-limitations.md +0 -23
- package/.agents/skills/prototype/reference/promotion-tasks.md +0 -23
- package/.agents/skills/prototype/scripts/build_sandbox_settings.py +0 -249
- package/.agents/skills/prototype/scripts/conftest.py +0 -15
- package/.agents/skills/prototype/scripts/launch_sandbox.py +0 -205
- package/.agents/skills/prototype/scripts/probe_sandbox_safety.py +0 -311
- package/.agents/skills/prototype/scripts/prototype_scripts_constants/__init__.py +0 -1
- package/.agents/skills/prototype/scripts/prototype_scripts_constants/config/__init__.py +0 -0
- package/.agents/skills/prototype/scripts/prototype_scripts_constants/config/build_sandbox_settings_constants.py +0 -41
- package/.agents/skills/prototype/scripts/prototype_scripts_constants/config/launch_sandbox_constants.py +0 -23
- package/.agents/skills/prototype/scripts/prototype_scripts_constants/config/probe_sandbox_safety_constants.py +0 -45
- package/.agents/skills/prototype/scripts/prototype_scripts_constants/config/prototype_common_constants.py +0 -10
- package/.agents/skills/prototype/scripts/test_build_sandbox_settings.py +0 -275
- package/.agents/skills/prototype/scripts/test_launch_sandbox.py +0 -303
- package/.agents/skills/prototype/scripts/test_probe_sandbox_safety.py +0 -312
- package/.agents/skills/prototype/workflows/promotion.md +0 -25
- package/.agents/skills/prototype/workflows/sandbox.md +0 -35
- package/.agents/skills/rebase/.claude/CLAUDE.md +0 -1
- package/.agents/skills/rebase/AGENTS.md +0 -1
- package/.agents/skills/rebase/SKILL.md +0 -178
- package/.agents/skills/review-router/SKILL.md +0 -51
- package/.agents/skills/review-router/reference/route-policy.json +0 -7
- package/.agents/skills/review-router/reference/task-seeds.md +0 -1
- package/.agents/skills/review-router/scripts/conftest.py +0 -4
- package/.agents/skills/review-router/scripts/review_router.py +0 -50
- package/.agents/skills/review-router/scripts/review_router_cli.py +0 -211
- package/.agents/skills/review-router/scripts/review_router_constants/__init__.py +0 -1
- package/.agents/skills/review-router/scripts/review_router_constants/config/__init__.py +0 -0
- package/.agents/skills/review-router/scripts/review_router_constants/config/constants.py +0 -13
- package/.agents/skills/review-router/scripts/test_review_router.py +0 -23
- package/.agents/skills/review-router/scripts/test_review_router_cli.py +0 -47
- package/.agents/skills/review-tier/SKILL.md +0 -56
- package/.agents/skills/review-tier/reference/task-seeds.md +0 -1
- package/.agents/skills/review-tier/reference/tier-policy.json +0 -9
- package/.agents/skills/review-tier/scripts/conftest.py +0 -4
- package/.agents/skills/review-tier/scripts/review_tier.py +0 -359
- package/.agents/skills/review-tier/scripts/review_tier_constants/__init__.py +0 -1
- package/.agents/skills/review-tier/scripts/review_tier_constants/config/__init__.py +0 -0
- package/.agents/skills/review-tier/scripts/review_tier_constants/config/constants.py +0 -29
- package/.agents/skills/review-tier/scripts/test_generation.py +0 -159
- package/.agents/skills/review-tier/scripts/test_review_tier.py +0 -33
- package/.agents/skills/run-claude-dev-env/SKILL.md +0 -84
- package/.agents/skills/session-log/.claude/CLAUDE.md +0 -1
- package/.agents/skills/session-log/AGENTS.md +0 -1
- package/.agents/skills/session-log/SKILL.md +0 -170
- package/.agents/skills/session-log/templates/frontmatter.md +0 -40
- package/.agents/skills/session-tidy/.claude/CLAUDE.md +0 -1
- package/.agents/skills/session-tidy/AGENTS.md +0 -1
- package/.agents/skills/session-tidy/SKILL.md +0 -191
- package/.agents/skills/skill-builder/references/.claude/CLAUDE.md +0 -1
- package/.agents/skills/skill-builder/references/AGENTS.md +0 -1
- package/.agents/skills/skill-builder/references/delegation-map.md +0 -130
- package/.agents/skills/skill-builder/references/description-field.md +0 -111
- package/.agents/skills/skill-builder/references/deterministic-elements.md +0 -218
- package/.agents/skills/skill-builder/references/progressive-disclosure.md +0 -122
- package/.agents/skills/skill-builder/references/self-audit-checklist.md +0 -126
- package/.agents/skills/skill-builder/references/skill-modularity.md +0 -111
- package/.agents/skills/skill-builder/references/skill-types.md +0 -232
- package/.agents/skills/skill-builder/references/thariq-x-post-skills.json +0 -33
- package/.agents/skills/skill-builder/templates/.claude/CLAUDE.md +0 -1
- package/.agents/skills/skill-builder/templates/AGENTS.md +0 -1
- package/.agents/skills/skill-builder/templates/gap-analysis.md +0 -87
- package/.agents/skills/skill-builder/workflows/.claude/CLAUDE.md +0 -1
- package/.agents/skills/skill-builder/workflows/AGENTS.md +0 -1
- package/.agents/skills/skill-builder/workflows/improve-skill.md +0 -136
- package/.agents/skills/skill-builder/workflows/new-skill.md +0 -179
- package/.agents/skills/skill-builder/workflows/polish-skill.md +0 -139
- package/.agents/skills/source-command-sr-loop/SKILL.md +0 -82
- package/.agents/skills/update/.claude/CLAUDE.md +0 -1
- package/.agents/skills/update/AGENTS.md +0 -1
- package/.agents/skills/update/SKILL.md +0 -190
- package/_shared/pr-loop/AGENTS.md +0 -1
- package/_shared/pr-loop/CLAUDE.md +0 -1
- package/_shared/pr-loop/audit-contract.md +0 -183
- package/_shared/pr-loop/audit-reply-template.md +0 -151
- package/_shared/pr-loop/code-rules-gate.md +0 -65
- package/_shared/pr-loop/fix-protocol.md +0 -60
- package/_shared/pr-loop/gh-payloads.md +0 -75
- package/_shared/pr-loop/post-audit-thread-contract.md +0 -51
- package/_shared/pr-loop/precatch-rubric.md +0 -66
- package/_shared/pr-loop/preflight-proposal.md +0 -56
- package/_shared/pr-loop/scripts/post_audit_thread.py +0 -1242
- package/_shared/pr-loop/scripts/pr_loop_shared_constants/post_audit_thread_constants.py +0 -199
- package/_shared/pr-loop/scripts/tests/test_post_audit_thread.py +0 -1115
- package/_shared/pr-loop/scripts/tests/test_post_audit_thread_constants.py +0 -129
- package/_shared/pr-loop/state-schema.md +0 -45
- package/_shared/pr-loop/worker-spawn.md +0 -189
- /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 +0,0 @@
|
|
|
1
|
-
|
|
@@ -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())
|
package/.agents/skills/autoconverge/workflow/autoconverge_report_constants/.claude/CLAUDE.md
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
@../AGENTS.md
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
|
|
File without changes
|