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
package/bin/pr-risk.sh
ADDED
|
@@ -0,0 +1,532 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
5
|
+
# shellcheck source=/dev/null
|
|
6
|
+
source "${SCRIPT_DIR}/../tools/bin/flow-config-lib.sh"
|
|
7
|
+
|
|
8
|
+
PR_NUMBER="${1:?usage: pr-risk.sh PR_NUMBER}"
|
|
9
|
+
CONFIG_YAML="$(resolve_flow_config_yaml "${BASH_SOURCE[0]}")"
|
|
10
|
+
MANAGED_PR_PREFIXES_JSON="$(flow_managed_pr_prefixes_json "${CONFIG_YAML}")"
|
|
11
|
+
MANAGED_PR_ISSUE_CAPTURE_REGEX="$(flow_managed_issue_branch_regex "${CONFIG_YAML}")"
|
|
12
|
+
REPO_SLUG="$(flow_resolve_repo_slug "${CONFIG_YAML}")"
|
|
13
|
+
AGENT_ROOT="$(flow_resolve_agent_root "${CONFIG_YAML}")"
|
|
14
|
+
STATE_ROOT="$(flow_resolve_state_root "${CONFIG_YAML}")"
|
|
15
|
+
ALLOW_INFRA_CI_BYPASS="${ACP_ALLOW_INFRA_CI_BYPASS:-${F_LOSNING_ALLOW_INFRA_CI_BYPASS:-1}}"
|
|
16
|
+
LOCAL_FIRST_PR_POLICY="${ACP_LOCAL_FIRST_PR_POLICY:-${F_LOSNING_LOCAL_FIRST_PR_POLICY:-1}}"
|
|
17
|
+
PR_LANE_OVERRIDE_FILE="${STATE_ROOT}/pr-lane-overrides/${PR_NUMBER}.env"
|
|
18
|
+
PR_LANE_OVERRIDE=""
|
|
19
|
+
|
|
20
|
+
if [[ -f "${PR_LANE_OVERRIDE_FILE}" ]]; then
|
|
21
|
+
# shellcheck source=/dev/null
|
|
22
|
+
source "${PR_LANE_OVERRIDE_FILE}" || true
|
|
23
|
+
fi
|
|
24
|
+
|
|
25
|
+
PR_JSON="$(gh pr view "$PR_NUMBER" -R "$REPO_SLUG" --json number,title,url,body,isDraft,headRefName,baseRefName,labels,files,mergeStateStatus,reviewDecision,reviewRequests,statusCheckRollup,comments)"
|
|
26
|
+
PR_HEAD_SHA="$(gh api "repos/${REPO_SLUG}/pulls/${PR_NUMBER}" --jq .head.sha)"
|
|
27
|
+
PR_HEAD_COMMITTED_AT="$(gh api "repos/${REPO_SLUG}/commits/${PR_HEAD_SHA}" --jq .commit.committer.date 2>/dev/null || true)"
|
|
28
|
+
REVIEW_COMMENTS_JSON="$(gh api "repos/${REPO_SLUG}/pulls/${PR_NUMBER}/comments")"
|
|
29
|
+
CHECK_RUNS_JSON="$(gh api "repos/${REPO_SLUG}/commits/${PR_HEAD_SHA}/check-runs" 2>/dev/null || printf '{"check_runs":[]}')"
|
|
30
|
+
|
|
31
|
+
PR_JSON="$PR_JSON" PR_HEAD_SHA="$PR_HEAD_SHA" PR_HEAD_COMMITTED_AT="$PR_HEAD_COMMITTED_AT" REVIEW_COMMENTS_JSON="$REVIEW_COMMENTS_JSON" CHECK_RUNS_JSON="$CHECK_RUNS_JSON" PR_LANE_OVERRIDE="${PR_LANE_OVERRIDE:-}" MANAGED_PR_PREFIXES_JSON="$MANAGED_PR_PREFIXES_JSON" MANAGED_PR_ISSUE_CAPTURE_REGEX="$MANAGED_PR_ISSUE_CAPTURE_REGEX" ALLOW_INFRA_CI_BYPASS="$ALLOW_INFRA_CI_BYPASS" LOCAL_FIRST_PR_POLICY="$LOCAL_FIRST_PR_POLICY" node <<'EOF'
|
|
32
|
+
const { execFileSync } = require('node:child_process');
|
|
33
|
+
const data = JSON.parse(process.env.PR_JSON);
|
|
34
|
+
const reviewComments = JSON.parse(process.env.REVIEW_COMMENTS_JSON || '[]');
|
|
35
|
+
const checkRunsPayload = JSON.parse(process.env.CHECK_RUNS_JSON || '{"check_runs":[]}');
|
|
36
|
+
const checkRuns = checkRunsPayload.check_runs || [];
|
|
37
|
+
const files = (data.files || []).map((file) => file.path);
|
|
38
|
+
const labelNames = (data.labels || []).map((label) => label.name);
|
|
39
|
+
const comments = data.comments || [];
|
|
40
|
+
const reviewRequests = data.reviewRequests || [];
|
|
41
|
+
const checks = data.statusCheckRollup || [];
|
|
42
|
+
const headRefName = String(data.headRefName || '');
|
|
43
|
+
const headSha = String(process.env.PR_HEAD_SHA || '');
|
|
44
|
+
const headCommittedAt = String(process.env.PR_HEAD_COMMITTED_AT || '');
|
|
45
|
+
const allowInfraCiBypass = String(process.env.ALLOW_INFRA_CI_BYPASS || '1') !== '0';
|
|
46
|
+
const localFirstVerificationPolicy = String(process.env.LOCAL_FIRST_PR_POLICY || '1') !== '0';
|
|
47
|
+
const handoffLabelName = 'agent-handoff';
|
|
48
|
+
const managedBranchPrefixes = JSON.parse(process.env.MANAGED_PR_PREFIXES_JSON || '[]');
|
|
49
|
+
const managedIssueBranchRegex = new RegExp(
|
|
50
|
+
String(process.env.MANAGED_PR_ISSUE_CAPTURE_REGEX || '^(?!)$')
|
|
51
|
+
);
|
|
52
|
+
const isAgentBranch = managedBranchPrefixes.some((prefix) => headRefName.startsWith(prefix));
|
|
53
|
+
const hasAgentHandoffLabel = labelNames.includes(handoffLabelName);
|
|
54
|
+
const title = String(data.title || '');
|
|
55
|
+
const laneOverride = String(process.env.PR_LANE_OVERRIDE || '').trim();
|
|
56
|
+
const isBlocked = labelNames.includes('agent-blocked');
|
|
57
|
+
const hasRepairQueuedLabel = labelNames.includes('agent-repair-queued');
|
|
58
|
+
const hasManualFixNeededLabel = labelNames.includes('agent-fix-needed');
|
|
59
|
+
const hasManualFixOverrideLabel = labelNames.includes('agent-manual-fix-override');
|
|
60
|
+
const hasHumanApprovedLabel = labelNames.includes('agent-human-approved');
|
|
61
|
+
const hasDoubleCheckStageOneLabel = labelNames.includes('agent-double-check-1/2');
|
|
62
|
+
const hasDoubleCheckStageTwoLabel = labelNames.includes('agent-double-check-2/2');
|
|
63
|
+
const actionableReviewComments = reviewComments.filter((comment) => {
|
|
64
|
+
const login = String(comment?.user?.login || '');
|
|
65
|
+
const commitId = String(comment?.commit_id || '');
|
|
66
|
+
const body = String(comment?.body || '').trim();
|
|
67
|
+
if (login !== 'chatgpt-codex-connector[bot]') return false;
|
|
68
|
+
if (body.length === 0) return false;
|
|
69
|
+
if (headSha && commitId && commitId !== headSha) return false;
|
|
70
|
+
return true;
|
|
71
|
+
});
|
|
72
|
+
const hasActionableReviewComments = actionableReviewComments.length > 0;
|
|
73
|
+
|
|
74
|
+
const toTimestamp = (value) => {
|
|
75
|
+
const timestamp = Date.parse(String(value || ''));
|
|
76
|
+
return Number.isFinite(timestamp) ? timestamp : null;
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
const headCommittedAtTs = toTimestamp(headCommittedAt);
|
|
80
|
+
const statusComments = comments.filter((comment) =>
|
|
81
|
+
/^## PR (final review blocker|repair worker summary|repair summary|repair update)/i.test(
|
|
82
|
+
String(comment?.body || '').trim(),
|
|
83
|
+
),
|
|
84
|
+
);
|
|
85
|
+
const currentHeadStatusComments = headCommittedAtTs === null
|
|
86
|
+
? statusComments
|
|
87
|
+
: statusComments.filter((comment) => {
|
|
88
|
+
const createdAtTs = toTimestamp(comment?.createdAt);
|
|
89
|
+
if (createdAtTs === null) return true;
|
|
90
|
+
return createdAtTs >= headCommittedAtTs;
|
|
91
|
+
});
|
|
92
|
+
const hasAgentStatusComment = statusComments.length > 0;
|
|
93
|
+
const isManagedByAgent = isAgentBranch || hasAgentHandoffLabel || hasAgentStatusComment;
|
|
94
|
+
|
|
95
|
+
const isLowRiskPath = (filePath) => {
|
|
96
|
+
if (/^packages\/i18n\/src\/resources\/[^/]+\.json$/.test(filePath)) return true;
|
|
97
|
+
if (/^docs\/.+/.test(filePath)) return true;
|
|
98
|
+
if (/^[^/]+\.md$/.test(filePath)) return true;
|
|
99
|
+
return false;
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
const isDocPath = (filePath) =>
|
|
103
|
+
/^openspec\//.test(filePath) ||
|
|
104
|
+
/^docs\/.+/.test(filePath) ||
|
|
105
|
+
/(?:^|\/)README\.md$/i.test(filePath) ||
|
|
106
|
+
/^[^/]+\.md$/i.test(filePath);
|
|
107
|
+
|
|
108
|
+
const isTestPath = (filePath) =>
|
|
109
|
+
/(?:^|\/)__tests__\//.test(filePath) ||
|
|
110
|
+
/(?:^|\/)e2e\//.test(filePath) ||
|
|
111
|
+
/\.(?:spec|test)\.[cm]?[jt]sx?$/.test(filePath);
|
|
112
|
+
|
|
113
|
+
const isLocaleResourcePath = (filePath) =>
|
|
114
|
+
/^packages\/i18n\/src\/resources\/[^/]+\.json$/.test(filePath);
|
|
115
|
+
|
|
116
|
+
const isProductNonTestPath = (filePath) =>
|
|
117
|
+
!isDocPath(filePath) &&
|
|
118
|
+
!isTestPath(filePath) &&
|
|
119
|
+
!isLocaleResourcePath(filePath) &&
|
|
120
|
+
(/^apps\//.test(filePath) || /^packages\//.test(filePath));
|
|
121
|
+
|
|
122
|
+
const isMobileRoutePath = (filePath) =>
|
|
123
|
+
/^apps\/mobile\/app\/.+\.[cm]?[jt]sx?$/.test(filePath) &&
|
|
124
|
+
!isTestPath(filePath);
|
|
125
|
+
|
|
126
|
+
const mobileSurfaceKey = (filePath) => {
|
|
127
|
+
const relative = filePath
|
|
128
|
+
.replace(/^apps\/mobile\/app\//, '')
|
|
129
|
+
.replace(/\.[cm]?[jt]sx?$/, '');
|
|
130
|
+
const segments = relative
|
|
131
|
+
.split('/')
|
|
132
|
+
.filter(Boolean)
|
|
133
|
+
.filter((segment) => !/^\(.+\)$/.test(segment));
|
|
134
|
+
return segments[0] || relative;
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
const isAuthCriticalScopePath = (filePath) => {
|
|
138
|
+
if (/^apps\/api\/src\/modules\/auth\//.test(filePath)) return true;
|
|
139
|
+
if (filePath === 'apps/api/src/entities/user.entity.ts') return true;
|
|
140
|
+
if (/^apps\/api\/src\/migrations\/.*(?:Email|Phone|Auth|User).*\.[cm]?[jt]s$/.test(filePath))
|
|
141
|
+
return true;
|
|
142
|
+
if (/^apps\/api\/src\/common\/utils\/(?:phone|tenant|email|auth)[^/]*\.[cm]?[jt]s$/.test(filePath))
|
|
143
|
+
return true;
|
|
144
|
+
return false;
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
const isAuthAdjacentScopePath = (filePath) => {
|
|
148
|
+
if (isAuthCriticalScopePath(filePath)) return true;
|
|
149
|
+
if (/^apps\/web\/src\/app\/\(auth\)\//.test(filePath)) return true;
|
|
150
|
+
if (/^apps\/api\/src\/modules\/organization\//.test(filePath)) return true;
|
|
151
|
+
return false;
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
const isMobileRegressionPath = (filePath) => {
|
|
155
|
+
if (/^apps\/mobile\/src\/__tests__\/.+/.test(filePath)) return true;
|
|
156
|
+
if (/^apps\/mobile\/src\/lib\/[^/]+\.spec\.ts$/.test(filePath)) return true;
|
|
157
|
+
if (/^apps\/mobile\/app\/profile\/edit\.tsx$/.test(filePath)) return true;
|
|
158
|
+
if (/^apps\/mobile\/app\/settings\/security\.tsx$/.test(filePath)) return true;
|
|
159
|
+
return false;
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
const isMobileRegressionPr =
|
|
163
|
+
/^test\(mobile\):/i.test(title) &&
|
|
164
|
+
files.length > 0 &&
|
|
165
|
+
files.every((filePath) => isLowRiskPath(filePath) || isMobileRegressionPath(filePath));
|
|
166
|
+
|
|
167
|
+
const isCriticalInfraPath = (filePath) => {
|
|
168
|
+
if (/^apps\/api\/src\/migrations\//.test(filePath) || /\.sql$/i.test(filePath)) return true;
|
|
169
|
+
if (/^apps\/api\/src\/.*seed[^/]*\.ts$/i.test(filePath)) return true;
|
|
170
|
+
if (/^apps\/api\/SEEDING\.md$/.test(filePath)) return true;
|
|
171
|
+
if (/^docs\/TESTING_AND_SEED_POLICY\.md$/.test(filePath)) return true;
|
|
172
|
+
if (/^\.github\/workflows\//.test(filePath)) return true;
|
|
173
|
+
if (/^(package\.json|pnpm-lock\.yaml|pnpm-workspace\.yaml|turbo\.json)$/.test(filePath)) return true;
|
|
174
|
+
if (/^scripts\//.test(filePath)) return true;
|
|
175
|
+
return false;
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
const isSystemBreakingPath = (filePath) => {
|
|
179
|
+
if (/^apps\/api\/src\/migrations\//.test(filePath) || /\.sql$/i.test(filePath)) return true;
|
|
180
|
+
if (/^apps\/api\/src\/.*seed[^/]*\.ts$/i.test(filePath)) return true;
|
|
181
|
+
if (/^\.github\/workflows\/(?:release|deploy|go-live|production|hotfix|ship|ios|android)/i.test(filePath)) return true;
|
|
182
|
+
if (/^scripts\/(?:release|deploy|go-live|production|rollback|seed|reseed|reset|migrate)/i.test(filePath)) return true;
|
|
183
|
+
return false;
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
const isCriticalAppPath = (filePath) => {
|
|
187
|
+
if (/^apps\/api\/src\/modules\/auth\//.test(filePath)) return true;
|
|
188
|
+
if (/^apps\/api\/src\/modules\/subscription\//.test(filePath)) return true;
|
|
189
|
+
if (/^apps\/api\/src\/common\/decorators\/current-org\.decorator\.ts$/.test(filePath)) return true;
|
|
190
|
+
if (/^apps\/api\/src\/common\/services\/effective-organization-context\.service\.ts$/.test(filePath)) return true;
|
|
191
|
+
return false;
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
const disallowed = files.filter((filePath) => {
|
|
195
|
+
if (isLowRiskPath(filePath)) return false;
|
|
196
|
+
if (isMobileRegressionPr && isMobileRegressionPath(filePath)) return false;
|
|
197
|
+
return true;
|
|
198
|
+
});
|
|
199
|
+
const criticalInfraFiles = files.filter((filePath) => isCriticalInfraPath(filePath));
|
|
200
|
+
const criticalAppFiles = files.filter((filePath) => !criticalInfraFiles.includes(filePath) && isCriticalAppPath(filePath));
|
|
201
|
+
const systemBreakingFiles = criticalInfraFiles.filter((filePath) => isSystemBreakingPath(filePath));
|
|
202
|
+
const productNonTestFiles = files.filter((filePath) => isProductNonTestPath(filePath));
|
|
203
|
+
const mobileProductFiles = productNonTestFiles.filter((filePath) => /^apps\/mobile\//.test(filePath));
|
|
204
|
+
const localeResourceFiles = files.filter((filePath) => isLocaleResourcePath(filePath));
|
|
205
|
+
const mobileRouteFiles = productNonTestFiles.filter((filePath) => isMobileRoutePath(filePath));
|
|
206
|
+
const mobileSurfaceCount = new Set(mobileRouteFiles.map((filePath) => mobileSurfaceKey(filePath))).size;
|
|
207
|
+
const authCriticalTouched = productNonTestFiles.some((filePath) => isAuthCriticalScopePath(filePath));
|
|
208
|
+
const authMixedScopeFiles = authCriticalTouched
|
|
209
|
+
? productNonTestFiles.filter((filePath) => !isAuthAdjacentScopePath(filePath))
|
|
210
|
+
: [];
|
|
211
|
+
const scopeSplitReasons = [];
|
|
212
|
+
if (productNonTestFiles.length > 14) {
|
|
213
|
+
scopeSplitReasons.push(`product_non_test_count=${productNonTestFiles.length} exceeds max=14`);
|
|
214
|
+
}
|
|
215
|
+
if (mobileProductFiles.length > 8) {
|
|
216
|
+
scopeSplitReasons.push(`mobile_product_count=${mobileProductFiles.length} exceeds max=8`);
|
|
217
|
+
}
|
|
218
|
+
if (localeResourceFiles.length > 8 && productNonTestFiles.length >= 6) {
|
|
219
|
+
scopeSplitReasons.push(
|
|
220
|
+
`locale_resource_count=${localeResourceFiles.length} with product_non_test_count=${productNonTestFiles.length} exceeds mixed-scope limit`,
|
|
221
|
+
);
|
|
222
|
+
}
|
|
223
|
+
if (mobileRouteFiles.length > 3) {
|
|
224
|
+
scopeSplitReasons.push(`mobile_route_file_count=${mobileRouteFiles.length} exceeds max=3`);
|
|
225
|
+
}
|
|
226
|
+
if (mobileSurfaceCount > 2) {
|
|
227
|
+
scopeSplitReasons.push(`mobile_surface_count=${mobileSurfaceCount} exceeds max=2`);
|
|
228
|
+
}
|
|
229
|
+
if (authMixedScopeFiles.length > 0) {
|
|
230
|
+
scopeSplitReasons.push(
|
|
231
|
+
`auth_mixed_scope_count=${authMixedScopeFiles.length} requires a dedicated auth slice`,
|
|
232
|
+
);
|
|
233
|
+
}
|
|
234
|
+
const scopeTooBroad = scopeSplitReasons.length > 0;
|
|
235
|
+
const riskTier =
|
|
236
|
+
criticalInfraFiles.length > 0
|
|
237
|
+
? 'critical-infra'
|
|
238
|
+
: criticalAppFiles.length > 0
|
|
239
|
+
? 'critical-app'
|
|
240
|
+
: disallowed.length === 0
|
|
241
|
+
? 'low'
|
|
242
|
+
: 'high';
|
|
243
|
+
const riskReason =
|
|
244
|
+
riskTier === 'low'
|
|
245
|
+
? isMobileRegressionPr
|
|
246
|
+
? 'file-scope-within-low-risk-mobile-regression-allowlist'
|
|
247
|
+
: 'file-scope-within-low-risk-allowlist'
|
|
248
|
+
: riskTier === 'critical-infra'
|
|
249
|
+
? `paths-within-critical-infra-allowlist:${criticalInfraFiles.join(',')}`
|
|
250
|
+
: riskTier === 'critical-app'
|
|
251
|
+
? `paths-within-critical-app-allowlist:${criticalAppFiles.join(',')}`
|
|
252
|
+
: `paths-outside-low-risk-allowlist:${disallowed.join(',')}`;
|
|
253
|
+
|
|
254
|
+
const pendingChecks = [];
|
|
255
|
+
const checkFailures = [];
|
|
256
|
+
for (const check of checks) {
|
|
257
|
+
if (check.status !== 'COMPLETED') {
|
|
258
|
+
pendingChecks.push(`${check.name}:status-${String(check.status || '').toLowerCase()}`);
|
|
259
|
+
continue;
|
|
260
|
+
}
|
|
261
|
+
const conclusion = String(check.conclusion || '').toUpperCase();
|
|
262
|
+
if (conclusion !== 'SUCCESS' && conclusion !== 'SKIPPED') {
|
|
263
|
+
checkFailures.push(`${check.name}:conclusion-${String(check.conclusion || '').toLowerCase()}`);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
const failingCheckRuns = checkRuns.filter((checkRun) => {
|
|
268
|
+
const status = String(checkRun.status || '').toUpperCase();
|
|
269
|
+
const conclusion = String(checkRun.conclusion || '').toUpperCase();
|
|
270
|
+
return status === 'COMPLETED' && conclusion !== 'SUCCESS' && conclusion !== 'SKIPPED';
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
const infraOnlyMessagePatterns = [
|
|
274
|
+
/recent account payments have failed/i,
|
|
275
|
+
/spending limit needs to be increased/i,
|
|
276
|
+
/job was not started because/i,
|
|
277
|
+
/billing\s*&\s*plans/i,
|
|
278
|
+
/exceeded (your )?spending limit/i,
|
|
279
|
+
];
|
|
280
|
+
|
|
281
|
+
function fetchCheckRunAnnotationMessages(checkRun) {
|
|
282
|
+
const annotationsUrl = String(checkRun?.output?.annotations_url || '');
|
|
283
|
+
const annotationsCount = Number(checkRun?.output?.annotations_count || 0);
|
|
284
|
+
if (!annotationsUrl || !Number.isFinite(annotationsCount) || annotationsCount <= 0) {
|
|
285
|
+
return [];
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
try {
|
|
289
|
+
const raw = execFileSync('gh', ['api', annotationsUrl], {
|
|
290
|
+
encoding: 'utf8',
|
|
291
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
292
|
+
});
|
|
293
|
+
const annotations = JSON.parse(raw || '[]');
|
|
294
|
+
return annotations
|
|
295
|
+
.map((annotation) => String(annotation?.message || '').trim())
|
|
296
|
+
.filter(Boolean);
|
|
297
|
+
} catch {
|
|
298
|
+
return [];
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
const failingCheckRunMessages = failingCheckRuns.flatMap((checkRun) => fetchCheckRunAnnotationMessages(checkRun));
|
|
303
|
+
const hasInfraOnlyCheckFailures =
|
|
304
|
+
allowInfraCiBypass &&
|
|
305
|
+
checkFailures.length > 0 &&
|
|
306
|
+
failingCheckRuns.length > 0 &&
|
|
307
|
+
failingCheckRunMessages.length > 0 &&
|
|
308
|
+
failingCheckRunMessages.every((message) => infraOnlyMessagePatterns.some((pattern) => pattern.test(message)));
|
|
309
|
+
|
|
310
|
+
const effectiveCheckFailures = hasInfraOnlyCheckFailures ? [] : checkFailures;
|
|
311
|
+
|
|
312
|
+
const mergeStateStatus = String(data.mergeStateStatus || '').toUpperCase();
|
|
313
|
+
const hasCleanMergeState = mergeStateStatus === 'CLEAN';
|
|
314
|
+
const hasEffectiveCleanMergeState =
|
|
315
|
+
hasCleanMergeState ||
|
|
316
|
+
(hasInfraOnlyCheckFailures && (mergeStateStatus === 'UNSTABLE' || mergeStateStatus === 'UNKNOWN'));
|
|
317
|
+
const noChecksReported = checks.length === 0;
|
|
318
|
+
const checksOk = pendingChecks.length === 0 && checkFailures.length === 0;
|
|
319
|
+
const effectiveChecksOk = pendingChecks.length === 0 && effectiveCheckFailures.length === 0;
|
|
320
|
+
const noChecksNeutralForManagedPr = localFirstVerificationPolicy && isManagedByAgent;
|
|
321
|
+
const latestAgentStatusComment = [...currentHeadStatusComments].reverse()[0];
|
|
322
|
+
const latestAgentStatusBody = String(latestAgentStatusComment?.body || '');
|
|
323
|
+
const latestAgentStatusIsBlocker = /^## PR final review blocker/i.test(latestAgentStatusBody);
|
|
324
|
+
const latestAgentStatusHasHostGuard =
|
|
325
|
+
/(^|\n)## PR repair host guard/i.test(latestAgentStatusBody) ||
|
|
326
|
+
/Host rejected this repair and did not push it/i.test(latestAgentStatusBody);
|
|
327
|
+
const latestAgentStatusIsCiOnlyBlocker =
|
|
328
|
+
latestAgentStatusIsBlocker &&
|
|
329
|
+
(
|
|
330
|
+
/required verification is not green/i.test(latestAgentStatusBody) ||
|
|
331
|
+
/GitHub check [`'"]?Quality Lite[`'"]? is currently [`'"]?COMPLETED\s*\/\s*FAILURE/i.test(latestAgentStatusBody) ||
|
|
332
|
+
/PR merge state is [`'"]?UNSTABLE[`'"]?/i.test(latestAgentStatusBody) ||
|
|
333
|
+
/PR merge state is [`'"]?UNKNOWN[`'"]?/i.test(latestAgentStatusBody) ||
|
|
334
|
+
/merge-safe state/i.test(latestAgentStatusBody)
|
|
335
|
+
) &&
|
|
336
|
+
!/`(?:apps|packages|openspec|docs|scripts|\.github)\//.test(latestAgentStatusBody);
|
|
337
|
+
const latestAgentStatusIsRepairSummary =
|
|
338
|
+
/^## PR repair (worker summary|summary|update)/i.test(latestAgentStatusBody) &&
|
|
339
|
+
!latestAgentStatusHasHostGuard;
|
|
340
|
+
const hasOutstandingAgentStatusBlocker =
|
|
341
|
+
latestAgentStatusHasHostGuard ||
|
|
342
|
+
(latestAgentStatusIsBlocker && !latestAgentStatusIsCiOnlyBlocker);
|
|
343
|
+
const latestRepairSummaryComment = [...currentHeadStatusComments]
|
|
344
|
+
.reverse()
|
|
345
|
+
.find((comment) => /^## PR repair (worker summary|summary|update)/i.test(String(comment?.body || '').trim()));
|
|
346
|
+
const latestRepairSummaryBody = String(latestRepairSummaryComment?.body || '');
|
|
347
|
+
const hasNoopRepairSummary =
|
|
348
|
+
latestRepairSummaryBody.length > 0 &&
|
|
349
|
+
(
|
|
350
|
+
/already addressed on the current PR head/i.test(latestRepairSummaryBody) ||
|
|
351
|
+
/already contains the review fix/i.test(latestRepairSummaryBody) ||
|
|
352
|
+
/already satisfy those findings/i.test(latestRepairSummaryBody) ||
|
|
353
|
+
/stale PR review\/check metadata/i.test(latestRepairSummaryBody) ||
|
|
354
|
+
/blocked by the local test environment/i.test(latestRepairSummaryBody) ||
|
|
355
|
+
/external workspace\/node_modules baseline issue/i.test(latestRepairSummaryBody) ||
|
|
356
|
+
/no source change was needed/i.test(latestRepairSummaryBody) ||
|
|
357
|
+
/no source change was made/i.test(latestRepairSummaryBody) ||
|
|
358
|
+
/no branch-local source change was needed/i.test(latestRepairSummaryBody) ||
|
|
359
|
+
/no (additional )?(repository|repo|branch|source) change was needed/i.test(latestRepairSummaryBody) ||
|
|
360
|
+
/no code changes? were made/i.test(latestRepairSummaryBody) ||
|
|
361
|
+
/the reported final-review blocker does not reproduce/i.test(latestRepairSummaryBody) ||
|
|
362
|
+
/already fixed on the current PR (branch|head)/i.test(latestRepairSummaryBody) ||
|
|
363
|
+
/blocked by .*worktree.*dependency/i.test(latestRepairSummaryBody) ||
|
|
364
|
+
/dependency provisioning\s*\/\s*module-link state/i.test(latestRepairSummaryBody) ||
|
|
365
|
+
/this worktree'?s dependency state/i.test(latestRepairSummaryBody)
|
|
366
|
+
);
|
|
367
|
+
const hasOutstandingNoopRepairSummary = latestAgentStatusIsRepairSummary && hasNoopRepairSummary;
|
|
368
|
+
const shouldCiRefresh =
|
|
369
|
+
hasOutstandingNoopRepairSummary &&
|
|
370
|
+
effectiveCheckFailures.length > 0 &&
|
|
371
|
+
!hasActionableReviewComments &&
|
|
372
|
+
!data.isDraft;
|
|
373
|
+
const hasManualFixOverride = hasManualFixOverrideLabel;
|
|
374
|
+
const currentDoubleCheckStage =
|
|
375
|
+
(hasDoubleCheckStageTwoLabel || laneOverride === 'double-check-2')
|
|
376
|
+
? 2
|
|
377
|
+
: (hasDoubleCheckStageOneLabel || laneOverride === 'double-check-1')
|
|
378
|
+
? 1
|
|
379
|
+
: 0;
|
|
380
|
+
const requiresHumanReviewOnCiBypass =
|
|
381
|
+
hasInfraOnlyCheckFailures &&
|
|
382
|
+
systemBreakingFiles.length > 0;
|
|
383
|
+
const requiresExplicitHumanApproval =
|
|
384
|
+
systemBreakingFiles.length > 0 || requiresHumanReviewOnCiBypass;
|
|
385
|
+
const requiresAgentDoubleCheck =
|
|
386
|
+
!requiresExplicitHumanApproval &&
|
|
387
|
+
(riskTier === 'critical-infra' || riskTier === 'critical-app');
|
|
388
|
+
|
|
389
|
+
const missingReasons = [];
|
|
390
|
+
if (data.isDraft) missingReasons.push('draft');
|
|
391
|
+
if (reviewRequests.length > 0) missingReasons.push('requested-reviewers-present');
|
|
392
|
+
if (hasOutstandingAgentStatusBlocker) missingReasons.push('agent-status-blocker-present');
|
|
393
|
+
if (scopeTooBroad) missingReasons.push('scope-too-broad');
|
|
394
|
+
if (hasManualFixOverride) missingReasons.push('manual-fix-override');
|
|
395
|
+
if (hasActionableReviewComments && !hasOutstandingNoopRepairSummary) missingReasons.push('review-feedback-present');
|
|
396
|
+
if (requiresExplicitHumanApproval && !hasHumanApprovedLabel) missingReasons.push('system-breaking-risk-scope');
|
|
397
|
+
if (requiresAgentDoubleCheck) {
|
|
398
|
+
if (currentDoubleCheckStage === 2) {
|
|
399
|
+
missingReasons.push('double-check-2-pending');
|
|
400
|
+
} else {
|
|
401
|
+
missingReasons.push('double-check-1-pending');
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
if (noChecksReported && !noChecksNeutralForManagedPr) missingReasons.push('no-checks-reported');
|
|
405
|
+
if (pendingChecks.length > 0) missingReasons.push(...pendingChecks);
|
|
406
|
+
if (effectiveCheckFailures.length > 0) missingReasons.push(...effectiveCheckFailures);
|
|
407
|
+
if (!hasEffectiveCleanMergeState) missingReasons.push(`merge-state-${String(data.mergeStateStatus || '').toLowerCase() || 'unknown'}`);
|
|
408
|
+
|
|
409
|
+
const linkedIssueMatch = String(data.body || '').match(/\b(?:close[sd]?|fix(?:e[sd])?|resolve[sd]?)\s+#(\d+)\b/i);
|
|
410
|
+
const branchIssueMatch = headRefName.match(managedIssueBranchRegex);
|
|
411
|
+
const linkedIssueId = linkedIssueMatch
|
|
412
|
+
? Number(linkedIssueMatch[1])
|
|
413
|
+
: branchIssueMatch
|
|
414
|
+
? Number(branchIssueMatch.groups?.id || branchIssueMatch[1])
|
|
415
|
+
: null;
|
|
416
|
+
|
|
417
|
+
let agentLane = 'ignore';
|
|
418
|
+
if (isManagedByAgent && !data.isDraft) {
|
|
419
|
+
if (isBlocked) {
|
|
420
|
+
agentLane = 'blocked';
|
|
421
|
+
} else if (mergeStateStatus === 'DIRTY') {
|
|
422
|
+
agentLane = 'merge-repair';
|
|
423
|
+
} else if (hasManualFixOverride) {
|
|
424
|
+
agentLane = 'fix';
|
|
425
|
+
} else if (pendingChecks.length > 0) {
|
|
426
|
+
agentLane = 'pending';
|
|
427
|
+
} else if (scopeTooBroad) {
|
|
428
|
+
agentLane = 'fix';
|
|
429
|
+
} else if (hasOutstandingAgentStatusBlocker) {
|
|
430
|
+
agentLane = 'fix';
|
|
431
|
+
} else if ((hasManualFixOverride || hasActionableReviewComments) && !hasOutstandingNoopRepairSummary) {
|
|
432
|
+
agentLane = 'fix';
|
|
433
|
+
} else if (requiresExplicitHumanApproval && !hasHumanApprovedLabel && hasEffectiveCleanMergeState && !hasActionableReviewComments) {
|
|
434
|
+
agentLane = 'human-review';
|
|
435
|
+
} else if (requiresAgentDoubleCheck && hasEffectiveCleanMergeState && !hasActionableReviewComments) {
|
|
436
|
+
agentLane = currentDoubleCheckStage === 2 ? 'double-check-2' : 'double-check-1';
|
|
437
|
+
} else if (shouldCiRefresh) {
|
|
438
|
+
agentLane = 'ci-refresh';
|
|
439
|
+
} else if (missingReasons.length === 0) {
|
|
440
|
+
agentLane = 'automerge';
|
|
441
|
+
} else if (!hasEffectiveCleanMergeState || effectiveCheckFailures.length > 0) {
|
|
442
|
+
agentLane = 'fix';
|
|
443
|
+
} else if (effectiveChecksOk && requiresExplicitHumanApproval) {
|
|
444
|
+
agentLane = 'human-review';
|
|
445
|
+
} else if (effectiveChecksOk && requiresAgentDoubleCheck) {
|
|
446
|
+
agentLane = currentDoubleCheckStage === 2 ? 'double-check-2' : 'double-check-1';
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
if (
|
|
451
|
+
laneOverride &&
|
|
452
|
+
isManagedByAgent &&
|
|
453
|
+
!data.isDraft &&
|
|
454
|
+
!isBlocked &&
|
|
455
|
+
!labelNames.includes('agent-running') &&
|
|
456
|
+
!hasOutstandingAgentStatusBlocker &&
|
|
457
|
+
!hasActionableReviewComments
|
|
458
|
+
) {
|
|
459
|
+
if (laneOverride === 'double-check-2' && requiresAgentDoubleCheck && hasEffectiveCleanMergeState) {
|
|
460
|
+
agentLane = 'double-check-2';
|
|
461
|
+
} else if (laneOverride === 'double-check-1' && requiresAgentDoubleCheck && hasEffectiveCleanMergeState) {
|
|
462
|
+
agentLane = 'double-check-1';
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
const result = {
|
|
467
|
+
number: data.number,
|
|
468
|
+
title: data.title,
|
|
469
|
+
url: data.url,
|
|
470
|
+
headRefName,
|
|
471
|
+
baseRefName: data.baseRefName,
|
|
472
|
+
labels: labelNames,
|
|
473
|
+
risk: riskTier,
|
|
474
|
+
riskTier,
|
|
475
|
+
riskReason,
|
|
476
|
+
linkedIssueId,
|
|
477
|
+
isAgentBranch: isManagedByAgent,
|
|
478
|
+
isManagedByAgent,
|
|
479
|
+
hasAgentHandoffLabel,
|
|
480
|
+
hasAgentStatusComment,
|
|
481
|
+
isBlocked,
|
|
482
|
+
hasRepairQueuedLabel,
|
|
483
|
+
hasManualFixNeededLabel,
|
|
484
|
+
hasManualFixOverrideLabel,
|
|
485
|
+
hasHumanApprovedLabel,
|
|
486
|
+
hasDoubleCheckStageOneLabel,
|
|
487
|
+
hasDoubleCheckStageTwoLabel,
|
|
488
|
+
currentDoubleCheckStage,
|
|
489
|
+
laneOverride,
|
|
490
|
+
hasManualFixOverride,
|
|
491
|
+
headCommittedAt,
|
|
492
|
+
hasActionableReviewComments,
|
|
493
|
+
actionableReviewCommentCount: actionableReviewComments.length,
|
|
494
|
+
actionableReviewCommentUrls: actionableReviewComments.map((comment) => comment.html_url).filter(Boolean),
|
|
495
|
+
isMobileRegressionPr,
|
|
496
|
+
hasRequestedReviewers: reviewRequests.length > 0,
|
|
497
|
+
localFirstVerificationPolicy,
|
|
498
|
+
noChecksReported,
|
|
499
|
+
checksOk,
|
|
500
|
+
effectiveChecksOk,
|
|
501
|
+
pendingChecks,
|
|
502
|
+
checkFailures,
|
|
503
|
+
effectiveCheckFailures,
|
|
504
|
+
checksBypassed: hasInfraOnlyCheckFailures,
|
|
505
|
+
infraOnlyCheckFailureMessages: failingCheckRunMessages,
|
|
506
|
+
systemBreakingFiles,
|
|
507
|
+
requiresExplicitHumanApproval,
|
|
508
|
+
requiresAgentDoubleCheck,
|
|
509
|
+
mergeStateStatus: data.mergeStateStatus,
|
|
510
|
+
hasCleanMergeState,
|
|
511
|
+
hasEffectiveCleanMergeState,
|
|
512
|
+
hasNoopRepairSummary,
|
|
513
|
+
hasOutstandingNoopRepairSummary,
|
|
514
|
+
currentHeadStatusCommentCount: currentHeadStatusComments.length,
|
|
515
|
+
latestAgentStatusIsCiOnlyBlocker,
|
|
516
|
+
hasOutstandingAgentStatusBlocker,
|
|
517
|
+
scopeTooBroad,
|
|
518
|
+
scopeSplitReasons,
|
|
519
|
+
productNonTestCount: productNonTestFiles.length,
|
|
520
|
+
mobileProductCount: mobileProductFiles.length,
|
|
521
|
+
mobileRouteFileCount: mobileRouteFiles.length,
|
|
522
|
+
mobileSurfaceCount,
|
|
523
|
+
localeResourceCount: localeResourceFiles.length,
|
|
524
|
+
shouldCiRefresh,
|
|
525
|
+
eligibleForAutoMerge: missingReasons.length === 0,
|
|
526
|
+
missingReasons,
|
|
527
|
+
agentLane,
|
|
528
|
+
files,
|
|
529
|
+
};
|
|
530
|
+
|
|
531
|
+
process.stdout.write(JSON.stringify(result));
|
|
532
|
+
EOF
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
PR_NUMBER="${1:?usage: sync-pr-labels.sh PR_NUMBER}"
|
|
5
|
+
ADAPTER_BIN_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
6
|
+
FLOW_SKILL_DIR="$(cd "${ADAPTER_BIN_DIR}/.." && pwd)"
|
|
7
|
+
FLOW_TOOLS_DIR="${FLOW_SKILL_DIR}/tools/bin"
|
|
8
|
+
# shellcheck source=/dev/null
|
|
9
|
+
source "${FLOW_TOOLS_DIR}/flow-config-lib.sh"
|
|
10
|
+
|
|
11
|
+
CONFIG_YAML="$(resolve_flow_config_yaml "${BASH_SOURCE[0]}")"
|
|
12
|
+
REPO_SLUG="$(flow_resolve_repo_slug "${CONFIG_YAML}")"
|
|
13
|
+
|
|
14
|
+
ensure_label() {
|
|
15
|
+
local name="${1:?name required}"
|
|
16
|
+
local color="${2:?color required}"
|
|
17
|
+
local description="${3:?description required}"
|
|
18
|
+
gh label edit "$name" -R "$REPO_SLUG" --color "$color" --description "$description" >/dev/null 2>&1 \
|
|
19
|
+
|| gh label create "$name" -R "$REPO_SLUG" --color "$color" --description "$description" >/dev/null 2>&1 \
|
|
20
|
+
|| true
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
ensure_label "agent-repair-queued" "D93F0B" "Agent queued this PR for another automated repair pass before merge"
|
|
24
|
+
ensure_label "agent-manual-fix-override" "9A6700" "Manual override: force one more PR repair pass on the current head"
|
|
25
|
+
ensure_label "agent-ci-refresh" "FBCA04" "Agent confirmed no branch-local repair is needed; host should rerun failed PR checks before another coding pass"
|
|
26
|
+
ensure_label "agent-ci-bypassed" "C2E0C6" "CI failures were classified as infrastructure-only and bypassed by policy for this PR"
|
|
27
|
+
ensure_label "agent-double-check-1/2" "B602FF" "PR needs the first independent agent review pass before merge"
|
|
28
|
+
ensure_label "agent-double-check-2/2" "7D3CFF" "PR passed one independent agent review and needs the second pass before merge"
|
|
29
|
+
ensure_label "agent-human-review" "5319E7" "System-breaking PR such as migrations, destructive data operations, or production release/deploy automation; human review/merge required"
|
|
30
|
+
ensure_label "agent-human-approved" "1D76DB" "Human approved a human-review PR; automation may proceed if no newer blockers appear"
|
|
31
|
+
ensure_label "agent-handoff" "0052CC" "Manual or non-standard PR explicitly handed off to the agent PR lane"
|
|
32
|
+
ensure_label "agent-exclusive" "C2185B" "Exclusive priority item: agent should prioritize it and pause launching unrelated work until it finishes"
|
|
33
|
+
|
|
34
|
+
risk_json="$("${ADAPTER_BIN_DIR}/pr-risk.sh" "$PR_NUMBER")"
|
|
35
|
+
is_managed_by_agent="$(jq -r '.isManagedByAgent' <<<"$risk_json")"
|
|
36
|
+
if [[ "$is_managed_by_agent" != "true" ]]; then
|
|
37
|
+
printf 'PR_NUMBER=%s\n' "$PR_NUMBER"
|
|
38
|
+
printf 'SYNC_STATUS=ignored-non-agent-branch\n'
|
|
39
|
+
exit 0
|
|
40
|
+
fi
|
|
41
|
+
|
|
42
|
+
lane="$(jq -r '.agentLane' <<<"$risk_json")"
|
|
43
|
+
linked_issue_id="$(jq -r '.linkedIssueId // empty' <<<"$risk_json")"
|
|
44
|
+
is_blocked="$(jq -r '.isBlocked' <<<"$risk_json")"
|
|
45
|
+
has_manual_fix_override="$(jq -r '.hasManualFixOverride' <<<"$risk_json")"
|
|
46
|
+
eligible_for_automerge="$(jq -r '.eligibleForAutoMerge' <<<"$risk_json")"
|
|
47
|
+
risk_tier="$(jq -r '.riskTier // .risk' <<<"$risk_json")"
|
|
48
|
+
checks_bypassed="$(jq -r '.checksBypassed // false' <<<"$risk_json")"
|
|
49
|
+
linked_issue_is_exclusive="false"
|
|
50
|
+
|
|
51
|
+
if [[ -n "$linked_issue_id" ]]; then
|
|
52
|
+
issue_json="$(gh issue view "$linked_issue_id" -R "$REPO_SLUG" --json labels 2>/dev/null || true)"
|
|
53
|
+
if [[ -n "$issue_json" ]] && jq -e 'any(.labels[]?; .name == "agent-exclusive")' >/dev/null <<<"$issue_json"; then
|
|
54
|
+
linked_issue_is_exclusive="true"
|
|
55
|
+
fi
|
|
56
|
+
fi
|
|
57
|
+
|
|
58
|
+
args=()
|
|
59
|
+
if [[ "$is_blocked" == "true" ]]; then
|
|
60
|
+
args+=(--remove agent-automerge --remove agent-repair-queued --remove agent-fix-needed --remove agent-ci-refresh --remove agent-ci-bypassed --remove agent-double-check-1/2 --remove agent-double-check-2/2 --remove agent-human-review --remove agent-human-approved)
|
|
61
|
+
elif [[ "$eligible_for_automerge" == "true" ]]; then
|
|
62
|
+
args+=(--add agent-automerge)
|
|
63
|
+
else
|
|
64
|
+
args+=(--remove agent-automerge)
|
|
65
|
+
fi
|
|
66
|
+
|
|
67
|
+
if [[ "$checks_bypassed" == "true" ]]; then
|
|
68
|
+
args+=(--add agent-ci-bypassed)
|
|
69
|
+
else
|
|
70
|
+
args+=(--remove agent-ci-bypassed)
|
|
71
|
+
fi
|
|
72
|
+
|
|
73
|
+
if [[ "$linked_issue_is_exclusive" == "true" ]]; then
|
|
74
|
+
args+=(--add agent-exclusive)
|
|
75
|
+
fi
|
|
76
|
+
|
|
77
|
+
if [[ "$is_blocked" != "true" ]]; then
|
|
78
|
+
case "$lane" in
|
|
79
|
+
fix)
|
|
80
|
+
args+=(--add agent-repair-queued --remove agent-fix-needed --remove agent-ci-refresh --remove agent-double-check-1/2 --remove agent-double-check-2/2 --remove agent-human-review --remove agent-human-approved)
|
|
81
|
+
;;
|
|
82
|
+
ci-refresh)
|
|
83
|
+
args+=(--add agent-ci-refresh --remove agent-repair-queued --remove agent-fix-needed --remove agent-double-check-1/2 --remove agent-double-check-2/2 --remove agent-human-review --remove agent-human-approved)
|
|
84
|
+
;;
|
|
85
|
+
double-check-1)
|
|
86
|
+
args+=(--add agent-double-check-1/2 --remove agent-double-check-2/2 --remove agent-repair-queued --remove agent-fix-needed --remove agent-ci-refresh --remove agent-human-review --remove agent-human-approved)
|
|
87
|
+
;;
|
|
88
|
+
double-check-2)
|
|
89
|
+
args+=(--add agent-double-check-2/2 --remove agent-double-check-1/2 --remove agent-repair-queued --remove agent-fix-needed --remove agent-ci-refresh --remove agent-human-review --remove agent-human-approved)
|
|
90
|
+
;;
|
|
91
|
+
human-review)
|
|
92
|
+
args+=(--add agent-human-review --remove agent-double-check-1/2 --remove agent-double-check-2/2 --remove agent-repair-queued --remove agent-fix-needed --remove agent-ci-refresh)
|
|
93
|
+
;;
|
|
94
|
+
*)
|
|
95
|
+
args+=(--remove agent-repair-queued --remove agent-fix-needed --remove agent-ci-refresh --remove agent-double-check-1/2 --remove agent-double-check-2/2 --remove agent-human-review --remove agent-human-approved)
|
|
96
|
+
;;
|
|
97
|
+
esac
|
|
98
|
+
fi
|
|
99
|
+
|
|
100
|
+
bash "${FLOW_TOOLS_DIR}/agent-github-update-labels" --repo-slug "$REPO_SLUG" --number "$PR_NUMBER" "${args[@]}" >/dev/null
|
|
101
|
+
|
|
102
|
+
if [[ -n "$linked_issue_id" ]]; then
|
|
103
|
+
bash "${FLOW_TOOLS_DIR}/agent-github-update-labels" --repo-slug "$REPO_SLUG" --number "$linked_issue_id" --remove agent-ready --remove agent-running >/dev/null || true
|
|
104
|
+
fi
|
|
105
|
+
|
|
106
|
+
printf 'PR_NUMBER=%s\n' "$PR_NUMBER"
|
|
107
|
+
printf 'SYNC_STATUS=ok\n'
|
|
108
|
+
printf 'RISK=%s\n' "$risk_tier"
|
|
109
|
+
printf 'AGENT_LANE=%s\n' "$lane"
|
|
110
|
+
printf 'LINKED_ISSUE_ID=%s\n' "$linked_issue_id"
|
|
111
|
+
printf 'IS_BLOCKED=%s\n' "$is_blocked"
|
|
112
|
+
printf 'MANUAL_FIX_OVERRIDE=%s\n' "$has_manual_fix_override"
|