agent-control-plane 0.1.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/LICENSE +21 -0
- package/README.md +589 -0
- package/SKILL.md +149 -0
- package/assets/workflow-catalog.json +57 -0
- package/bin/audit-issue-routing.sh +74 -0
- package/bin/issue-resource-class.sh +58 -0
- package/bin/label-follow-up-issues.sh +114 -0
- package/bin/pr-risk.sh +532 -0
- package/bin/sync-pr-labels.sh +112 -0
- package/hooks/heartbeat-hooks.sh +573 -0
- package/hooks/issue-reconcile-hooks.sh +217 -0
- package/hooks/pr-reconcile-hooks.sh +225 -0
- package/npm/bin/agent-control-plane.js +1984 -0
- package/npm/public-bin/agent-control-plane +3 -0
- package/package.json +61 -0
- package/tools/bin/agent-cleanup-worktree +247 -0
- package/tools/bin/agent-github-update-labels +66 -0
- package/tools/bin/agent-init-worktree +216 -0
- package/tools/bin/agent-project-archive-run +52 -0
- package/tools/bin/agent-project-capture-worker +46 -0
- package/tools/bin/agent-project-catch-up-merged-prs +137 -0
- package/tools/bin/agent-project-cleanup-session +244 -0
- package/tools/bin/agent-project-detached-launch +107 -0
- package/tools/bin/agent-project-heartbeat-loop +2347 -0
- package/tools/bin/agent-project-open-issue-worktree +89 -0
- package/tools/bin/agent-project-open-pr-worktree +80 -0
- package/tools/bin/agent-project-publish-issue-pr +349 -0
- package/tools/bin/agent-project-reconcile-issue-session +1128 -0
- package/tools/bin/agent-project-reconcile-pr-session +1005 -0
- package/tools/bin/agent-project-retry-state +147 -0
- package/tools/bin/agent-project-run-claude-session +657 -0
- package/tools/bin/agent-project-run-codex-resilient +718 -0
- package/tools/bin/agent-project-run-codex-session +316 -0
- package/tools/bin/agent-project-run-kilo-session +27 -0
- package/tools/bin/agent-project-run-openclaw-session +984 -0
- package/tools/bin/agent-project-run-opencode-session +27 -0
- package/tools/bin/agent-project-sync-anchor-repo +128 -0
- package/tools/bin/agent-project-worker-status +143 -0
- package/tools/bin/audit-agent-worktrees.sh +310 -0
- package/tools/bin/audit-issue-routing.sh +11 -0
- package/tools/bin/audit-retained-layout.sh +58 -0
- package/tools/bin/audit-retained-overlap.sh +135 -0
- package/tools/bin/audit-retained-worktrees.sh +228 -0
- package/tools/bin/branch-verification-guard.sh +351 -0
- package/tools/bin/capture-worker.sh +18 -0
- package/tools/bin/check-skill-contracts.sh +324 -0
- package/tools/bin/cleanup-worktree.sh +44 -0
- package/tools/bin/codex-quota +31 -0
- package/tools/bin/create-follow-up-issue.sh +114 -0
- package/tools/bin/dashboard-launchd-bootstrap.sh +38 -0
- package/tools/bin/flow-config-lib.sh +2127 -0
- package/tools/bin/flow-resident-worker-lib.sh +683 -0
- package/tools/bin/flow-runtime-doctor.sh +97 -0
- package/tools/bin/flow-shell-lib.sh +266 -0
- package/tools/bin/heartbeat-recovery-preflight.sh +106 -0
- package/tools/bin/heartbeat-safe-auto.sh +551 -0
- package/tools/bin/install-dashboard-launchd.sh +152 -0
- package/tools/bin/install-project-launchd.sh +219 -0
- package/tools/bin/issue-publish-scope-guard.sh +242 -0
- package/tools/bin/issue-requires-local-workspace-install.sh +31 -0
- package/tools/bin/issue-resource-class.sh +12 -0
- package/tools/bin/kick-scheduler.sh +75 -0
- package/tools/bin/label-follow-up-issues.sh +14 -0
- package/tools/bin/new-pr-worktree.sh +50 -0
- package/tools/bin/new-worktree.sh +49 -0
- package/tools/bin/pr-risk.sh +12 -0
- package/tools/bin/prepare-worktree.sh +140 -0
- package/tools/bin/profile-activate.sh +109 -0
- package/tools/bin/profile-adopt.sh +219 -0
- package/tools/bin/profile-smoke.sh +461 -0
- package/tools/bin/project-init.sh +189 -0
- package/tools/bin/project-launchd-bootstrap.sh +54 -0
- package/tools/bin/project-remove.sh +155 -0
- package/tools/bin/project-runtime-supervisor.sh +56 -0
- package/tools/bin/project-runtimectl.sh +586 -0
- package/tools/bin/provider-cooldown-state.sh +166 -0
- package/tools/bin/publish-issue-worker.sh +31 -0
- package/tools/bin/reconcile-issue-worker.sh +34 -0
- package/tools/bin/reconcile-pr-worker.sh +34 -0
- package/tools/bin/record-verification.sh +71 -0
- package/tools/bin/render-architecture-infographics.sh +110 -0
- package/tools/bin/render-dashboard-demo-media.sh +333 -0
- package/tools/bin/render-dashboard-snapshot.py +16 -0
- package/tools/bin/render-flow-config.sh +86 -0
- package/tools/bin/retry-state.sh +31 -0
- package/tools/bin/reuse-issue-worktree.sh +75 -0
- package/tools/bin/run-codex-bypass.sh +3 -0
- package/tools/bin/run-codex-safe.sh +3 -0
- package/tools/bin/run-codex-task.sh +231 -0
- package/tools/bin/scaffold-profile.sh +374 -0
- package/tools/bin/serve-dashboard.sh +5 -0
- package/tools/bin/split-retained-slice.sh +124 -0
- package/tools/bin/start-issue-worker.sh +796 -0
- package/tools/bin/start-pr-fix-worker.sh +458 -0
- package/tools/bin/start-pr-merge-repair-worker.sh +8 -0
- package/tools/bin/start-pr-review-worker.sh +227 -0
- package/tools/bin/start-resident-issue-loop.sh +908 -0
- package/tools/bin/sync-agent-repo.sh +52 -0
- package/tools/bin/sync-dependency-baseline.sh +247 -0
- package/tools/bin/sync-pr-labels.sh +12 -0
- package/tools/bin/sync-recurring-issue-checklist.sh +274 -0
- package/tools/bin/sync-shared-agent-home.sh +214 -0
- package/tools/bin/sync-vscode-workspace.sh +157 -0
- package/tools/bin/test-smoke.sh +63 -0
- package/tools/bin/uninstall-project-launchd.sh +55 -0
- package/tools/bin/update-github-labels.sh +14 -0
- package/tools/bin/worker-status.sh +19 -0
- package/tools/bin/workflow-catalog.sh +77 -0
- package/tools/dashboard/app.js +286 -0
- package/tools/dashboard/dashboard_snapshot.py +466 -0
- package/tools/dashboard/index.html +41 -0
- package/tools/dashboard/server.py +64 -0
- package/tools/dashboard/styles.css +351 -0
- package/tools/templates/issue-prompt-template.md +109 -0
- package/tools/templates/pr-fix-template.md +120 -0
- package/tools/templates/pr-merge-repair-template.md +91 -0
- package/tools/templates/pr-review-template.md +62 -0
- package/tools/templates/scheduled-issue-prompt-template.md +62 -0
- package/tools/tests/test-agent-control-plane-npm-cli.sh +279 -0
- package/tools/tests/test-agent-github-update-labels-falls-back-to-repository-id.sh +56 -0
- package/tools/tests/test-agent-project-claude-session-wrapper-clears-stale-sandbox-artifacts.sh +89 -0
- package/tools/tests/test-agent-project-claude-session-wrapper-does-not-retry-provider-quota.sh +82 -0
- package/tools/tests/test-agent-project-claude-session-wrapper-retries-transient-failures.sh +90 -0
- package/tools/tests/test-agent-project-claude-session-wrapper-times-out.sh +73 -0
- package/tools/tests/test-agent-project-claude-session-wrapper.sh +103 -0
- package/tools/tests/test-agent-project-cleanup-session-orphan-fallback.sh +90 -0
- package/tools/tests/test-agent-project-cleanup-session-skip-worktree-cleanup.sh +90 -0
- package/tools/tests/test-agent-project-codex-live-thread-persist.sh +76 -0
- package/tools/tests/test-agent-project-codex-recovery.sh +731 -0
- package/tools/tests/test-agent-project-codex-session-wrapper-clears-stale-sandbox-artifacts.sh +105 -0
- package/tools/tests/test-agent-project-codex-session-wrapper.sh +97 -0
- package/tools/tests/test-agent-project-open-pr-worktree-config-prefix.sh +81 -0
- package/tools/tests/test-agent-project-openclaw-session-wrapper-clears-stale-sandbox-artifacts.sh +109 -0
- package/tools/tests/test-agent-project-openclaw-session-wrapper-infers-blocked-result-contract.sh +89 -0
- package/tools/tests/test-agent-project-openclaw-session-wrapper-recovers-literal-env-artifacts.sh +113 -0
- package/tools/tests/test-agent-project-openclaw-session-wrapper-recovers-version-mismatch.sh +135 -0
- package/tools/tests/test-agent-project-openclaw-session-wrapper-resident.sh +179 -0
- package/tools/tests/test-agent-project-openclaw-session-wrapper-reuses-existing-agent-after-add-race.sh +119 -0
- package/tools/tests/test-agent-project-openclaw-session-wrapper-terminates-rate-limit-hang.sh +91 -0
- package/tools/tests/test-agent-project-openclaw-session-wrapper.sh +117 -0
- package/tools/tests/test-agent-project-publish-issue-pr-prunes-stale-worktree-entry.sh +148 -0
- package/tools/tests/test-agent-project-publish-issue-pr-reads-archived-session.sh +146 -0
- package/tools/tests/test-agent-project-publish-issue-pr-recovers-final-head.sh +145 -0
- package/tools/tests/test-agent-project-publish-issue-pr-reuses-existing-worktree.sh +147 -0
- package/tools/tests/test-agent-project-reconcile-failure-reason.sh +456 -0
- package/tools/tests/test-agent-project-reconcile-issue-archived-session-fallback.sh +96 -0
- package/tools/tests/test-agent-project-reconcile-issue-before-blocked.sh +90 -0
- package/tools/tests/test-agent-project-reconcile-issue-host-verification-recovery-uses-recovered-worktree.sh +212 -0
- package/tools/tests/test-agent-project-reconcile-issue-host-verification-recovery.sh +207 -0
- package/tools/tests/test-agent-project-reconcile-issue-provider-quota-schedules-provider-cooldown.sh +101 -0
- package/tools/tests/test-agent-project-reconcile-issue-session-backfills-lane-metadata-from-worker-key.sh +113 -0
- package/tools/tests/test-agent-project-reconcile-issue-session-clears-stale-failed-summary.sh +117 -0
- package/tools/tests/test-agent-project-reconcile-issue-session-initializes-shared-agent-home.sh +55 -0
- package/tools/tests/test-agent-project-reconcile-issue-session-normalizes-runner-state.sh +125 -0
- package/tools/tests/test-agent-project-reconcile-issue-session-records-invalid-contract-summary.sh +118 -0
- package/tools/tests/test-agent-project-reconcile-issue-session-skips-duplicate-blocked-comment.sh +144 -0
- package/tools/tests/test-agent-project-reconcile-issue-session-standardizes-no-commits-blocker.sh +145 -0
- package/tools/tests/test-agent-project-reconcile-issue-session-synthesizes-blocked-comment.sh +139 -0
- package/tools/tests/test-agent-project-reconcile-pr-blocked-host-recovery.sh +242 -0
- package/tools/tests/test-agent-project-reconcile-pr-guard-blocked-no-commit.sh +142 -0
- package/tools/tests/test-agent-project-reconcile-pr-provider-quota-schedules-provider-cooldown.sh +106 -0
- package/tools/tests/test-agent-project-reconcile-pr-session-initializes-shared-agent-home.sh +66 -0
- package/tools/tests/test-agent-project-reconcile-pr-updated-branch-noop.sh +129 -0
- package/tools/tests/test-audit-agent-worktrees-active-launch-skips-git-inspection.sh +69 -0
- package/tools/tests/test-audit-agent-worktrees-broken-worktree.sh +43 -0
- package/tools/tests/test-audit-agent-worktrees-pending-launch-owner.sh +46 -0
- package/tools/tests/test-audit-agent-worktrees-unreconciled-owner.sh +79 -0
- package/tools/tests/test-audit-issue-routing-managed-branch-globs.sh +56 -0
- package/tools/tests/test-branch-verification-guard-generated-artifacts.sh +72 -0
- package/tools/tests/test-branch-verification-guard-targeted-coverage.sh +125 -0
- package/tools/tests/test-codex-quota-manager-failure-driven-rotation.sh +178 -0
- package/tools/tests/test-codex-quota-wrapper.sh +37 -0
- package/tools/tests/test-contribution-docs.sh +18 -0
- package/tools/tests/test-control-plane-dashboard-runtime-smoke.sh +343 -0
- package/tools/tests/test-create-follow-up-issue.sh +73 -0
- package/tools/tests/test-dashboard-launchd-bootstrap.sh +55 -0
- package/tools/tests/test-flow-export-execution-env-exports-repo-id.sh +30 -0
- package/tools/tests/test-flow-export-github-cli-auth-env-prefers-git-credential.sh +48 -0
- package/tools/tests/test-flow-github-api-repo-fallback-preserves-input.sh +85 -0
- package/tools/tests/test-flow-github-api-repo-prefers-explicit-repository-id.sh +60 -0
- package/tools/tests/test-flow-github-issue-list-falls-back-to-repository-id.sh +64 -0
- package/tools/tests/test-flow-github-pr-list-falls-back-to-repository-id.sh +77 -0
- package/tools/tests/test-flow-resident-can-reuse-does-not-leak-metadata.sh +52 -0
- package/tools/tests/test-flow-resident-reap-stale-controllers.sh +63 -0
- package/tools/tests/test-flow-resolve-codex-quota-tools.sh +104 -0
- package/tools/tests/test-flow-runtime-doctor-profile-selection.sh +27 -0
- package/tools/tests/test-heartbeat-codex-pr-linked-issue-exclusion.sh +79 -0
- package/tools/tests/test-heartbeat-hooks-enqueue-resident-issue-for-idle-controller.sh +115 -0
- package/tools/tests/test-heartbeat-hooks-enqueue-resident-issue-for-live-lane-controller.sh +117 -0
- package/tools/tests/test-heartbeat-hooks-start-resident-issue-loop-claude.sh +96 -0
- package/tools/tests/test-heartbeat-hooks-start-resident-issue-loop-codex.sh +96 -0
- package/tools/tests/test-heartbeat-hooks-start-resident-issue-loop.sh +96 -0
- package/tools/tests/test-heartbeat-loop-auth-wait-does-not-consume-capacity.sh +170 -0
- package/tools/tests/test-heartbeat-loop-blocked-recovery-lane.sh +201 -0
- package/tools/tests/test-heartbeat-loop-blocked-recovery-vs-pr-reservation.sh +201 -0
- package/tools/tests/test-heartbeat-loop-idle-resident-controller-does-not-block-launches.sh +160 -0
- package/tools/tests/test-heartbeat-loop-pr-launch-dedup.sh +133 -0
- package/tools/tests/test-heartbeat-loop-provider-cooldown-suppresses-launches.sh +157 -0
- package/tools/tests/test-heartbeat-loop-reaps-stale-resident-controller.sh +181 -0
- package/tools/tests/test-heartbeat-loop-waiting-provider-resident-controller-does-not-block-launches.sh +160 -0
- package/tools/tests/test-heartbeat-ready-issues-blocked-recovery.sh +134 -0
- package/tools/tests/test-heartbeat-safe-auto-dynamic-concurrency.sh +162 -0
- package/tools/tests/test-heartbeat-safe-auto-no-tmux-sessions.sh +136 -0
- package/tools/tests/test-heartbeat-safe-auto-openclaw-skips-codex-quota.sh +139 -0
- package/tools/tests/test-heartbeat-safe-auto-quota-health-signal.sh +119 -0
- package/tools/tests/test-heartbeat-safe-auto-stale-shared-loop-pid-does-not-skip.sh +140 -0
- package/tools/tests/test-heartbeat-safe-auto-static-capacity-without-quota-cache.sh +142 -0
- package/tools/tests/test-heartbeat-safe-auto-zero-healthy-pools.sh +141 -0
- package/tools/tests/test-heartbeat-sync-issue-labels-empty-schedule.sh +65 -0
- package/tools/tests/test-heartbeat-sync-open-agent-prs-terminal-clears-running.sh +179 -0
- package/tools/tests/test-install-dashboard-launchd.sh +78 -0
- package/tools/tests/test-install-project-launchd-adds-tool-paths.sh +87 -0
- package/tools/tests/test-install-project-launchd.sh +110 -0
- package/tools/tests/test-issue-local-workspace-install-policy.sh +81 -0
- package/tools/tests/test-issue-publish-scope-guard-docs-signal.sh +70 -0
- package/tools/tests/test-issue-reconcile-hooks-success-clears-blocked.sh +36 -0
- package/tools/tests/test-kick-scheduler-requires-explicit-profile.sh +47 -0
- package/tools/tests/test-label-follow-up-issues-falls-back-to-repository-id.sh +132 -0
- package/tools/tests/test-manual-operator-entrypoints-require-explicit-profile.sh +64 -0
- package/tools/tests/test-package-funding-metadata.sh +21 -0
- package/tools/tests/test-package-public-metadata.sh +62 -0
- package/tools/tests/test-placeholder-worker-adapters.sh +38 -0
- package/tools/tests/test-pr-reconcile-hooks-refreshes-recurring-issue-checklist.sh +110 -0
- package/tools/tests/test-pr-risk-cohesive-mobile-locale-scope.sh +70 -0
- package/tools/tests/test-pr-risk-fix-label-semantics.sh +114 -0
- package/tools/tests/test-pr-risk-local-first-no-checks.sh +70 -0
- package/tools/tests/test-prepare-worktree-simple-repo-baseline.sh +67 -0
- package/tools/tests/test-profile-activate.sh +33 -0
- package/tools/tests/test-profile-adopt-allow-missing-repo.sh +68 -0
- package/tools/tests/test-profile-adopt-skip-workspace-sync-missing-file.sh +61 -0
- package/tools/tests/test-profile-adopt-syncs-anchor-and-workspace.sh +90 -0
- package/tools/tests/test-profile-smoke-collision.sh +44 -0
- package/tools/tests/test-profile-smoke-invalid-claude-config.sh +31 -0
- package/tools/tests/test-profile-smoke-invalid-provider-pool.sh +68 -0
- package/tools/tests/test-profile-smoke-repo-slug-mismatch.sh +36 -0
- package/tools/tests/test-profile-smoke.sh +45 -0
- package/tools/tests/test-project-init-force-and-skip-sync.sh +61 -0
- package/tools/tests/test-project-init-repo-slug-mismatch.sh +29 -0
- package/tools/tests/test-project-init.sh +66 -0
- package/tools/tests/test-project-launchd-bootstrap.sh +66 -0
- package/tools/tests/test-project-remove.sh +150 -0
- package/tools/tests/test-project-runtime-supervisor.sh +47 -0
- package/tools/tests/test-project-runtimectl-launchd.sh +115 -0
- package/tools/tests/test-project-runtimectl-missing-profile.sh +54 -0
- package/tools/tests/test-project-runtimectl-start-falls-back-to-bootstrap.sh +108 -0
- package/tools/tests/test-project-runtimectl-status-reports-supervisor-as-heartbeat-parent.sh +95 -0
- package/tools/tests/test-project-runtimectl-status-supervisor-running.sh +59 -0
- package/tools/tests/test-project-runtimectl-stop-cancels-pending-kick.sh +85 -0
- package/tools/tests/test-project-runtimectl-stop-clears-running-labels.sh +78 -0
- package/tools/tests/test-project-runtimectl.sh +212 -0
- package/tools/tests/test-provider-cooldown-state-prefers-runtime-worker-context.sh +39 -0
- package/tools/tests/test-provider-cooldown-state.sh +59 -0
- package/tools/tests/test-public-repo-docs.sh +159 -0
- package/tools/tests/test-reconcile-pr-worker-acp-config-routing.sh +75 -0
- package/tools/tests/test-render-dashboard-snapshot.sh +149 -0
- package/tools/tests/test-render-flow-config-demo-profile.sh +36 -0
- package/tools/tests/test-render-flow-config-provider-pool-fallback.sh +81 -0
- package/tools/tests/test-render-flow-config.sh +52 -0
- package/tools/tests/test-run-codex-task-claude-routing.sh +125 -0
- package/tools/tests/test-run-codex-task-codex-resident-routing.sh +108 -0
- package/tools/tests/test-run-codex-task-kilo-routing.sh +98 -0
- package/tools/tests/test-run-codex-task-openclaw-resident-routing.sh +117 -0
- package/tools/tests/test-run-codex-task-openclaw-routing.sh +113 -0
- package/tools/tests/test-run-codex-task-opencode-routing.sh +98 -0
- package/tools/tests/test-run-codex-task-provider-pool-fallback-routing.sh +146 -0
- package/tools/tests/test-scaffold-profile.sh +108 -0
- package/tools/tests/test-serve-dashboard.sh +93 -0
- package/tools/tests/test-start-issue-worker-blocked-context.sh +129 -0
- package/tools/tests/test-start-issue-worker-blocks-complete-recurring-checklist.sh +189 -0
- package/tools/tests/test-start-issue-worker-local-install-routing.sh +157 -0
- package/tools/tests/test-start-issue-worker-profile-template-routing.sh +149 -0
- package/tools/tests/test-start-issue-worker-recurring-resident-reuse-codex.sh +212 -0
- package/tools/tests/test-start-issue-worker-recurring-resident-reuse.sh +219 -0
- package/tools/tests/test-start-issue-worker-renders-verification-snippet.sh +155 -0
- package/tools/tests/test-start-issue-worker-resident-reuse-falls-back-to-new-worktree.sh +199 -0
- package/tools/tests/test-start-pr-fix-worker-host-blocker-context.sh +275 -0
- package/tools/tests/test-start-resident-issue-loop-adopts-next-recurring-issue.sh +185 -0
- package/tools/tests/test-start-resident-issue-loop-clears-pending-while-waiting-due.sh +152 -0
- package/tools/tests/test-start-resident-issue-loop-consumes-queued-lease.sh +186 -0
- package/tools/tests/test-start-resident-issue-loop-fails-over-provider-pool.sh +212 -0
- package/tools/tests/test-start-resident-issue-loop-immediate-cycles.sh +148 -0
- package/tools/tests/test-start-resident-issue-loop-waits-for-provider.sh +194 -0
- package/tools/tests/test-start-resident-issue-loop-waits-for-terminal-reconcile-status.sh +198 -0
- package/tools/tests/test-start-resident-issue-loop-yields-to-live-lane-controller.sh +145 -0
- package/tools/tests/test-sync-pr-labels-fix-lane-uses-repair-queued.sh +67 -0
- package/tools/tests/test-sync-recurring-issue-checklist-backfills-workflow-complete-blocker.sh +70 -0
- package/tools/tests/test-sync-recurring-issue-checklist.sh +95 -0
- package/tools/tests/test-sync-shared-agent-home-local-source-root.sh +66 -0
- package/tools/tests/test-sync-shared-agent-home-preserves-unrelated-workflow-catalog-skill.sh +47 -0
- package/tools/tests/test-test-smoke.sh +86 -0
- package/tools/tests/test-uninstall-project-launchd.sh +37 -0
- package/tools/tests/test-update-github-labels-prefers-sibling-helper.sh +49 -0
- package/tools/tests/test-workflow-catalog.sh +43 -0
- package/tools/vendor/codex-quota/LICENSE +21 -0
- package/tools/vendor/codex-quota/README.md +459 -0
- package/tools/vendor/codex-quota/codex-quota.js +261 -0
- package/tools/vendor/codex-quota/lib/claude-accounts.js +226 -0
- package/tools/vendor/codex-quota/lib/claude-oauth.js +174 -0
- package/tools/vendor/codex-quota/lib/claude-tokens.js +471 -0
- package/tools/vendor/codex-quota/lib/claude-usage.js +929 -0
- package/tools/vendor/codex-quota/lib/codex-accounts.js +205 -0
- package/tools/vendor/codex-quota/lib/codex-tokens.js +326 -0
- package/tools/vendor/codex-quota/lib/codex-usage.js +32 -0
- package/tools/vendor/codex-quota/lib/color.js +72 -0
- package/tools/vendor/codex-quota/lib/constants.js +57 -0
- package/tools/vendor/codex-quota/lib/container.js +143 -0
- package/tools/vendor/codex-quota/lib/display.js +1111 -0
- package/tools/vendor/codex-quota/lib/fs.js +63 -0
- package/tools/vendor/codex-quota/lib/handlers.js +2060 -0
- package/tools/vendor/codex-quota/lib/jwt.js +33 -0
- package/tools/vendor/codex-quota/lib/oauth.js +486 -0
- package/tools/vendor/codex-quota/lib/paths.js +34 -0
- package/tools/vendor/codex-quota/lib/prompts.js +44 -0
- package/tools/vendor/codex-quota/lib/sync.js +1438 -0
- package/tools/vendor/codex-quota/lib/token-match.js +96 -0
- package/tools/vendor/codex-quota-manager/scripts/auto-switch.sh +500 -0
- package/tools/vendor/codex-quota-manager/scripts/batch-add.sh +123 -0
|
@@ -0,0 +1,1005 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
5
|
+
|
|
6
|
+
bootstrap_flow_shell_lib() {
|
|
7
|
+
local candidate=""
|
|
8
|
+
local skill_name=""
|
|
9
|
+
|
|
10
|
+
for candidate in \
|
|
11
|
+
"${SCRIPT_DIR}/flow-shell-lib.sh" \
|
|
12
|
+
"${AGENT_CONTROL_PLANE_ROOT:-}/tools/bin/flow-shell-lib.sh" \
|
|
13
|
+
"${ACP_ROOT:-}/tools/bin/flow-shell-lib.sh" \
|
|
14
|
+
"${F_LOSNING_FLOW_ROOT:-}/tools/bin/flow-shell-lib.sh" \
|
|
15
|
+
"${AGENT_FLOW_SKILL_ROOT:-}/tools/bin/flow-shell-lib.sh" \
|
|
16
|
+
"${SHARED_AGENT_HOME:-}/tools/bin/flow-shell-lib.sh" \
|
|
17
|
+
"$(pwd)/tools/bin/flow-shell-lib.sh"; do
|
|
18
|
+
if [[ -n "${candidate}" && -f "${candidate}" ]]; then
|
|
19
|
+
printf '%s\n' "${candidate}"
|
|
20
|
+
return 0
|
|
21
|
+
fi
|
|
22
|
+
done
|
|
23
|
+
|
|
24
|
+
if [[ -n "${SHARED_AGENT_HOME:-}" ]]; then
|
|
25
|
+
for skill_name in "${AGENT_CONTROL_PLANE_SKILL_NAME:-agent-control-plane}" "${AGENT_CONTROL_PLANE_COMPAT_ALIAS:-}"; do
|
|
26
|
+
[[ -n "${skill_name}" ]] || continue
|
|
27
|
+
candidate="${SHARED_AGENT_HOME}/skills/openclaw/${skill_name}/tools/bin/flow-shell-lib.sh"
|
|
28
|
+
if [[ -f "${candidate}" ]]; then
|
|
29
|
+
printf '%s\n' "${candidate}"
|
|
30
|
+
return 0
|
|
31
|
+
fi
|
|
32
|
+
done
|
|
33
|
+
fi
|
|
34
|
+
|
|
35
|
+
echo "unable to locate flow-shell-lib.sh for reconcile bootstrap" >&2
|
|
36
|
+
return 1
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
FLOW_SHELL_LIB_PATH="$(bootstrap_flow_shell_lib)"
|
|
40
|
+
BOOTSTRAP_TOOLS_DIR="$(cd "$(dirname "${FLOW_SHELL_LIB_PATH}")" && pwd)"
|
|
41
|
+
# shellcheck source=/dev/null
|
|
42
|
+
source "${FLOW_SHELL_LIB_PATH}"
|
|
43
|
+
|
|
44
|
+
resolve_reconcile_tools_dir() {
|
|
45
|
+
local candidate_root=""
|
|
46
|
+
local skill_name=""
|
|
47
|
+
|
|
48
|
+
for candidate_root in \
|
|
49
|
+
"${AGENT_CONTROL_PLANE_ROOT:-}" \
|
|
50
|
+
"${ACP_ROOT:-}" \
|
|
51
|
+
"${F_LOSNING_FLOW_ROOT:-}" \
|
|
52
|
+
"${AGENT_FLOW_SKILL_ROOT:-}"; do
|
|
53
|
+
if [[ -n "${candidate_root}" && -d "${candidate_root}/tools/bin" ]]; then
|
|
54
|
+
printf '%s/tools/bin\n' "${candidate_root}"
|
|
55
|
+
return 0
|
|
56
|
+
fi
|
|
57
|
+
done
|
|
58
|
+
|
|
59
|
+
if [[ -n "${SHARED_AGENT_HOME:-}" ]]; then
|
|
60
|
+
if [[ -d "${SHARED_AGENT_HOME}/tools/bin" ]]; then
|
|
61
|
+
printf '%s/tools/bin\n' "${SHARED_AGENT_HOME}"
|
|
62
|
+
return 0
|
|
63
|
+
fi
|
|
64
|
+
for skill_name in "${AGENT_CONTROL_PLANE_SKILL_NAME:-agent-control-plane}" "${AGENT_CONTROL_PLANE_COMPAT_ALIAS:-}"; do
|
|
65
|
+
[[ -n "${skill_name}" ]] || continue
|
|
66
|
+
candidate_root="${SHARED_AGENT_HOME}/skills/openclaw/${skill_name}"
|
|
67
|
+
if [[ -d "${candidate_root}/tools/bin" ]]; then
|
|
68
|
+
printf '%s/tools/bin\n' "${candidate_root}"
|
|
69
|
+
return 0
|
|
70
|
+
fi
|
|
71
|
+
done
|
|
72
|
+
fi
|
|
73
|
+
|
|
74
|
+
if [[ -d "${SCRIPT_DIR}" ]]; then
|
|
75
|
+
printf '%s\n' "${SCRIPT_DIR}"
|
|
76
|
+
return 0
|
|
77
|
+
fi
|
|
78
|
+
|
|
79
|
+
printf '%s\n' "${BOOTSTRAP_TOOLS_DIR}"
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
usage() {
|
|
83
|
+
cat <<'EOF'
|
|
84
|
+
Usage:
|
|
85
|
+
agent-project-reconcile-pr-session --session <id> --repo-slug <owner/repo> --repo-root <path> --runs-root <path> --history-root <path> [--hook-file <path>]
|
|
86
|
+
|
|
87
|
+
Reconcile a completed PR worker run using shared lifecycle control flow while
|
|
88
|
+
allowing project adapters to inject policy hooks.
|
|
89
|
+
EOF
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
shared_tools_dir="$(resolve_reconcile_tools_dir)"
|
|
93
|
+
resolve_reconcile_helper_path() {
|
|
94
|
+
local helper_name="${1:?helper name required}"
|
|
95
|
+
local candidate=""
|
|
96
|
+
|
|
97
|
+
for candidate in \
|
|
98
|
+
"${SCRIPT_DIR}/${helper_name}" \
|
|
99
|
+
"${BOOTSTRAP_TOOLS_DIR}/${helper_name}" \
|
|
100
|
+
"${shared_tools_dir}/${helper_name}"; do
|
|
101
|
+
if [[ -n "${candidate}" && -f "${candidate}" ]]; then
|
|
102
|
+
printf '%s\n' "${candidate}"
|
|
103
|
+
return 0
|
|
104
|
+
fi
|
|
105
|
+
done
|
|
106
|
+
|
|
107
|
+
echo "unable to locate ${helper_name} for reconcile bootstrap" >&2
|
|
108
|
+
return 1
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
FLOW_CONFIG_LIB_PATH="$(resolve_reconcile_helper_path "flow-config-lib.sh")"
|
|
112
|
+
# shellcheck source=/dev/null
|
|
113
|
+
source "${FLOW_CONFIG_LIB_PATH}"
|
|
114
|
+
verification_guard_script="${shared_tools_dir}/branch-verification-guard.sh"
|
|
115
|
+
session=""
|
|
116
|
+
repo_slug=""
|
|
117
|
+
repo_root=""
|
|
118
|
+
runs_root=""
|
|
119
|
+
history_root=""
|
|
120
|
+
hook_file=""
|
|
121
|
+
|
|
122
|
+
while [[ $# -gt 0 ]]; do
|
|
123
|
+
case "$1" in
|
|
124
|
+
--session) session="${2:-}"; shift 2 ;;
|
|
125
|
+
--repo-slug) repo_slug="${2:-}"; shift 2 ;;
|
|
126
|
+
--repo-root) repo_root="${2:-}"; shift 2 ;;
|
|
127
|
+
--runs-root) runs_root="${2:-}"; shift 2 ;;
|
|
128
|
+
--history-root) history_root="${2:-}"; shift 2 ;;
|
|
129
|
+
--hook-file) hook_file="${2:-}"; shift 2 ;;
|
|
130
|
+
--help|-h) usage; exit 0 ;;
|
|
131
|
+
*) echo "Unknown argument: $1" >&2; usage >&2; exit 1 ;;
|
|
132
|
+
esac
|
|
133
|
+
done
|
|
134
|
+
|
|
135
|
+
if [[ -z "$session" || -z "$repo_slug" || -z "$repo_root" || -z "$runs_root" || -z "$history_root" ]]; then
|
|
136
|
+
usage >&2
|
|
137
|
+
exit 1
|
|
138
|
+
fi
|
|
139
|
+
|
|
140
|
+
status_out="$(
|
|
141
|
+
"${shared_tools_dir}/agent-project-worker-status" \
|
|
142
|
+
--runs-root "$runs_root" \
|
|
143
|
+
--session "$session"
|
|
144
|
+
)"
|
|
145
|
+
status="$(awk -F= '/^STATUS=/{print $2}' <<<"$status_out")"
|
|
146
|
+
failure_reason="$(awk -F= '/^FAILURE_REASON=/{print $2}' <<<"$status_out" | tail -n 1)"
|
|
147
|
+
|
|
148
|
+
meta_file="$(awk -F= '/^META_FILE=/{print $2}' <<<"$status_out")"
|
|
149
|
+
if [[ -z "$meta_file" || ! -f "$meta_file" ]]; then
|
|
150
|
+
echo "missing metadata for session $session" >&2
|
|
151
|
+
exit 1
|
|
152
|
+
fi
|
|
153
|
+
|
|
154
|
+
run_dir="$(dirname "$meta_file")"
|
|
155
|
+
|
|
156
|
+
set -a
|
|
157
|
+
# shellcheck source=/dev/null
|
|
158
|
+
source "$meta_file"
|
|
159
|
+
set +a
|
|
160
|
+
pr_worktree="${WORKTREE:-}"
|
|
161
|
+
|
|
162
|
+
pr_number="${PR_NUMBER:-}"
|
|
163
|
+
if [[ -z "$pr_number" ]]; then
|
|
164
|
+
echo "session $session is missing PR_NUMBER" >&2
|
|
165
|
+
exit 1
|
|
166
|
+
fi
|
|
167
|
+
|
|
168
|
+
result_outcome=""
|
|
169
|
+
result_action=""
|
|
170
|
+
result_issue_id="${ISSUE_ID:-}"
|
|
171
|
+
host_blocker_file="${run_dir}/host-blocker.md"
|
|
172
|
+
prompt_file="${run_dir}/prompt.md"
|
|
173
|
+
pr_comment_file="${run_dir}/pr-comment.md"
|
|
174
|
+
session_log_file="${run_dir}/${session}.log"
|
|
175
|
+
record_verification_script="${FLOW_TOOLS_DIR:-${shared_tools_dir}}/record-verification.sh"
|
|
176
|
+
result_file_candidate="${run_dir}/result.env"
|
|
177
|
+
if [[ ! -f "$result_file_candidate" && -n "${RESULT_FILE:-}" && -f "${RESULT_FILE}" ]]; then
|
|
178
|
+
result_file_candidate="${RESULT_FILE}"
|
|
179
|
+
fi
|
|
180
|
+
if [[ -f "$result_file_candidate" ]]; then
|
|
181
|
+
set -a
|
|
182
|
+
# shellcheck source=/dev/null
|
|
183
|
+
source "$result_file_candidate"
|
|
184
|
+
set +a
|
|
185
|
+
result_outcome="${OUTCOME:-}"
|
|
186
|
+
result_action="${ACTION:-}"
|
|
187
|
+
result_issue_id="${ISSUE_ID:-${result_issue_id}}"
|
|
188
|
+
fi
|
|
189
|
+
|
|
190
|
+
pr_schedule_retry() { :; }
|
|
191
|
+
pr_clear_retry() { :; }
|
|
192
|
+
pr_cleanup_linked_issue_session() { :; }
|
|
193
|
+
pr_cleanup_merged_residue() { :; }
|
|
194
|
+
pr_linked_issue_should_close() { printf 'yes\n'; }
|
|
195
|
+
pr_after_merged() { :; }
|
|
196
|
+
pr_after_closed() { :; }
|
|
197
|
+
pr_automerge_allowed() { printf 'no\n'; }
|
|
198
|
+
pr_review_pass_action() { printf 'merge\n'; }
|
|
199
|
+
pr_after_double_check_advanced() { :; }
|
|
200
|
+
pr_after_updated_branch() { :; }
|
|
201
|
+
pr_after_blocked() { :; }
|
|
202
|
+
pr_after_succeeded() { :; }
|
|
203
|
+
pr_after_failed() { :; }
|
|
204
|
+
pr_after_reconciled() { :; }
|
|
205
|
+
pr_result_contract_note=""
|
|
206
|
+
|
|
207
|
+
if [[ -n "$hook_file" && -f "$hook_file" ]]; then
|
|
208
|
+
# shellcheck source=/dev/null
|
|
209
|
+
source "$hook_file"
|
|
210
|
+
fi
|
|
211
|
+
|
|
212
|
+
provider_cooldown_script="${shared_tools_dir}/provider-cooldown-state.sh"
|
|
213
|
+
|
|
214
|
+
schedule_provider_quota_cooldown() {
|
|
215
|
+
local reason="${1:-provider-quota-limit}"
|
|
216
|
+
[[ "${failure_reason:-}" == "provider-quota-limit" ]] || return 0
|
|
217
|
+
[[ -x "${provider_cooldown_script}" ]] || return 0
|
|
218
|
+
|
|
219
|
+
"${provider_cooldown_script}" schedule "${reason}" >/dev/null || true
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
clear_provider_quota_cooldown() {
|
|
223
|
+
[[ -x "${provider_cooldown_script}" ]] || return 0
|
|
224
|
+
|
|
225
|
+
"${provider_cooldown_script}" clear >/dev/null || true
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
owner="${repo_slug%%/*}"
|
|
229
|
+
repo="${repo_slug#*/}"
|
|
230
|
+
pr_view_json="$(flow_github_pr_view_json "$repo_slug" "$pr_number")"
|
|
231
|
+
pr_state="$(jq -r '.state' <<<"$pr_view_json")"
|
|
232
|
+
pr_base_ref="$(jq -r '.baseRefName // "main"' <<<"$pr_view_json")"
|
|
233
|
+
|
|
234
|
+
if [[ "$status" == "RUNNING" && "$pr_state" != "MERGED" && "$pr_state" != "CLOSED" ]]; then
|
|
235
|
+
printf 'STATUS=%s\n' "$status"
|
|
236
|
+
exit 0
|
|
237
|
+
fi
|
|
238
|
+
|
|
239
|
+
review_pass_action_from_result_action() {
|
|
240
|
+
case "${1:-}" in
|
|
241
|
+
host-advance-double-check-2)
|
|
242
|
+
printf 'advance-double-check-2\n'
|
|
243
|
+
;;
|
|
244
|
+
host-await-human-review)
|
|
245
|
+
printf 'wait-human\n'
|
|
246
|
+
;;
|
|
247
|
+
host-approve-and-merge|"")
|
|
248
|
+
printf 'merge\n'
|
|
249
|
+
;;
|
|
250
|
+
*)
|
|
251
|
+
return 1
|
|
252
|
+
;;
|
|
253
|
+
esac
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
normalize_pr_result_contract() {
|
|
257
|
+
[[ "$status" == "SUCCEEDED" ]] || return 0
|
|
258
|
+
[[ "$pr_state" == "MERGED" ]] && return 0
|
|
259
|
+
|
|
260
|
+
case "${result_outcome:-}" in
|
|
261
|
+
approved-local-review-passed)
|
|
262
|
+
local review_pass_action expected_action legacy_action=""
|
|
263
|
+
if [[ -n "${result_action:-}" ]]; then
|
|
264
|
+
if review_pass_action="$(review_pass_action_from_result_action "${result_action}" 2>/dev/null)"; then
|
|
265
|
+
:
|
|
266
|
+
elif [[ "${result_action}" == "host-approve-and-merge" ]]; then
|
|
267
|
+
review_pass_action="merge"
|
|
268
|
+
pr_result_contract_note="normalized-legacy-review-action"
|
|
269
|
+
else
|
|
270
|
+
echo "invalid PR review result contract for session ${session}: ACTION='${result_action}'" >&2
|
|
271
|
+
return 1
|
|
272
|
+
fi
|
|
273
|
+
else
|
|
274
|
+
review_pass_action="$(pr_review_pass_action "$pr_number")"
|
|
275
|
+
fi
|
|
276
|
+
case "$review_pass_action" in
|
|
277
|
+
advance-double-check-2)
|
|
278
|
+
expected_action="host-advance-double-check-2"
|
|
279
|
+
legacy_action="host-approve-and-merge"
|
|
280
|
+
;;
|
|
281
|
+
wait-human)
|
|
282
|
+
expected_action="host-await-human-review"
|
|
283
|
+
;;
|
|
284
|
+
merge|"")
|
|
285
|
+
expected_action="host-approve-and-merge"
|
|
286
|
+
;;
|
|
287
|
+
*)
|
|
288
|
+
echo "unsupported review pass action for PR ${pr_number}: ${review_pass_action}" >&2
|
|
289
|
+
return 1
|
|
290
|
+
;;
|
|
291
|
+
esac
|
|
292
|
+
if [[ -z "${result_action:-}" ]]; then
|
|
293
|
+
result_action="$expected_action"
|
|
294
|
+
pr_result_contract_note="normalized-missing-review-action"
|
|
295
|
+
return 0
|
|
296
|
+
fi
|
|
297
|
+
if [[ "$result_action" == "$expected_action" ]]; then
|
|
298
|
+
return 0
|
|
299
|
+
fi
|
|
300
|
+
if [[ -n "$legacy_action" && "$result_action" == "$legacy_action" ]]; then
|
|
301
|
+
result_action="$expected_action"
|
|
302
|
+
pr_result_contract_note="normalized-legacy-review-action"
|
|
303
|
+
return 0
|
|
304
|
+
fi
|
|
305
|
+
echo "invalid PR review result contract for session ${session}: OUTCOME='${result_outcome}' ACTION='${result_action}' EXPECTED='${expected_action}'" >&2
|
|
306
|
+
return 1
|
|
307
|
+
;;
|
|
308
|
+
updated-branch)
|
|
309
|
+
if [[ -z "${result_action:-}" ]]; then
|
|
310
|
+
result_action="host-push-pr-branch"
|
|
311
|
+
pr_result_contract_note="normalized-missing-updated-branch-action"
|
|
312
|
+
return 0
|
|
313
|
+
fi
|
|
314
|
+
if [[ "$result_action" == "host-push-pr-branch" ]]; then
|
|
315
|
+
return 0
|
|
316
|
+
fi
|
|
317
|
+
echo "invalid PR updated-branch result contract for session ${session}: ACTION='${result_action}'" >&2
|
|
318
|
+
return 1
|
|
319
|
+
;;
|
|
320
|
+
no-change-needed)
|
|
321
|
+
if [[ -z "${result_action:-}" ]]; then
|
|
322
|
+
result_action="host-refresh-pr-state"
|
|
323
|
+
pr_result_contract_note="normalized-missing-no-change-needed-action"
|
|
324
|
+
return 0
|
|
325
|
+
fi
|
|
326
|
+
if [[ "$result_action" == "host-refresh-pr-state" ]]; then
|
|
327
|
+
return 0
|
|
328
|
+
fi
|
|
329
|
+
echo "invalid PR no-change-needed result contract for session ${session}: ACTION='${result_action}'" >&2
|
|
330
|
+
return 1
|
|
331
|
+
;;
|
|
332
|
+
blocked)
|
|
333
|
+
if [[ -z "${result_action:-}" ]]; then
|
|
334
|
+
result_action="host-comment-pr-blocker"
|
|
335
|
+
pr_result_contract_note="normalized-missing-blocked-action"
|
|
336
|
+
return 0
|
|
337
|
+
fi
|
|
338
|
+
case "$result_action" in
|
|
339
|
+
host-comment-pr-blocker)
|
|
340
|
+
return 0
|
|
341
|
+
;;
|
|
342
|
+
requested-changes-or-blocked)
|
|
343
|
+
result_action="host-comment-pr-blocker"
|
|
344
|
+
pr_result_contract_note="normalized-legacy-blocked-action"
|
|
345
|
+
return 0
|
|
346
|
+
;;
|
|
347
|
+
*)
|
|
348
|
+
echo "invalid PR blocked result contract for session ${session}: ACTION='${result_action}'" >&2
|
|
349
|
+
return 1
|
|
350
|
+
;;
|
|
351
|
+
esac
|
|
352
|
+
;;
|
|
353
|
+
*)
|
|
354
|
+
echo "invalid PR worker result contract for session ${session}: OUTCOME='${result_outcome:-}' ACTION='${result_action:-}'" >&2
|
|
355
|
+
return 1
|
|
356
|
+
;;
|
|
357
|
+
esac
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
mark_reconciled() {
|
|
361
|
+
if [[ -d "$run_dir" ]]; then
|
|
362
|
+
touch "${run_dir}/reconciled.ok"
|
|
363
|
+
fi
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
post_pr_comment_if_present() {
|
|
367
|
+
local comment_file="${run_dir}/pr-comment.md"
|
|
368
|
+
[[ -s "$comment_file" ]] || return 0
|
|
369
|
+
if pr_comment_already_posted; then
|
|
370
|
+
return 0
|
|
371
|
+
fi
|
|
372
|
+
flow_github_api_repo "${repo_slug}" "issues/${pr_number}/comments" --method POST -f body="$(cat "$comment_file")" >/dev/null
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
pr_comment_already_posted() {
|
|
376
|
+
local comment_file="${run_dir}/pr-comment.md"
|
|
377
|
+
[[ -s "$comment_file" ]] || return 1
|
|
378
|
+
local comment_body comments_json
|
|
379
|
+
comment_body="$(cat "$comment_file")"
|
|
380
|
+
comments_json="$(flow_github_pr_view_json "$repo_slug" "$pr_number" 2>/dev/null || true)"
|
|
381
|
+
[[ -n "$comments_json" ]] || return 1
|
|
382
|
+
jq -e --arg body "$comment_body" 'any(.comments[]?; .body == $body)' >/dev/null <<<"$comments_json"
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
blocked_result_indicates_local_bind_failure() {
|
|
386
|
+
local candidate_file
|
|
387
|
+
for candidate_file in "$pr_comment_file" "$session_log_file"; do
|
|
388
|
+
[[ -f "$candidate_file" ]] || continue
|
|
389
|
+
if grep -Eiq 'listen EPERM|failed to bind to local ports|Process from config\.webServer exited early' "$candidate_file"; then
|
|
390
|
+
return 0
|
|
391
|
+
fi
|
|
392
|
+
done
|
|
393
|
+
return 1
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
extract_preapproved_host_recovery_commands() {
|
|
397
|
+
[[ -f "$prompt_file" ]] || return 0
|
|
398
|
+
sed -n 's/^.*loopback retry command: `\(.*\)`$/\1/p' "$prompt_file"
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
record_host_verification_result() {
|
|
402
|
+
local verification_status="${1:?verification status required}"
|
|
403
|
+
local command_text="${2:?command text required}"
|
|
404
|
+
local note_text="${3:-}"
|
|
405
|
+
|
|
406
|
+
if [[ ! -x "$record_verification_script" ]]; then
|
|
407
|
+
return 0
|
|
408
|
+
fi
|
|
409
|
+
|
|
410
|
+
if [[ -n "$note_text" ]]; then
|
|
411
|
+
bash "$record_verification_script" --run-dir "$run_dir" --status "$verification_status" --command "$command_text" --note "$note_text" >/dev/null
|
|
412
|
+
else
|
|
413
|
+
bash "$record_verification_script" --run-dir "$run_dir" --status "$verification_status" --command "$command_text" >/dev/null
|
|
414
|
+
fi
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
run_host_verification_command() {
|
|
418
|
+
local command_text="${1:?command text required}"
|
|
419
|
+
|
|
420
|
+
{
|
|
421
|
+
printf '\n[host-recovery] command=%s\n' "$command_text"
|
|
422
|
+
} >>"$session_log_file"
|
|
423
|
+
|
|
424
|
+
if WORKTREE_DIR="$pr_worktree" HOST_COMMAND="$command_text" bash -lc 'set -euo pipefail; cd "$WORKTREE_DIR"; eval "$HOST_COMMAND"' >>"$session_log_file" 2>&1; then
|
|
425
|
+
record_host_verification_result "pass" "$command_text" "host-recovery-after-sandbox-bind-failure"
|
|
426
|
+
return 0
|
|
427
|
+
fi
|
|
428
|
+
|
|
429
|
+
record_host_verification_result "fail" "$command_text" "host-recovery-after-sandbox-bind-failure"
|
|
430
|
+
printf '[host-recovery] command failed=%s\n' "$command_text" >>"$session_log_file"
|
|
431
|
+
return 1
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
rewrite_pr_comment_for_host_recovery() {
|
|
435
|
+
local commands_text="${1:-}"
|
|
436
|
+
local tmp_comment_file="${pr_comment_file}.tmp.$$"
|
|
437
|
+
local command_text=""
|
|
438
|
+
|
|
439
|
+
if [[ -f "$pr_comment_file" ]]; then
|
|
440
|
+
awk '
|
|
441
|
+
/^\*\*Blocker\*\*$/ { exit }
|
|
442
|
+
{ print }
|
|
443
|
+
' "$pr_comment_file" >"$tmp_comment_file"
|
|
444
|
+
else
|
|
445
|
+
: >"$tmp_comment_file"
|
|
446
|
+
fi
|
|
447
|
+
|
|
448
|
+
{
|
|
449
|
+
if [[ -s "$tmp_comment_file" ]]; then
|
|
450
|
+
printf '\n\n'
|
|
451
|
+
fi
|
|
452
|
+
printf '**Host Recovery**\n'
|
|
453
|
+
printf -- '- Host reran the pre-approved verification outside the worker sandbox after sandbox-only local port bind failures.\n'
|
|
454
|
+
while IFS= read -r command_text; do
|
|
455
|
+
[[ -n "$command_text" ]] || continue
|
|
456
|
+
printf -- '- ✅ `%s`\n' "$command_text"
|
|
457
|
+
done <<<"$commands_text"
|
|
458
|
+
} >>"$tmp_comment_file"
|
|
459
|
+
|
|
460
|
+
mv "$tmp_comment_file" "$pr_comment_file"
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
persist_updated_branch_result_contract() {
|
|
464
|
+
cat >"${run_dir}/result.env" <<EOF
|
|
465
|
+
OUTCOME=updated-branch
|
|
466
|
+
ACTION=host-push-pr-branch
|
|
467
|
+
PR_NUMBER=${pr_number}
|
|
468
|
+
ISSUE_ID=${result_issue_id}
|
|
469
|
+
EOF
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
attempt_blocked_pr_host_verification_recovery() {
|
|
473
|
+
local recovery_commands=""
|
|
474
|
+
local command_text=""
|
|
475
|
+
|
|
476
|
+
[[ "${result_outcome:-}" == "blocked" ]] || return 1
|
|
477
|
+
[[ -n "$pr_worktree" && -d "$pr_worktree" ]] || return 1
|
|
478
|
+
blocked_result_indicates_local_bind_failure || return 1
|
|
479
|
+
|
|
480
|
+
recovery_commands="$(extract_preapproved_host_recovery_commands)"
|
|
481
|
+
[[ -n "$recovery_commands" ]] || return 1
|
|
482
|
+
|
|
483
|
+
while IFS= read -r command_text; do
|
|
484
|
+
[[ -n "$command_text" ]] || continue
|
|
485
|
+
if ! run_host_verification_command "$command_text"; then
|
|
486
|
+
return 1
|
|
487
|
+
fi
|
|
488
|
+
done <<<"$recovery_commands"
|
|
489
|
+
|
|
490
|
+
rewrite_pr_comment_for_host_recovery "$recovery_commands"
|
|
491
|
+
persist_updated_branch_result_contract
|
|
492
|
+
result_outcome="updated-branch"
|
|
493
|
+
result_action="host-push-pr-branch"
|
|
494
|
+
failure_reason=""
|
|
495
|
+
pr_result_contract_note="host-recovered-sandbox-bind-failure"
|
|
496
|
+
return 0
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
require_transition() {
|
|
500
|
+
local step="${1:?step required}"
|
|
501
|
+
shift
|
|
502
|
+
if ! "$@"; then
|
|
503
|
+
echo "reconcile transition failed: ${step}" >&2
|
|
504
|
+
exit 1
|
|
505
|
+
fi
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
close_linked_issue_if_open() {
|
|
509
|
+
local issue_id="${1:-}"
|
|
510
|
+
[[ -n "$issue_id" ]] || return 0
|
|
511
|
+
|
|
512
|
+
local issue_state
|
|
513
|
+
issue_state="$(flow_github_issue_view_json "$repo_slug" "$issue_id" 2>/dev/null | jq -r '.state // empty' || true)"
|
|
514
|
+
if [[ "$issue_state" == "OPEN" ]]; then
|
|
515
|
+
flow_github_issue_close "$repo_slug" "$issue_id" "Closed automatically after PR #${pr_number} merged." >/dev/null 2>&1 || true
|
|
516
|
+
fi
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
push_pr_branch() {
|
|
520
|
+
if [[ -z "$pr_worktree" || ! -d "$pr_worktree" ]]; then
|
|
521
|
+
echo "missing PR worktree for session $session" >&2
|
|
522
|
+
return 1
|
|
523
|
+
fi
|
|
524
|
+
if [[ -z "${PR_HEAD_REF:-}" ]]; then
|
|
525
|
+
echo "session $session is missing PR_HEAD_REF" >&2
|
|
526
|
+
return 1
|
|
527
|
+
fi
|
|
528
|
+
|
|
529
|
+
git -C "$pr_worktree" push origin "HEAD:${PR_HEAD_REF}"
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
pr_branch_commits_ahead_remote_count() {
|
|
533
|
+
if [[ -z "$pr_worktree" || ! -d "$pr_worktree" ]]; then
|
|
534
|
+
echo "missing PR worktree for session $session" >&2
|
|
535
|
+
return 1
|
|
536
|
+
fi
|
|
537
|
+
if [[ -z "${PR_HEAD_REF:-}" ]]; then
|
|
538
|
+
echo "session $session is missing PR_HEAD_REF" >&2
|
|
539
|
+
return 1
|
|
540
|
+
fi
|
|
541
|
+
if ! git -C "$pr_worktree" fetch origin "+refs/heads/${PR_HEAD_REF}:refs/remotes/origin/${PR_HEAD_REF}" --prune >/dev/null 2>&1; then
|
|
542
|
+
echo "unable to refresh remote tracking ref for PR head ${PR_HEAD_REF}" >&2
|
|
543
|
+
return 1
|
|
544
|
+
fi
|
|
545
|
+
|
|
546
|
+
git -C "$pr_worktree" rev-list --count "origin/${PR_HEAD_REF}..HEAD"
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
guard_pr_branch_verification() {
|
|
550
|
+
local guard_output=""
|
|
551
|
+
if [[ -z "$pr_worktree" || ! -d "$pr_worktree" ]]; then
|
|
552
|
+
echo "missing PR worktree for session $session" >&2
|
|
553
|
+
return 1
|
|
554
|
+
fi
|
|
555
|
+
|
|
556
|
+
if guard_output="$(
|
|
557
|
+
"${verification_guard_script}" \
|
|
558
|
+
--worktree "$pr_worktree" \
|
|
559
|
+
--base-ref "origin/${pr_base_ref}" \
|
|
560
|
+
--run-dir "$run_dir" 2>&1
|
|
561
|
+
)"; then
|
|
562
|
+
rm -f "$host_blocker_file"
|
|
563
|
+
return 0
|
|
564
|
+
fi
|
|
565
|
+
|
|
566
|
+
printf '%s\n' "$guard_output" >"$host_blocker_file"
|
|
567
|
+
printf '%s\n' "$guard_output" >&2
|
|
568
|
+
return 1
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
collect_stageable_paths() {
|
|
572
|
+
if [[ -z "$pr_worktree" || ! -d "$pr_worktree" ]]; then
|
|
573
|
+
return 0
|
|
574
|
+
fi
|
|
575
|
+
|
|
576
|
+
{
|
|
577
|
+
git -C "$pr_worktree" diff --name-only --relative
|
|
578
|
+
git -C "$pr_worktree" diff --cached --name-only --relative
|
|
579
|
+
git -C "$pr_worktree" ls-files --others --exclude-standard 2>/dev/null || true
|
|
580
|
+
} | awk '
|
|
581
|
+
NF == 0 { next }
|
|
582
|
+
$0 ~ /(^|\/)node_modules(\/|$)/ { next }
|
|
583
|
+
$0 ~ /^\.openclaw-artifacts(\/|$)/ { next }
|
|
584
|
+
!seen[$0]++ { print $0 }
|
|
585
|
+
' | sort
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
host_commit_pr_worktree_changes() {
|
|
589
|
+
local stageable_paths
|
|
590
|
+
local commit_message_file="${run_dir}/commit-message.txt"
|
|
591
|
+
local commit_message=""
|
|
592
|
+
|
|
593
|
+
if [[ -z "$pr_worktree" || ! -d "$pr_worktree" ]]; then
|
|
594
|
+
echo "missing PR worktree for session $session" >&2
|
|
595
|
+
return 1
|
|
596
|
+
fi
|
|
597
|
+
|
|
598
|
+
stageable_paths="$(collect_stageable_paths)"
|
|
599
|
+
if [[ -n "$stageable_paths" ]]; then
|
|
600
|
+
while IFS= read -r relative_path; do
|
|
601
|
+
[[ -n "$relative_path" ]] || continue
|
|
602
|
+
git -C "$pr_worktree" add -- "$relative_path"
|
|
603
|
+
done <<<"$stageable_paths"
|
|
604
|
+
fi
|
|
605
|
+
|
|
606
|
+
if git -C "$pr_worktree" diff --cached --quiet && git -C "$pr_worktree" diff --quiet; then
|
|
607
|
+
return 0
|
|
608
|
+
fi
|
|
609
|
+
|
|
610
|
+
if [[ -f "$commit_message_file" ]]; then
|
|
611
|
+
commit_message="$(tr -d '\r' <"$commit_message_file" | sed -n '1p')"
|
|
612
|
+
fi
|
|
613
|
+
|
|
614
|
+
if [[ -z "$commit_message" ]]; then
|
|
615
|
+
if git -C "$pr_worktree" rev-parse -q --verify MERGE_HEAD >/dev/null 2>&1; then
|
|
616
|
+
commit_message="fix(pr): resolve merge drift for PR #${pr_number}"
|
|
617
|
+
else
|
|
618
|
+
commit_message="fix(pr): apply repair for PR #${pr_number}"
|
|
619
|
+
fi
|
|
620
|
+
fi
|
|
621
|
+
|
|
622
|
+
git -C "$pr_worktree" commit -m "$commit_message" >/dev/null
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
remaining_merge_conflict_paths() {
|
|
626
|
+
local base_ref="${1:?base ref required}"
|
|
627
|
+
|
|
628
|
+
if [[ -z "$pr_worktree" || ! -d "$pr_worktree" ]]; then
|
|
629
|
+
printf '%s\n' "__missing_worktree__"
|
|
630
|
+
return 0
|
|
631
|
+
fi
|
|
632
|
+
|
|
633
|
+
if git -C "$pr_worktree" rev-parse -q --verify MERGE_HEAD >/dev/null 2>&1; then
|
|
634
|
+
git -C "$pr_worktree" ls-files -u \
|
|
635
|
+
| awk '
|
|
636
|
+
NF >= 4 {
|
|
637
|
+
path=$4
|
|
638
|
+
if (!(path in seen)) {
|
|
639
|
+
seen[path]=1
|
|
640
|
+
print path
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
'
|
|
644
|
+
return 0
|
|
645
|
+
fi
|
|
646
|
+
|
|
647
|
+
if ! git -C "$repo_root" fetch origin "+refs/heads/${base_ref}:refs/remotes/origin/${base_ref}" --prune >/dev/null 2>&1; then
|
|
648
|
+
printf '%s\n' "__unable_to_fetch_base_ref__:${base_ref}"
|
|
649
|
+
return 0
|
|
650
|
+
fi
|
|
651
|
+
|
|
652
|
+
local base_sha
|
|
653
|
+
base_sha="$(git -C "$pr_worktree" merge-base HEAD "origin/${base_ref}" 2>/dev/null || true)"
|
|
654
|
+
if [[ -z "$base_sha" ]]; then
|
|
655
|
+
printf '%s\n' "__unable_to_compute_merge_base__:${base_ref}"
|
|
656
|
+
return 0
|
|
657
|
+
fi
|
|
658
|
+
|
|
659
|
+
git -C "$pr_worktree" merge-tree "$base_sha" HEAD "origin/${base_ref}" 2>/dev/null \
|
|
660
|
+
| awk '
|
|
661
|
+
/^changed in both$/ { capture=1; next }
|
|
662
|
+
capture && /^( base| our| their) / {
|
|
663
|
+
path=$NF
|
|
664
|
+
if (!(path in seen)) {
|
|
665
|
+
seen[path]=1
|
|
666
|
+
print path
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
capture && /^@@ / { capture=0 }
|
|
670
|
+
'
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
append_host_guard_comment() {
|
|
674
|
+
local base_ref="${1:?base ref required}"
|
|
675
|
+
local conflict_paths="${2:-}"
|
|
676
|
+
local comment_file="${run_dir}/pr-comment.md"
|
|
677
|
+
local host_blocker_body=""
|
|
678
|
+
|
|
679
|
+
if [[ -s "$comment_file" ]]; then
|
|
680
|
+
printf '\n\n' >>"$comment_file"
|
|
681
|
+
fi
|
|
682
|
+
|
|
683
|
+
host_blocker_body="$(cat <<EOF
|
|
684
|
+
## PR repair host guard
|
|
685
|
+
|
|
686
|
+
Host rejected this repair and did not push it because local merge simulation against \`${base_ref}\` still reports unresolved conflict paths:
|
|
687
|
+
|
|
688
|
+
$(printf '%s\n' "$conflict_paths" | sed 's/^/- /')
|
|
689
|
+
|
|
690
|
+
No partial repair commit was pushed to the PR branch. The PR stays in fix lane and will retry after cooldown.
|
|
691
|
+
EOF
|
|
692
|
+
)"
|
|
693
|
+
|
|
694
|
+
printf '%s\n' "$host_blocker_body" >>"$comment_file"
|
|
695
|
+
printf '%s\n' "$host_blocker_body" >"$host_blocker_file"
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
merge_state_prepared() {
|
|
699
|
+
[[ -n "$pr_worktree" && -d "$pr_worktree" ]] || return 1
|
|
700
|
+
git -C "$pr_worktree" rev-parse -q --verify MERGE_HEAD >/dev/null 2>&1
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
approve_and_merge() {
|
|
704
|
+
local approve_output
|
|
705
|
+
if ! approve_output="$(
|
|
706
|
+
flow_github_api_repo "${repo_slug}" "pulls/${pr_number}/reviews" \
|
|
707
|
+
--method POST \
|
|
708
|
+
-f event=APPROVE \
|
|
709
|
+
-f body="Automated final review passed. Safe low-risk scope, green checks, and host-side merge approved." \
|
|
710
|
+
2>&1
|
|
711
|
+
)"; then
|
|
712
|
+
if ! grep -q "Can not approve your own pull request" <<<"$approve_output"; then
|
|
713
|
+
printf '%s\n' "$approve_output" >&2
|
|
714
|
+
return 1
|
|
715
|
+
fi
|
|
716
|
+
fi
|
|
717
|
+
|
|
718
|
+
flow_github_pr_merge "$repo_slug" "$pr_number" "squash" "yes"
|
|
719
|
+
}
|
|
720
|
+
|
|
721
|
+
cleanup_pr_session() {
|
|
722
|
+
"${shared_tools_dir}/agent-project-cleanup-session" \
|
|
723
|
+
--repo-root "$repo_root" \
|
|
724
|
+
--runs-root "$runs_root" \
|
|
725
|
+
--history-root "$history_root" \
|
|
726
|
+
--session "$session" \
|
|
727
|
+
--worktree "$pr_worktree" \
|
|
728
|
+
--mode pr >/dev/null || true
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
notify_pr_reconciled() {
|
|
732
|
+
pr_after_reconciled "$status" "$pr_state" "${result_outcome:-}" "${result_action:-}" "$pr_number" || true
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
handle_verification_guard_block() {
|
|
736
|
+
failure_reason="verification-guard-blocked"
|
|
737
|
+
require_transition "pr_schedule_retry" pr_schedule_retry "$failure_reason"
|
|
738
|
+
require_transition "pr_after_blocked" pr_after_blocked "$pr_number"
|
|
739
|
+
cleanup_pr_session
|
|
740
|
+
result_outcome="blocked"
|
|
741
|
+
result_action="host-verification-guard-blocked"
|
|
742
|
+
notify_pr_reconciled
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
handle_linked_issue_merge_cleanup() {
|
|
746
|
+
local issue_id="${1:-}"
|
|
747
|
+
[[ -n "$issue_id" ]] || return 0
|
|
748
|
+
pr_cleanup_linked_issue_session "$issue_id" || true
|
|
749
|
+
if [[ "$(pr_linked_issue_should_close "$issue_id" || printf 'yes\n')" == "yes" ]]; then
|
|
750
|
+
close_linked_issue_if_open "$issue_id"
|
|
751
|
+
fi
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
handle_updated_branch_result() {
|
|
755
|
+
if [[ -z "$pr_worktree" || ! -d "$pr_worktree" ]]; then
|
|
756
|
+
if pr_comment_already_posted; then
|
|
757
|
+
require_transition "pr_clear_retry" pr_clear_retry
|
|
758
|
+
require_transition "pr_after_updated_branch" pr_after_updated_branch "$pr_number"
|
|
759
|
+
cleanup_pr_session
|
|
760
|
+
result_action="${result_action:-pushed-branch-for-ci}"
|
|
761
|
+
notify_pr_reconciled
|
|
762
|
+
else
|
|
763
|
+
require_transition "pr_schedule_retry" pr_schedule_retry "missing-pr-worktree-before-publish"
|
|
764
|
+
require_transition "pr_after_blocked" pr_after_blocked "$pr_number"
|
|
765
|
+
cleanup_pr_session
|
|
766
|
+
result_outcome="blocked"
|
|
767
|
+
result_action="host-missing-pr-worktree"
|
|
768
|
+
notify_pr_reconciled
|
|
769
|
+
fi
|
|
770
|
+
return 0
|
|
771
|
+
fi
|
|
772
|
+
|
|
773
|
+
if ! guard_pr_branch_verification; then
|
|
774
|
+
handle_verification_guard_block
|
|
775
|
+
return 0
|
|
776
|
+
fi
|
|
777
|
+
|
|
778
|
+
host_commit_pr_worktree_changes
|
|
779
|
+
remaining_conflict_paths="$(remaining_merge_conflict_paths "$pr_base_ref" || true)"
|
|
780
|
+
if [[ -n "$remaining_conflict_paths" ]]; then
|
|
781
|
+
append_host_guard_comment "$pr_base_ref" "$remaining_conflict_paths"
|
|
782
|
+
# Keep host-guard notes local when nothing was pushed. Posting them to GitHub
|
|
783
|
+
# makes unchanged PR heads look like successful repairs and can re-queue review.
|
|
784
|
+
require_transition "pr_schedule_retry" pr_schedule_retry "remaining-merge-conflicts-after-updated-branch"
|
|
785
|
+
require_transition "pr_after_blocked" pr_after_blocked "$pr_number"
|
|
786
|
+
cleanup_pr_session
|
|
787
|
+
result_outcome="blocked"
|
|
788
|
+
result_action="host-rejected-partial-repair"
|
|
789
|
+
notify_pr_reconciled
|
|
790
|
+
return 0
|
|
791
|
+
fi
|
|
792
|
+
|
|
793
|
+
if ! ahead_count="$(pr_branch_commits_ahead_remote_count)"; then
|
|
794
|
+
failure_reason="updated-branch-remote-ref-unavailable"
|
|
795
|
+
require_transition "pr_schedule_retry" pr_schedule_retry "$failure_reason"
|
|
796
|
+
require_transition "pr_after_blocked" pr_after_blocked "$pr_number"
|
|
797
|
+
cleanup_pr_session
|
|
798
|
+
result_outcome="blocked"
|
|
799
|
+
result_action="host-branch-ahead-check-failed"
|
|
800
|
+
notify_pr_reconciled
|
|
801
|
+
return 0
|
|
802
|
+
fi
|
|
803
|
+
|
|
804
|
+
if [[ "${ahead_count}" == "0" ]]; then
|
|
805
|
+
failure_reason="updated-branch-no-commits-ahead"
|
|
806
|
+
require_transition "pr_schedule_retry" pr_schedule_retry "$failure_reason"
|
|
807
|
+
require_transition "pr_after_blocked" pr_after_blocked "$pr_number"
|
|
808
|
+
cleanup_pr_session
|
|
809
|
+
result_outcome="blocked"
|
|
810
|
+
result_action="host-noop-updated-branch"
|
|
811
|
+
notify_pr_reconciled
|
|
812
|
+
return 0
|
|
813
|
+
fi
|
|
814
|
+
|
|
815
|
+
push_pr_branch
|
|
816
|
+
post_pr_comment_if_present
|
|
817
|
+
require_transition "pr_clear_retry" pr_clear_retry
|
|
818
|
+
require_transition "pr_after_updated_branch" pr_after_updated_branch "$pr_number"
|
|
819
|
+
cleanup_pr_session
|
|
820
|
+
result_action="${result_action:-pushed-branch-for-ci}"
|
|
821
|
+
notify_pr_reconciled
|
|
822
|
+
}
|
|
823
|
+
|
|
824
|
+
if [[ "$status" == "SUCCEEDED" ]] && ! normalize_pr_result_contract; then
|
|
825
|
+
status="FAILED"
|
|
826
|
+
failure_reason="invalid-result-contract"
|
|
827
|
+
pr_result_contract_note="invalid-result-contract"
|
|
828
|
+
require_transition "pr_schedule_retry" pr_schedule_retry "$failure_reason"
|
|
829
|
+
require_transition "pr_after_failed" pr_after_failed "$pr_number"
|
|
830
|
+
cleanup_pr_session
|
|
831
|
+
result_outcome="invalid-contract"
|
|
832
|
+
result_action="queued-pr-retry"
|
|
833
|
+
notify_pr_reconciled
|
|
834
|
+
elif [[ "$pr_state" == "MERGED" ]]; then
|
|
835
|
+
status="SUCCEEDED"
|
|
836
|
+
failure_reason=""
|
|
837
|
+
clear_provider_quota_cooldown
|
|
838
|
+
require_transition "pr_clear_retry" pr_clear_retry
|
|
839
|
+
require_transition "handle_linked_issue_merge_cleanup" handle_linked_issue_merge_cleanup "$result_issue_id"
|
|
840
|
+
require_transition "pr_after_merged" pr_after_merged "$pr_number"
|
|
841
|
+
require_transition "pr_cleanup_merged_residue" pr_cleanup_merged_residue "$pr_number"
|
|
842
|
+
cleanup_pr_session
|
|
843
|
+
result_outcome="${result_outcome:-merged}"
|
|
844
|
+
result_action="${result_action:-approved-and-merged}"
|
|
845
|
+
notify_pr_reconciled
|
|
846
|
+
elif [[ "$pr_state" == "CLOSED" ]]; then
|
|
847
|
+
status="SUCCEEDED"
|
|
848
|
+
failure_reason=""
|
|
849
|
+
clear_provider_quota_cooldown
|
|
850
|
+
require_transition "pr_clear_retry" pr_clear_retry
|
|
851
|
+
require_transition "pr_after_closed" pr_after_closed "$pr_number"
|
|
852
|
+
cleanup_pr_session
|
|
853
|
+
result_outcome="${result_outcome:-closed}"
|
|
854
|
+
result_action="${result_action:-cleaned-closed-pr}"
|
|
855
|
+
notify_pr_reconciled
|
|
856
|
+
elif [[ "$status" == "SUCCEEDED" && "$result_outcome" == "approved-local-review-passed" ]]; then
|
|
857
|
+
if ! review_pass_action="$(review_pass_action_from_result_action "${result_action:-}" 2>/dev/null)"; then
|
|
858
|
+
review_pass_action="$(pr_review_pass_action "$pr_number")"
|
|
859
|
+
fi
|
|
860
|
+
case "$review_pass_action" in
|
|
861
|
+
advance-double-check-2)
|
|
862
|
+
require_transition "pr_clear_retry" pr_clear_retry
|
|
863
|
+
require_transition "pr_after_double_check_advanced" pr_after_double_check_advanced "$pr_number" "2"
|
|
864
|
+
cleanup_pr_session
|
|
865
|
+
result_outcome="double-check-1-approved"
|
|
866
|
+
result_action="queued-double-check-2"
|
|
867
|
+
notify_pr_reconciled
|
|
868
|
+
;;
|
|
869
|
+
wait-human)
|
|
870
|
+
require_transition "pr_clear_retry" pr_clear_retry
|
|
871
|
+
require_transition "pr_after_succeeded" pr_after_succeeded "$pr_number"
|
|
872
|
+
cleanup_pr_session
|
|
873
|
+
result_outcome="waiting-human-review"
|
|
874
|
+
result_action="queued-human-review"
|
|
875
|
+
notify_pr_reconciled
|
|
876
|
+
;;
|
|
877
|
+
merge|"")
|
|
878
|
+
if [[ "$(pr_automerge_allowed "$pr_number")" != "yes" ]]; then
|
|
879
|
+
echo "PR ${pr_number} is no longer eligible for auto-merge" >&2
|
|
880
|
+
exit 1
|
|
881
|
+
fi
|
|
882
|
+
|
|
883
|
+
require_transition "pr_clear_retry" pr_clear_retry
|
|
884
|
+
approve_and_merge
|
|
885
|
+
pr_state="$(flow_github_pr_view_json "$repo_slug" "$pr_number" | jq -r '.state')"
|
|
886
|
+
if [[ "$pr_state" != "MERGED" ]]; then
|
|
887
|
+
echo "PR ${pr_number} did not merge successfully" >&2
|
|
888
|
+
exit 1
|
|
889
|
+
fi
|
|
890
|
+
|
|
891
|
+
require_transition "handle_linked_issue_merge_cleanup" handle_linked_issue_merge_cleanup "$result_issue_id"
|
|
892
|
+
require_transition "pr_after_merged" pr_after_merged "$pr_number"
|
|
893
|
+
require_transition "pr_cleanup_merged_residue" pr_cleanup_merged_residue "$pr_number"
|
|
894
|
+
cleanup_pr_session
|
|
895
|
+
result_outcome="merged"
|
|
896
|
+
result_action="approved-and-merged"
|
|
897
|
+
notify_pr_reconciled
|
|
898
|
+
;;
|
|
899
|
+
*)
|
|
900
|
+
echo "unsupported review pass action for PR ${pr_number}: ${review_pass_action}" >&2
|
|
901
|
+
exit 1
|
|
902
|
+
;;
|
|
903
|
+
esac
|
|
904
|
+
elif [[ "$status" == "SUCCEEDED" && "$result_outcome" == "updated-branch" ]]; then
|
|
905
|
+
handle_updated_branch_result
|
|
906
|
+
elif [[ "$status" == "SUCCEEDED" && "$result_outcome" == "no-change-needed" ]]; then
|
|
907
|
+
if merge_state_prepared; then
|
|
908
|
+
remaining_conflict_paths="$(remaining_merge_conflict_paths "$pr_base_ref" || true)"
|
|
909
|
+
if [[ -n "$remaining_conflict_paths" ]]; then
|
|
910
|
+
append_host_guard_comment "$pr_base_ref" "$remaining_conflict_paths"
|
|
911
|
+
post_pr_comment_if_present
|
|
912
|
+
require_transition "pr_schedule_retry" pr_schedule_retry "remaining-merge-conflicts-after-no-change-needed"
|
|
913
|
+
require_transition "pr_after_blocked" pr_after_blocked "$pr_number"
|
|
914
|
+
cleanup_pr_session
|
|
915
|
+
result_outcome="blocked"
|
|
916
|
+
result_action="host-rejected-no-change-needed"
|
|
917
|
+
notify_pr_reconciled
|
|
918
|
+
else
|
|
919
|
+
if ! guard_pr_branch_verification; then
|
|
920
|
+
handle_verification_guard_block
|
|
921
|
+
else
|
|
922
|
+
host_commit_pr_worktree_changes
|
|
923
|
+
if ! ahead_count="$(pr_branch_commits_ahead_remote_count)"; then
|
|
924
|
+
failure_reason="no-change-needed-remote-ref-unavailable"
|
|
925
|
+
require_transition "pr_schedule_retry" pr_schedule_retry "$failure_reason"
|
|
926
|
+
require_transition "pr_after_blocked" pr_after_blocked "$pr_number"
|
|
927
|
+
cleanup_pr_session
|
|
928
|
+
result_outcome="blocked"
|
|
929
|
+
result_action="host-branch-ahead-check-failed"
|
|
930
|
+
elif [[ "${ahead_count}" == "0" ]]; then
|
|
931
|
+
failure_reason="no-change-needed-promoted-without-branch-advance"
|
|
932
|
+
require_transition "pr_schedule_retry" pr_schedule_retry "$failure_reason"
|
|
933
|
+
require_transition "pr_after_blocked" pr_after_blocked "$pr_number"
|
|
934
|
+
cleanup_pr_session
|
|
935
|
+
result_outcome="blocked"
|
|
936
|
+
result_action="host-rejected-noop-promotion"
|
|
937
|
+
else
|
|
938
|
+
push_pr_branch
|
|
939
|
+
post_pr_comment_if_present
|
|
940
|
+
require_transition "pr_clear_retry" pr_clear_retry
|
|
941
|
+
require_transition "pr_after_updated_branch" pr_after_updated_branch "$pr_number"
|
|
942
|
+
cleanup_pr_session
|
|
943
|
+
result_outcome="updated-branch"
|
|
944
|
+
result_action="host-promoted-no-change-needed-to-updated-branch"
|
|
945
|
+
fi
|
|
946
|
+
notify_pr_reconciled
|
|
947
|
+
fi
|
|
948
|
+
fi
|
|
949
|
+
else
|
|
950
|
+
remaining_conflict_paths="$(remaining_merge_conflict_paths "$pr_base_ref" || true)"
|
|
951
|
+
if [[ -n "$remaining_conflict_paths" ]]; then
|
|
952
|
+
append_host_guard_comment "$pr_base_ref" "$remaining_conflict_paths"
|
|
953
|
+
# Keep host-guard notes local when nothing was pushed. Posting them to GitHub
|
|
954
|
+
# makes unchanged PR heads look like successful repairs and can re-queue review.
|
|
955
|
+
require_transition "pr_schedule_retry" pr_schedule_retry "remaining-merge-conflicts-after-no-change-needed"
|
|
956
|
+
require_transition "pr_after_blocked" pr_after_blocked "$pr_number"
|
|
957
|
+
cleanup_pr_session
|
|
958
|
+
result_outcome="blocked"
|
|
959
|
+
result_action="host-rejected-no-change-needed"
|
|
960
|
+
notify_pr_reconciled
|
|
961
|
+
else
|
|
962
|
+
post_pr_comment_if_present
|
|
963
|
+
require_transition "pr_clear_retry" pr_clear_retry
|
|
964
|
+
require_transition "pr_after_succeeded" pr_after_succeeded "$pr_number"
|
|
965
|
+
cleanup_pr_session
|
|
966
|
+
result_action="${result_action:-refreshed-pr-state}"
|
|
967
|
+
notify_pr_reconciled
|
|
968
|
+
fi
|
|
969
|
+
fi
|
|
970
|
+
elif [[ "$status" == "SUCCEEDED" && "$result_outcome" == "blocked" ]]; then
|
|
971
|
+
if attempt_blocked_pr_host_verification_recovery; then
|
|
972
|
+
handle_updated_branch_result
|
|
973
|
+
else
|
|
974
|
+
post_pr_comment_if_present
|
|
975
|
+
require_transition "pr_clear_retry" pr_clear_retry
|
|
976
|
+
require_transition "pr_after_blocked" pr_after_blocked "$pr_number"
|
|
977
|
+
cleanup_pr_session
|
|
978
|
+
result_action="${result_action:-queued-pr-fix}"
|
|
979
|
+
notify_pr_reconciled
|
|
980
|
+
fi
|
|
981
|
+
elif [[ "$status" == "SUCCEEDED" ]]; then
|
|
982
|
+
clear_provider_quota_cooldown
|
|
983
|
+
require_transition "pr_clear_retry" pr_clear_retry
|
|
984
|
+
require_transition "pr_after_succeeded" pr_after_succeeded "$pr_number"
|
|
985
|
+
cleanup_pr_session
|
|
986
|
+
notify_pr_reconciled
|
|
987
|
+
elif [[ "$status" == "FAILED" ]]; then
|
|
988
|
+
schedule_provider_quota_cooldown "${failure_reason:-worker-exit-failed}"
|
|
989
|
+
require_transition "pr_schedule_retry" pr_schedule_retry "${failure_reason:-worker-exit-failed}"
|
|
990
|
+
require_transition "pr_after_failed" pr_after_failed "$pr_number"
|
|
991
|
+
notify_pr_reconciled
|
|
992
|
+
fi
|
|
993
|
+
|
|
994
|
+
mark_reconciled
|
|
995
|
+
printf 'STATUS=%s\n' "$status"
|
|
996
|
+
printf 'PR_NUMBER=%s\n' "$pr_number"
|
|
997
|
+
printf 'PR_STATE=%s\n' "$pr_state"
|
|
998
|
+
printf 'OUTCOME=%s\n' "${result_outcome:-unknown}"
|
|
999
|
+
printf 'ACTION=%s\n' "${result_action:-unknown}"
|
|
1000
|
+
if [[ -n "$failure_reason" ]]; then
|
|
1001
|
+
printf 'FAILURE_REASON=%s\n' "$failure_reason"
|
|
1002
|
+
fi
|
|
1003
|
+
if [[ -n "$pr_result_contract_note" ]]; then
|
|
1004
|
+
printf 'RESULT_CONTRACT_NOTE=%s\n' "$pr_result_contract_note"
|
|
1005
|
+
fi
|