pr-shepherd 0.56.6 → 0.57.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/.claude-plugin/plugin.json +1 -1
- package/README.md +44 -27
- package/bin/api.d.mts +25 -3
- package/bin/api.mjs +51 -13
- package/bin/checks/classify.d.mts +1 -0
- package/bin/checks/classify.mjs +1 -1
- package/bin/checks/conclusions.d.mts +5 -1
- package/bin/checks/conclusions.mjs +8 -2
- package/bin/checks/superseded.d.mts +8 -2
- package/bin/checks/superseded.mjs +24 -7
- package/bin/classify/loader.d.mts +2 -0
- package/bin/classify/loader.mjs +15 -0
- package/bin/classify/standard/author.d.mts +3 -0
- package/bin/classify/standard/author.mjs +10 -0
- package/bin/classify/standard/codecov-report.d.mts +4 -0
- package/bin/classify/standard/codecov-report.mjs +10 -0
- package/bin/classify/standard/coderabbit-notices.d.mts +8 -0
- package/bin/classify/standard/coderabbit-notices.mjs +38 -0
- package/bin/classify/standard/coderabbit-review-summary.d.mts +8 -0
- package/bin/classify/standard/coderabbit-review-summary.mjs +37 -0
- package/bin/classify/standard/codex-notices.d.mts +7 -0
- package/bin/classify/standard/codex-notices.mjs +36 -0
- package/bin/classify/standard/codex-review-summary.d.mts +7 -0
- package/bin/classify/standard/codex-review-summary.mjs +20 -0
- package/bin/classify/standard/dependabot-notices.d.mts +4 -0
- package/bin/classify/standard/dependabot-notices.mjs +15 -0
- package/bin/classify/standard/gemini-notices.d.mts +4 -0
- package/bin/classify/standard/gemini-notices.mjs +13 -0
- package/bin/classify/standard/index.d.mts +4 -0
- package/bin/classify/standard/index.mjs +22 -0
- package/bin/classify/standard/kilo-no-issues.d.mts +4 -0
- package/bin/classify/standard/kilo-no-issues.mjs +17 -0
- package/bin/classify/standard/sourcery-notices.d.mts +8 -0
- package/bin/classify/standard/sourcery-notices.mjs +20 -0
- package/bin/cli/api-usage-formatter.mjs +6 -1
- package/bin/cli/apply-merge-handler.d.mts +3 -0
- package/bin/cli/apply-merge-handler.mjs +73 -0
- package/bin/cli/arg-flags.d.mts +2 -0
- package/bin/cli/arg-flags.mjs +47 -0
- package/bin/cli/args.mjs +10 -41
- package/bin/cli/clean-handler.d.mts +1 -0
- package/bin/cli/clean-handler.mjs +71 -0
- package/bin/cli/default-poll.mjs +3 -0
- package/bin/cli/event-state-scope.d.mts +19 -0
- package/bin/cli/event-state-scope.mjs +60 -0
- package/bin/cli/fix-formatter.mjs +5 -11
- package/bin/cli/handlers.d.mts +0 -1
- package/bin/cli/handlers.mjs +8 -64
- package/bin/cli/help-command-pages.d.mts +62 -18
- package/bin/cli/help-command-pages.mjs +59 -15
- package/bin/cli/help-iterate-poll-pages.d.mts +2 -2
- package/bin/cli/help-iterate-poll-pages.mjs +6 -0
- package/bin/cli/help-log-file-page.d.mts +1 -1
- package/bin/cli/help-log-file-page.mjs +4 -1
- package/bin/cli/help-top-page.d.mts +1 -1
- package/bin/cli/help-top-page.mjs +5 -0
- package/bin/cli/help.d.mts +63 -19
- package/bin/cli/help.mjs +2 -0
- package/bin/cli/iterate-branch-segment.d.mts +2 -0
- package/bin/cli/iterate-branch-segment.mjs +12 -7
- package/bin/cli/iterate-flags.d.mts +7 -1
- package/bin/cli/iterate-flags.mjs +38 -0
- package/bin/cli/iterate-formatter.d.mts +6 -6
- package/bin/cli/iterate-formatter.mjs +56 -22
- package/bin/cli/iterate-instructions.mjs +45 -15
- package/bin/cli/iterate-lean.mjs +39 -14
- package/bin/cli/iterate-merge-formatter.d.mts +6 -0
- package/bin/cli/iterate-merge-formatter.mjs +24 -14
- package/bin/cli/iterate-verbose.mjs +3 -6
- package/bin/cli/list-formatters.mjs +3 -1
- package/bin/cli/mutate-formatter.mjs +10 -5
- package/bin/cli/next-check-format.d.mts +7 -0
- package/bin/cli/next-check-format.mjs +10 -0
- package/bin/cli/playbook-handler.d.mts +5 -0
- package/bin/cli/playbook-handler.mjs +40 -0
- package/bin/cli/poll-handler.mjs +7 -6
- package/bin/cli/poll-summary-formatter.mjs +11 -2
- package/bin/cli/poll-targets.mjs +2 -0
- package/bin/cli/resolve-validators.mjs +2 -2
- package/bin/cli/runner.mjs +6 -1
- package/bin/cli/stack-layer-view.d.mts +33 -0
- package/bin/cli/stack-layer-view.mjs +1 -0
- package/bin/cli/stack-overview.d.mts +10 -28
- package/bin/cli/stack-overview.mjs +39 -14
- package/bin/cli/transport-args.d.mts +5 -0
- package/bin/cli/transport-args.mjs +23 -0
- package/bin/cli/transport-formatter.d.mts +9 -0
- package/bin/cli/transport-formatter.mjs +13 -0
- package/bin/cli-parser.mjs +62 -7
- package/bin/commands/apply-merge-options.d.mts +4 -0
- package/bin/commands/apply-merge-options.mjs +34 -0
- package/bin/commands/apply-merge-output.d.mts +7 -0
- package/bin/commands/apply-merge-output.mjs +20 -0
- package/bin/commands/apply-merge-pull.d.mts +20 -0
- package/bin/commands/apply-merge-pull.mjs +15 -0
- package/bin/commands/apply-merge.d.mts +18 -0
- package/bin/commands/apply-merge.mjs +126 -0
- package/bin/commands/apply-queue-removal.mjs +7 -0
- package/bin/commands/check-annotations.mjs +28 -18
- package/bin/commands/check-execution-context.d.mts +5 -0
- package/bin/commands/check-execution-context.mjs +16 -1
- package/bin/commands/check-fingerprint.d.mts +26 -2
- package/bin/commands/check-fingerprint.mjs +64 -28
- package/bin/commands/check-terminal-report.mjs +11 -1
- package/bin/commands/check-unreported.d.mts +6 -2
- package/bin/commands/check-unreported.mjs +32 -12
- package/bin/commands/check-wait-detectors.d.mts +35 -0
- package/bin/commands/check-wait-detectors.mjs +107 -0
- package/bin/commands/check.d.mts +4 -2
- package/bin/commands/check.mjs +130 -40
- package/bin/commands/event-instructions.d.mts +11 -0
- package/bin/commands/event-instructions.mjs +27 -0
- package/bin/commands/event-mode.d.mts +14 -0
- package/bin/commands/event-mode.mjs +138 -0
- package/bin/commands/iterate/api-usage.mjs +4 -2
- package/bin/commands/iterate/base.mjs +4 -0
- package/bin/commands/iterate/check-blocker-gate.mjs +14 -2
- package/bin/commands/iterate/check-instructions.d.mts +9 -10
- package/bin/commands/iterate/check-instructions.mjs +23 -22
- package/bin/commands/iterate/classify.mjs +19 -5
- package/bin/commands/iterate/escalate.mjs +13 -3
- package/bin/commands/iterate/fix-code.mjs +26 -9
- package/bin/commands/iterate/fix-instruction-threads.d.mts +0 -8
- package/bin/commands/iterate/fix-instruction-threads.mjs +0 -16
- package/bin/commands/iterate/fix-loop-instruction.d.mts +9 -0
- package/bin/commands/iterate/fix-loop-instruction.mjs +35 -0
- package/bin/commands/iterate/helpers.mjs +15 -2
- package/bin/commands/iterate/index.mjs +26 -4
- package/bin/commands/iterate/mark-ready.mjs +50 -10
- package/bin/commands/iterate/merge-plan.d.mts +19 -0
- package/bin/commands/iterate/merge-plan.mjs +88 -0
- package/bin/commands/iterate/merge-state.mjs +3 -0
- package/bin/commands/iterate/merge.d.mts +4 -15
- package/bin/commands/iterate/merge.mjs +18 -51
- package/bin/commands/iterate/merged-base-pull-requests.d.mts +2 -6
- package/bin/commands/iterate/merged-base-pull-requests.mjs +15 -11
- package/bin/commands/iterate/native-stack-rebase.mjs +11 -0
- package/bin/commands/iterate/render.d.mts +8 -2
- package/bin/commands/iterate/render.mjs +28 -42
- package/bin/commands/iterate/stack-trunk-conflict.mjs +17 -1
- package/bin/commands/iterate/stale-ancestry.mjs +4 -1
- package/bin/commands/iterate/stall.d.mts +5 -1
- package/bin/commands/iterate/stall.mjs +19 -7
- package/bin/commands/iterate/thread-mutation-routing.d.mts +1 -0
- package/bin/commands/iterate/thread-mutation-routing.mjs +4 -2
- package/bin/commands/iterate/unreported-required.mjs +5 -2
- package/bin/commands/mark-files-as-viewed.mjs +7 -0
- package/bin/commands/next-check.d.mts +31 -0
- package/bin/commands/next-check.mjs +46 -0
- package/bin/commands/playbook.d.mts +13 -0
- package/bin/commands/playbook.mjs +48 -0
- package/bin/commands/poll-mode.d.mts +8 -0
- package/bin/commands/poll-mode.mjs +14 -0
- package/bin/commands/poll-progress.d.mts +1 -0
- package/bin/commands/poll-progress.mjs +6 -3
- package/bin/commands/poll-quota.d.mts +3 -2
- package/bin/commands/poll-quota.mjs +7 -3
- package/bin/commands/poll-summary-explicit-instructions.d.mts +2 -0
- package/bin/commands/poll-summary-explicit-instructions.mjs +10 -1
- package/bin/commands/poll-summary-instructions.mjs +16 -17
- package/bin/commands/poll-summary.mjs +42 -17
- package/bin/commands/poll.d.mts +0 -1
- package/bin/commands/poll.mjs +11 -19
- package/bin/commands/quota-selection.d.mts +2 -1
- package/bin/commands/quota-selection.mjs +12 -7
- package/bin/commands/resolve-mutate.mjs +33 -5
- package/bin/commands/rest-stack-merge-readiness.d.mts +4 -0
- package/bin/commands/rest-stack-merge-readiness.mjs +74 -0
- package/bin/commands/rule-auto-resolve.mjs +9 -3
- package/bin/commands/shepherd-journal.d.mts +5 -4
- package/bin/commands/shepherd-journal.mjs +9 -8
- package/bin/commands/stack-drain.d.mts +1 -9
- package/bin/commands/stack-drain.mjs +50 -37
- package/bin/commands/stack-handoffs.d.mts +10 -0
- package/bin/commands/stack-handoffs.mjs +25 -0
- package/bin/commands/stack-stall.d.mts +5 -0
- package/bin/commands/stack-stall.mjs +11 -0
- package/bin/commands/stack-work.d.mts +5 -0
- package/bin/commands/stack-work.mjs +32 -0
- package/bin/comments/existing-reply-scan.d.mts +17 -0
- package/bin/comments/existing-reply-scan.mjs +41 -0
- package/bin/comments/rate-limit.mjs +2 -2
- package/bin/comments/resolve.d.mts +7 -1
- package/bin/comments/resolve.mjs +108 -18
- package/bin/comments/rest-reply.d.mts +9 -0
- package/bin/comments/rest-reply.mjs +95 -0
- package/bin/comments/rest-review-mutations.d.mts +22 -0
- package/bin/comments/rest-review-mutations.mjs +125 -0
- package/bin/comments/review-visibility.d.mts +1 -1
- package/bin/comments/review-visibility.mjs +3 -2
- package/bin/comments/sha-poll.mjs +7 -3
- package/bin/comments/thread-visibility.mjs +10 -5
- package/bin/comments/uncertain-replies.d.mts +11 -0
- package/bin/comments/uncertain-replies.mjs +121 -0
- package/bin/comments/uncertain-reply-guards.d.mts +10 -0
- package/bin/comments/uncertain-reply-guards.mjs +94 -0
- package/bin/comments/visible-comments.d.mts +1 -1
- package/bin/comments/visible-comments.mjs +4 -2
- package/bin/config/load.d.mts +37 -1
- package/bin/config/load.mjs +73 -1
- package/bin/config.json +6 -2
- package/bin/exit-codes.d.mts +3 -0
- package/bin/exit-codes.mjs +8 -0
- package/bin/github/api-telemetry-aggregate.d.mts +15 -4
- package/bin/github/api-telemetry-aggregate.mjs +57 -18
- package/bin/github/api-telemetry.d.mts +4 -0
- package/bin/github/api-telemetry.mjs +22 -8
- package/bin/github/apply-review-preflight.d.mts +20 -0
- package/bin/github/apply-review-preflight.mjs +61 -0
- package/bin/github/base-behind-cache.d.mts +15 -0
- package/bin/github/base-behind-cache.mjs +18 -0
- package/bin/github/batch-parse-suites.d.mts +4 -2
- package/bin/github/batch-parse-suites.mjs +6 -1
- package/bin/github/batch-parser-helpers.mjs +40 -2
- package/bin/github/batch-parsers.mjs +1 -0
- package/bin/github/batch-raw-rules.d.mts +26 -0
- package/bin/github/batch-raw-types.d.mts +8 -6
- package/bin/github/batch-stack-evidence.d.mts +28 -0
- package/bin/github/batch-stack-evidence.mjs +62 -0
- package/bin/github/batch.d.mts +15 -2
- package/bin/github/batch.mjs +34 -17
- package/bin/github/check-annotations-batch.d.mts +0 -5
- package/bin/github/check-annotations-batch.mjs +25 -4
- package/bin/github/check-annotations.mjs +3 -1
- package/bin/github/client.d.mts +8 -19
- package/bin/github/client.mjs +45 -13
- package/bin/github/fingerprint-fields.d.mts +8 -0
- package/bin/github/fingerprint-fields.mjs +6 -1
- package/bin/github/fingerprint.d.mts +4 -2
- package/bin/github/fingerprint.mjs +6 -38
- package/bin/github/github-fetch.d.mts +2 -0
- package/bin/github/github-fetch.mjs +19 -0
- package/bin/github/gql/base-behind.gql +3 -0
- package/bin/github/gql/batch-pr-page.gql +16 -0
- package/bin/github/gql/batch-pr.gql +57 -0
- package/bin/github/gql/commit-check-contexts.gql +17 -0
- package/bin/github/gql/get-pr-body.gql +1 -0
- package/bin/github/gql/poll-stack-summary.gql +1 -0
- package/bin/github/gql/poll-summary-check-contexts.gql +5 -0
- package/bin/github/gql/poll-summary-fragment.gql +65 -15
- package/bin/github/gql/stack-handoff-check-runs.gql +42 -0
- package/bin/github/graphql-http.mjs +9 -4
- package/bin/github/graphql-internal-retry.d.mts +2 -0
- package/bin/github/graphql-internal-retry.mjs +1 -1
- package/bin/github/graphql-quota-probe.d.mts +6 -0
- package/bin/github/graphql-quota-probe.mjs +56 -0
- package/bin/github/graphql-session-refusal.d.mts +8 -0
- package/bin/github/graphql-session-refusal.mjs +14 -0
- package/bin/github/http-request.d.mts +1 -1
- package/bin/github/http-request.mjs +22 -6
- package/bin/github/http-utils.mjs +6 -0
- package/bin/github/merge-target-rules.d.mts +12 -3
- package/bin/github/merge-target-rules.mjs +71 -34
- package/bin/github/mutation-policy.d.mts +6 -0
- package/bin/github/mutation-policy.mjs +21 -0
- package/bin/github/poll-summary-annotation-probe.mjs +17 -10
- package/bin/github/poll-summary-check-blockers.d.mts +1 -1
- package/bin/github/poll-summary-check-blockers.mjs +2 -2
- package/bin/github/poll-summary-check-hydration.mjs +25 -10
- package/bin/github/poll-summary-checks.d.mts +2 -2
- package/bin/github/poll-summary-checks.mjs +9 -6
- package/bin/github/poll-summary-command.d.mts +2 -0
- package/bin/github/poll-summary-command.mjs +24 -0
- package/bin/github/poll-summary-fingerprint.d.mts +1 -1
- package/bin/github/poll-summary-fingerprint.mjs +4 -2
- package/bin/github/poll-summary-handoff-fields.d.mts +3 -0
- package/bin/github/poll-summary-handoff-fields.mjs +73 -0
- package/bin/github/poll-summary-projector.d.mts +1 -1
- package/bin/github/poll-summary-projector.mjs +17 -24
- package/bin/github/poll-summary-raw.d.mts +70 -10
- package/bin/github/poll-summary-readiness.mjs +4 -1
- package/bin/github/poll-summary-rest-queue.d.mts +3 -0
- package/bin/github/poll-summary-rest-queue.mjs +12 -0
- package/bin/github/poll-summary-review.d.mts +1 -1
- package/bin/github/poll-summary-review.mjs +23 -11
- package/bin/github/poll-summary-route.mjs +19 -3
- package/bin/github/poll-summary-stack-page.d.mts +11 -0
- package/bin/github/poll-summary-stack-page.mjs +27 -0
- package/bin/github/poll-summary-unreported.d.mts +3 -1
- package/bin/github/poll-summary-unreported.mjs +6 -3
- package/bin/github/poll-summary.d.mts +4 -1
- package/bin/github/poll-summary.mjs +47 -33
- package/bin/github/queries.d.mts +7 -3
- package/bin/github/queries.mjs +8 -4
- package/bin/github/rate-limit-sample.d.mts +7 -0
- package/bin/github/rate-limit-sample.mjs +12 -0
- package/bin/github/reply-recovery-read.d.mts +50 -0
- package/bin/github/reply-recovery-read.mjs +118 -0
- package/bin/github/reply-thread-transcripts.d.mts +0 -1
- package/bin/github/reply-thread-transcripts.mjs +24 -1
- package/bin/github/rest-annotation-read.d.mts +5 -0
- package/bin/github/rest-annotation-read.mjs +44 -0
- package/bin/github/rest-batch-read.d.mts +12 -0
- package/bin/github/rest-batch-read.mjs +57 -0
- package/bin/github/rest-batch-snapshot.d.mts +30 -0
- package/bin/github/rest-batch-snapshot.mjs +115 -0
- package/bin/github/rest-batch-unavailable.d.mts +5 -0
- package/bin/github/rest-batch-unavailable.mjs +16 -0
- package/bin/github/rest-check-read.d.mts +34 -0
- package/bin/github/rest-check-read.mjs +124 -0
- package/bin/github/rest-comment-authorship.d.mts +7 -0
- package/bin/github/rest-comment-authorship.mjs +11 -0
- package/bin/github/rest-conditional-scope.d.mts +20 -0
- package/bin/github/rest-conditional-scope.mjs +44 -0
- package/bin/github/rest-explicit-summary-read.d.mts +3 -0
- package/bin/github/rest-explicit-summary-read.mjs +8 -0
- package/bin/github/rest-feedback-read.d.mts +36 -0
- package/bin/github/rest-feedback-read.mjs +147 -0
- package/bin/github/rest-feedback-validation.d.mts +5 -0
- package/bin/github/rest-feedback-validation.mjs +28 -0
- package/bin/github/rest-http.d.mts +12 -0
- package/bin/github/rest-http.mjs +108 -23
- package/bin/github/rest-identities.d.mts +22 -0
- package/bin/github/rest-identities.mjs +134 -0
- package/bin/github/rest-merge-stack-guard.d.mts +14 -0
- package/bin/github/rest-merge-stack-guard.mjs +41 -0
- package/bin/github/rest-merge.d.mts +29 -0
- package/bin/github/rest-merge.mjs +56 -0
- package/bin/github/rest-merged-base-read.d.mts +9 -0
- package/bin/github/rest-merged-base-read.mjs +48 -0
- package/bin/github/rest-pr-core.d.mts +52 -0
- package/bin/github/rest-pr-core.mjs +60 -0
- package/bin/github/rest-reader-core.d.mts +16 -0
- package/bin/github/rest-reader-core.mjs +154 -0
- package/bin/github/rest-review-read.d.mts +11 -0
- package/bin/github/rest-review-read.mjs +47 -0
- package/bin/github/rest-rules-read.d.mts +9 -0
- package/bin/github/rest-rules-read.mjs +154 -0
- package/bin/github/rest-session-refusal.d.mts +5 -0
- package/bin/github/rest-session-refusal.mjs +21 -0
- package/bin/github/rest-snapshot-context.d.mts +10 -0
- package/bin/github/rest-snapshot-context.mjs +1 -0
- package/bin/github/rest-stack-read.d.mts +21 -0
- package/bin/github/rest-stack-read.mjs +47 -0
- package/bin/github/rest-stack-summary.d.mts +8 -0
- package/bin/github/rest-stack-summary.mjs +62 -0
- package/bin/github/rest-summary-read.d.mts +7 -0
- package/bin/github/rest-summary-read.mjs +112 -0
- package/bin/github/rest-terminal-batch.d.mts +14 -0
- package/bin/github/rest-terminal-batch.mjs +45 -0
- package/bin/github/rest-text.mjs +7 -3
- package/bin/github/rest-thread-read.d.mts +4 -0
- package/bin/github/rest-thread-read.mjs +35 -0
- package/bin/github/rest-viewer-read.d.mts +2 -0
- package/bin/github/rest-viewer-read.mjs +41 -0
- package/bin/github/stack-bottom.d.mts +3 -0
- package/bin/github/stack-bottom.mjs +14 -0
- package/bin/github/stack-handoff-context.d.mts +25 -0
- package/bin/github/stack-handoff-context.mjs +12 -0
- package/bin/github/stack-handoff-page.d.mts +17 -0
- package/bin/github/stack-handoff-page.mjs +306 -0
- package/bin/github/stack-handoff.d.mts +16 -0
- package/bin/github/stack-handoff.mjs +115 -0
- package/bin/github/stack-order.d.mts +6 -0
- package/bin/github/stack-order.mjs +13 -0
- package/bin/github/stack-read.d.mts +7 -5
- package/bin/github/stack-read.mjs +22 -24
- package/bin/github/stack-size-hint.d.mts +3 -0
- package/bin/github/stack-size-hint.mjs +14 -0
- package/bin/github/suggestion-thread.mjs +27 -1
- package/bin/github/thread-comments.mjs +9 -1
- package/bin/github/transport-evidence.d.mts +20 -0
- package/bin/github/transport-evidence.mjs +26 -0
- package/bin/github/transport-mode.d.mts +2 -0
- package/bin/github/transport-mode.mjs +5 -0
- package/bin/github/transport.d.mts +19 -0
- package/bin/github/transport.mjs +126 -0
- package/bin/github/unsupported-rest.d.mts +4 -0
- package/bin/github/unsupported-rest.mjs +7 -0
- package/bin/mcp/server.mjs +52 -3
- package/bin/merge-status/derive.d.mts +2 -0
- package/bin/merge-status/derive.mjs +17 -13
- package/bin/merge-status/required-check-requirements.d.mts +7 -0
- package/bin/merge-status/required-check-requirements.mjs +15 -0
- package/bin/merge-status/requirements-format.d.mts +5 -0
- package/bin/merge-status/requirements-format.mjs +41 -12
- package/bin/merge-status/requirements.mjs +18 -7
- package/bin/state/base.mjs +41 -0
- package/bin/state/durable-state.d.mts +6 -0
- package/bin/state/durable-state.mjs +41 -0
- package/bin/state/graphql-quota-policy.mjs +23 -16
- package/bin/state/merge-request.d.mts +25 -0
- package/bin/state/merge-request.mjs +145 -0
- package/bin/state/pr-fingerprint.d.mts +15 -0
- package/bin/state/pr-fingerprint.mjs +22 -7
- package/bin/state/rest-cache.d.mts +3 -0
- package/bin/state/rest-cache.mjs +1 -0
- package/bin/state/rest-snapshot-report.d.mts +21 -0
- package/bin/state/rest-snapshot-report.mjs +52 -0
- package/bin/state/seen-comments.d.mts +3 -0
- package/bin/state/seen-comments.mjs +18 -0
- package/bin/types/api-usage.d.mts +9 -1
- package/bin/types/escalate.d.mts +1 -1
- package/bin/types/github.d.mts +23 -9
- package/bin/types/iterate.d.mts +24 -2
- package/bin/types/merge-action.d.mts +1 -1
- package/bin/types/merge-requirements.d.mts +7 -7
- package/bin/types/next-check.d.mts +12 -0
- package/bin/types/next-check.mjs +1 -0
- package/bin/types/poll-summary.d.mts +21 -0
- package/bin/types/report.d.mts +13 -1
- package/bin/types/review-thread.d.mts +1 -1
- package/bin/types.d.mts +1 -0
- package/bin/types.mjs +1 -0
- package/package.json +3 -2
- package/plugins/pr-shepherd/.codex-plugin/plugin.json +1 -1
- package/plugins/pr-shepherd/.codex.mcp.json +1 -1
- package/plugins/pr-shepherd/.mcp.json +1 -1
- package/plugins/pr-shepherd/skills/mark-files-as-viewed/SKILL.md +1 -1
- package/plugins/pr-shepherd/skills/pr-shepherd/SKILL.md +14 -51
- package/plugins/pr-shepherd/skills/pr-shepherd/references/ci-failure-triage.md +12 -16
- package/plugins/pr-shepherd/skills/pr-shepherd/references/cloud-event-loop.md +14 -0
- package/plugins/pr-shepherd/skills/pr-shepherd/references/create-pr.md +10 -0
- package/plugins/pr-shepherd/skills/pr-shepherd/references/fix-code-loop.md +10 -0
- package/plugins/pr-shepherd/skills/pr-shepherd/references/mcp-fallback.md +9 -0
- package/plugins/pr-shepherd/skills/reduce-pr-noise/references/classifiers.md +2 -0
- package/bin/github/gql/pr-fingerprint.gql +0 -75
- package/plugins/pr-shepherd/skills/pr-shepherd/references/journal.md +0 -7
- package/plugins/pr-shepherd/skills/pr-shepherd/references/review-mutations.md +0 -9
- package/plugins/pr-shepherd/skills/pr-shepherd/references/stack-merge.md +0 -7
package/bin/commands/check.mjs
CHANGED
|
@@ -2,7 +2,11 @@ import { fetchPrBatch } from "../github/batch.mjs";
|
|
|
2
2
|
import { headArrivalUnix, queueRemovalAppliesToHead } from "../github/queue-removal-freshness.mjs";
|
|
3
3
|
import { readQueueRemovalAcknowledgment, matchesQueueRemovalAcknowledgment, isCiQueueRemovalReason, } from "../state/queue-removal-ack.mjs";
|
|
4
4
|
import { storePrFingerprint } from "../state/pr-fingerprint.mjs";
|
|
5
|
-
import {
|
|
5
|
+
import { storeRestSnapshotReport } from "../state/rest-snapshot-report.mjs";
|
|
6
|
+
import { restSnapshotState, withRestConditionalScope } from "../github/rest-conditional-scope.mjs";
|
|
7
|
+
import { fingerprintReuser, tryReuseRestSnapshotReport } from "./check-fingerprint.mjs";
|
|
8
|
+
import { readWaitDetectors, recordWaitDetectors } from "./check-wait-detectors.mjs";
|
|
9
|
+
import { withTrunkRequiredContexts } from "../merge-status/required-check-requirements.mjs";
|
|
6
10
|
import { collectUnreportedRequired, refreshCachedUnreported } from "./check-unreported.mjs";
|
|
7
11
|
import { getRepoInfo, getCurrentPrNumber } from "../github/client.mjs";
|
|
8
12
|
import { classifyChecks, getCiVerdict } from "../checks/classify.mjs";
|
|
@@ -16,7 +20,10 @@ import { computeStatus } from "./check-status.mjs";
|
|
|
16
20
|
import { annotationMarkerBody, attachAndMergeCheckAnnotations, hasCheckDrivenActionableWork, } from "./check-annotations.mjs";
|
|
17
21
|
import { buildTerminalReport } from "./check-terminal-report.mjs";
|
|
18
22
|
import { isBlockedByFilteredCheck, refreshReadyMergeability, refreshUnknownMergeability, } from "./ready-mergeability.mjs";
|
|
19
|
-
import { loadSeenMap, markSeen, classifyItem } from "../state/seen-comments.mjs";
|
|
23
|
+
import { loadSeenMap, markSeen, classifyItem, mutationWasDenied } from "../state/seen-comments.mjs";
|
|
24
|
+
import { aliasThreadSeenMarkers } from "../github/rest-identities.mjs";
|
|
25
|
+
import { transportReadinessGaps } from "../github/transport-evidence.mjs";
|
|
26
|
+
import { canGenerateGithubMutation } from "../github/mutation-policy.mjs";
|
|
20
27
|
import { threadTranscriptBody } from "../threads/transcript.mjs";
|
|
21
28
|
import { classifyThreadVisibility } from "../comments/thread-visibility.mjs";
|
|
22
29
|
import { classifyReviewsForDisplay, classifyChangesRequestedReviewsForDisplay, } from "../comments/review-visibility.mjs";
|
|
@@ -24,10 +31,21 @@ import { applySuppressedRuleAutoResolve } from "./rule-auto-resolve.mjs";
|
|
|
24
31
|
import { markReviewInlineThreadMarkers } from "../comments/review-thread-markers.mjs";
|
|
25
32
|
import { isConfiguredBotAuthor, isHumanAuthor, normalizeBotUsernames, } from "../comments/authors.mjs";
|
|
26
33
|
import { buildThreadMutationRouting, threadHasAuthorizedMutation, } from "./iterate/thread-mutation-routing.mjs";
|
|
27
|
-
import {
|
|
34
|
+
import { loadClassifyRules } from "../classify/loader.mjs";
|
|
28
35
|
import { buildClassifyIndex, partitionBatch } from "../classify/apply.mjs";
|
|
29
36
|
import { EXIT, ShepherdError } from "../exit-codes.mjs";
|
|
30
37
|
import { getEffectiveCwd } from "../execution-context.mjs";
|
|
38
|
+
function enforceTransportReadiness(status, data) {
|
|
39
|
+
if (status !== "READY" || data.transport !== "rest")
|
|
40
|
+
return status;
|
|
41
|
+
if (data.reviewThreads.some((thread) => thread.isResolved === undefined ||
|
|
42
|
+
thread.isOutdated === undefined ||
|
|
43
|
+
thread.comments === undefined))
|
|
44
|
+
return "UNKNOWN";
|
|
45
|
+
if (transportReadinessGaps(data, data.mergeStateStatus).length > 0)
|
|
46
|
+
return "UNKNOWN";
|
|
47
|
+
return status;
|
|
48
|
+
}
|
|
31
49
|
export async function runCheck(opts, context) {
|
|
32
50
|
const repo = opts.targetRepository ?? (await getRepoInfo());
|
|
33
51
|
const prNumber = opts.prNumber ?? (await getCurrentPrNumber());
|
|
@@ -35,20 +53,48 @@ export async function runCheck(opts, context) {
|
|
|
35
53
|
throw new ShepherdError("No open PR found for current branch. Pass a PR number explicitly.", EXIT.UNAVAILABLE);
|
|
36
54
|
}
|
|
37
55
|
const stateKey = { owner: repo.owner, repo: repo.name, pr: prNumber };
|
|
56
|
+
// Named REST reads in this PR's check are conditional (ETag/304) and cached under its state dir.
|
|
57
|
+
return withRestConditionalScope(stateKey, () => runScopedCheck(opts, context, repo, prNumber, stateKey));
|
|
58
|
+
}
|
|
59
|
+
async function runScopedCheck(opts, context, repo, prNumber, stateKey) {
|
|
38
60
|
const config = loadConfig();
|
|
39
61
|
const reuseFingerprint = opts.fingerprintCache === true;
|
|
40
|
-
if (reuseFingerprint) {
|
|
41
|
-
const cached = await tryReuseFingerprintReport(prNumber, repo, stateKey, config);
|
|
42
|
-
if (cached)
|
|
43
|
-
return refreshCachedUnreported(cached, repo, context);
|
|
44
|
-
}
|
|
45
62
|
const paginateApprovedReviews = config.iterate.minimizeApprovals;
|
|
46
63
|
const includeReceiptSummary = (await context?.wantsReceiptSummary(prNumber, repo)) ?? false;
|
|
47
|
-
|
|
64
|
+
// GraphQL transport: conditional REST change detectors can replay an idle report for free.
|
|
65
|
+
// Changed trunk rules invalidate a cached report; check again without reuse.
|
|
66
|
+
const refreshReused = async (cached, baseTipOid) => (await refreshCachedUnreported(cached, repo, context, baseTipOid)) ??
|
|
67
|
+
runScopedCheck({ ...opts, fingerprintCache: false }, context, repo, prNumber, stateKey);
|
|
68
|
+
const detectors = reuseFingerprint && !includeReceiptSummary
|
|
69
|
+
? await readWaitDetectors(prNumber, repo, stateKey, config)
|
|
70
|
+
: undefined;
|
|
71
|
+
if (detectors && "reused" in detectors)
|
|
72
|
+
return refreshReused(detectors.reused, detectors.baseTipOid);
|
|
73
|
+
const reuse = reuseFingerprint
|
|
74
|
+
? await fingerprintReuser(prNumber, repo, stateKey, config)
|
|
75
|
+
: undefined;
|
|
76
|
+
const batchOptions = {
|
|
48
77
|
paginateApprovedReviews,
|
|
78
|
+
terminalShortCircuit: true,
|
|
49
79
|
...(includeReceiptSummary && { includeReceiptSummary: true }),
|
|
50
|
-
}
|
|
80
|
+
};
|
|
81
|
+
const fetched = reuse
|
|
82
|
+
? await fetchPrBatch(prNumber, repo, batchOptions, reuse)
|
|
83
|
+
: await fetchPrBatch(prNumber, repo, batchOptions);
|
|
84
|
+
if (fetched.stackEvidence)
|
|
85
|
+
context?.seedStack(prNumber, repo, fetched.stackEvidence);
|
|
86
|
+
if ("reused" in fetched) {
|
|
87
|
+
await recordWaitDetectors(stateKey, config, detectors, undefined);
|
|
88
|
+
return refreshReused(fetched.reused, fetched.baseTipOid);
|
|
89
|
+
}
|
|
90
|
+
const result = fetched;
|
|
51
91
|
context?.setReceiptSummary(result.receiptSummary ?? null);
|
|
92
|
+
const restSnapshot = result.data.transport === "rest" ? restSnapshotState() : undefined;
|
|
93
|
+
if (reuseFingerprint) {
|
|
94
|
+
const reused = await tryReuseRestSnapshotReport(stateKey, config, restSnapshot);
|
|
95
|
+
if (reused)
|
|
96
|
+
return refreshReused(reused);
|
|
97
|
+
}
|
|
52
98
|
let batchData = result.data;
|
|
53
99
|
const unknownRefresh = await refreshUnknownMergeability(prNumber, repo, batchData);
|
|
54
100
|
batchData = unknownRefresh.batchData;
|
|
@@ -67,7 +113,18 @@ export async function runCheck(opts, context) {
|
|
|
67
113
|
? []
|
|
68
114
|
: await fetchStartupFailureChecks(repo, batchData.headRefOid, prNumber, stateKey, triageBudget);
|
|
69
115
|
const allChecks = mergeStartupFailureChecks(batchData.checks, startupFailureChecks);
|
|
70
|
-
const
|
|
116
|
+
const unreported = await collectUnreportedRequired({
|
|
117
|
+
batchData,
|
|
118
|
+
checks: allChecks,
|
|
119
|
+
suites: result.headWorkflowSuites ?? [],
|
|
120
|
+
owner: repo.owner,
|
|
121
|
+
name: repo.name,
|
|
122
|
+
pr: prNumber,
|
|
123
|
+
relevantEvents: config.checks.ciTriggerEvents,
|
|
124
|
+
}, context);
|
|
125
|
+
const classifiedPrChecks = classifyChecks(allChecks, {
|
|
126
|
+
requiredContexts: unreported.requiredContexts,
|
|
127
|
+
});
|
|
71
128
|
const latestRemoval = batchData.latestMergeQueueRemoval;
|
|
72
129
|
// `timelineItems(last: 1, ...)` returns the single most recent removal regardless of age, so
|
|
73
130
|
// a PR removed from the queue once, long ago, and never re-added keeps returning that same
|
|
@@ -114,6 +171,7 @@ export async function runCheck(opts, context) {
|
|
|
114
171
|
// synthetic queue-commit source.
|
|
115
172
|
const classifiedQueueChecks = classifyChecks(queueRawChecks, {
|
|
116
173
|
additionalRelevantEvents: ["merge_group"],
|
|
174
|
+
requiredContexts: unreported.requiredContexts,
|
|
117
175
|
});
|
|
118
176
|
const classifiedChecks = [...classifiedPrChecks, ...classifiedQueueChecks];
|
|
119
177
|
const verdict = getCiVerdict(classifiedChecks);
|
|
@@ -129,23 +187,32 @@ export async function runCheck(opts, context) {
|
|
|
129
187
|
triageBudget.throwIfSecondary();
|
|
130
188
|
triageBudget.reportOmissionIfNeeded();
|
|
131
189
|
const seenMap = await loadSeenMap(stateKey);
|
|
190
|
+
await aliasThreadSeenMarkers(repo, prNumber, batchData.reviewThreads.map((thread) => thread.id), seenMap);
|
|
191
|
+
const canGenerateItemMutation = (id, body, capability, operation) => !mutationWasDenied(id, body, seenMap) && canGenerateGithubMutation(capability, operation);
|
|
132
192
|
const botUsernames = normalizeBotUsernames(config.botUsernames);
|
|
133
|
-
const ruleSet = await
|
|
193
|
+
const ruleSet = await loadClassifyRules(getEffectiveCwd(), config.standardRules);
|
|
134
194
|
const classifyIndex = buildClassifyIndex(ruleSet, batchData);
|
|
135
195
|
const partition = partitionBatch(classifyIndex, batchData);
|
|
136
196
|
const merged = await attachAndMergeCheckAnnotations({ passing, failing: triagedBase, skipped, filtered, ignored }, seenMap, prNumber, { stateKey, headSha: batchData.headRefOid });
|
|
137
197
|
const ignoredAnnotated = merged.ignored.filter((c) => (c.annotations?.length ?? 0) > 0);
|
|
138
198
|
const minimizedCommentCandidates = batchData.comments.filter((c) => c.isMinimized && !partition.suppressedCommentIds.has(c.id));
|
|
139
|
-
const deniedRuleAutoResolveCommentIds = new Set(partition.ruleAutoResolveCommentIds.filter((id) => batchData.comments.find((comment) => comment.id === id)?.
|
|
140
|
-
const visibleCommentClassification = classifyVisibleComments(batchData.comments.filter((c) => !partition.suppressedCommentIds.has(c.id) || deniedRuleAutoResolveCommentIds.has(c.id)), seenMap, config.iterate.minimizeComments, botUsernames
|
|
141
|
-
|
|
199
|
+
const deniedRuleAutoResolveCommentIds = new Set(partition.ruleAutoResolveCommentIds.filter((id) => !canGenerateItemMutation(id, batchData.comments.find((comment) => comment.id === id)?.body ?? "", batchData.comments.find((comment) => comment.id === id)?.viewerCanMinimize, "minimize")));
|
|
200
|
+
const visibleCommentClassification = classifyVisibleComments(batchData.comments.filter((c) => !partition.suppressedCommentIds.has(c.id) || deniedRuleAutoResolveCommentIds.has(c.id)), seenMap, config.iterate.minimizeComments, botUsernames, new Set(batchData.comments
|
|
201
|
+
.filter((comment) => mutationWasDenied(comment.id, comment.body, seenMap))
|
|
202
|
+
.map((comment) => comment.id)));
|
|
203
|
+
const deniedRuleAutoResolveThreadIds = new Set(partition.ruleAutoResolveThreadIds.filter((id) => {
|
|
204
|
+
const thread = batchData.reviewThreads.find((candidate) => candidate.id === id);
|
|
205
|
+
return (thread?.isResolved !== false ||
|
|
206
|
+
!canGenerateItemMutation(thread.id, threadTranscriptBody(thread), thread.viewerCanResolve, "resolve"));
|
|
207
|
+
}));
|
|
142
208
|
const visibleThreadCandidates = batchData.reviewThreads.filter((t) => !partition.suppressedThreadIds.has(t.id) || deniedRuleAutoResolveThreadIds.has(t.id));
|
|
143
209
|
const resolveOtherHumanThreads = config.iterate.resolveOtherHumanThreads ?? "none";
|
|
144
210
|
const threadMutationRouting = buildThreadMutationRouting(visibleThreadCandidates, botUsernames, partition.ruleAutoResolveThreadIds, resolveOtherHumanThreads);
|
|
145
211
|
const replyThreadIds = new Set(threadMutationRouting.replyThreadIds);
|
|
146
212
|
const resolveThreadIds = new Set(threadMutationRouting.resolveThreadIds);
|
|
147
213
|
const repeatableThreadIds = new Set(visibleThreadCandidates
|
|
148
|
-
.filter((thread) =>
|
|
214
|
+
.filter((thread) => !mutationWasDenied(thread.id, threadTranscriptBody(thread), seenMap) &&
|
|
215
|
+
threadHasAuthorizedMutation(thread, replyThreadIds, resolveThreadIds))
|
|
149
216
|
.map((thread) => thread.id));
|
|
150
217
|
const threadVisibility = classifyThreadVisibility(visibleThreadCandidates, seenMap, botUsernames, repeatableThreadIds, resolveOtherHumanThreads);
|
|
151
218
|
const firstLookComments = minimizedCommentCandidates.flatMap((c) => {
|
|
@@ -158,7 +225,7 @@ export async function runCheck(opts, context) {
|
|
|
158
225
|
const firstLookSummaries = [];
|
|
159
226
|
const editedSummaries = [];
|
|
160
227
|
const seenSummaries = [];
|
|
161
|
-
const deniedRuleAutoResolveReviewSummaryIds = new Set(partition.ruleAutoResolveReviewSummaryIds.filter((id) => batchData.reviewSummaries.find((review) => review.id === id)?.
|
|
228
|
+
const deniedRuleAutoResolveReviewSummaryIds = new Set(partition.ruleAutoResolveReviewSummaryIds.filter((id) => !canGenerateItemMutation(id, batchData.reviewSummaries.find((review) => review.id === id)?.body ?? "", batchData.reviewSummaries.find((review) => review.id === id)?.viewerCanMinimize, "minimize")));
|
|
162
229
|
const unseenReviewSummaries = batchData.reviewSummaries.filter((r) => !partition.suppressedReviewSummaryIds.has(r.id) ||
|
|
163
230
|
deniedRuleAutoResolveReviewSummaryIds.has(r.id));
|
|
164
231
|
for (const r of unseenReviewSummaries) {
|
|
@@ -167,10 +234,12 @@ export async function runCheck(opts, context) {
|
|
|
167
234
|
firstLookSummaries.push(r);
|
|
168
235
|
else if (cls === "edited")
|
|
169
236
|
editedSummaries.push(r);
|
|
170
|
-
else
|
|
237
|
+
else if (!mutationWasDenied(r.id, r.body, seenMap))
|
|
171
238
|
seenSummaries.push(r);
|
|
172
239
|
}
|
|
173
|
-
const changesRequestedReviewVisibility = classifyChangesRequestedReviewsForDisplay(batchData.changesRequestedReviews.filter((r) => !partition.suppressedChangesRequestedIds.has(r.id)), seenMap, botUsernames, batchData.viewerAuthorization?.viewerCanAdminister
|
|
240
|
+
const changesRequestedReviewVisibility = classifyChangesRequestedReviewsForDisplay(batchData.changesRequestedReviews.filter((r) => !partition.suppressedChangesRequestedIds.has(r.id)), seenMap, botUsernames, canGenerateGithubMutation(batchData.viewerAuthorization?.viewerCanAdminister, "dismiss"), new Set(batchData.changesRequestedReviews
|
|
241
|
+
.filter((review) => mutationWasDenied(review.id, review.body, seenMap))
|
|
242
|
+
.map((review) => review.id)));
|
|
174
243
|
const approvedReviewVisibility = classifyReviewsForDisplay(batchData.approvedReviews, seenMap);
|
|
175
244
|
const changesRequestedReviews = changesRequestedReviewVisibility.visible;
|
|
176
245
|
const visibleChangesRequestedIds = new Set(changesRequestedReviews.map((review) => review.id));
|
|
@@ -179,20 +248,12 @@ export async function runCheck(opts, context) {
|
|
|
179
248
|
return false;
|
|
180
249
|
const isBot = !isHumanAuthor(review) || isConfiguredBotAuthor(review, botUsernames);
|
|
181
250
|
return (!isBot ||
|
|
182
|
-
batchData.viewerAuthorization?.viewerCanAdminister
|
|
251
|
+
canGenerateItemMutation(review.id, review.body, batchData.viewerAuthorization?.viewerCanAdminister, "dismiss") ||
|
|
183
252
|
visibleChangesRequestedIds.has(review.id));
|
|
184
253
|
}).length;
|
|
185
254
|
const approvedReviews = approvedReviewVisibility.visible;
|
|
186
|
-
const unreported = await collectUnreportedRequired({
|
|
187
|
-
batchData,
|
|
188
|
-
checks: allChecks,
|
|
189
|
-
suites: result.headWorkflowSuites ?? [],
|
|
190
|
-
owner: repo.owner,
|
|
191
|
-
name: repo.name,
|
|
192
|
-
pr: prNumber,
|
|
193
|
-
relevantEvents: config.checks.ciTriggerEvents,
|
|
194
|
-
}, context);
|
|
195
255
|
let status = computeStatus(verdict, threadVisibility.activeThreads.length + threadVisibility.resolutionOnlyThreads.length, visibleCommentClassification.actionable.length, mergeStatus, changesRequestedReviewCount, unreported.hasUnreportedRequired);
|
|
256
|
+
status = enforceTransportReadiness(status, batchData);
|
|
196
257
|
// Resolve any pending mergeability refresh (and the resulting MERGED/CLOSED short-circuit)
|
|
197
258
|
// before deciding what to persist below — deferWhileQueued must see the same final,
|
|
198
259
|
// possibly-refreshed mergeStatus that commands/iterate/index.mts acts on, not the pre-refresh
|
|
@@ -203,6 +264,7 @@ export async function runCheck(opts, context) {
|
|
|
203
264
|
batchData = refreshed.batchData;
|
|
204
265
|
mergeStatus = refreshed.mergeStatus;
|
|
205
266
|
status = refreshed.status;
|
|
267
|
+
status = enforceTransportReadiness(status, batchData);
|
|
206
268
|
if (mergeStatus.state === "MERGED" || mergeStatus.state === "CLOSED") {
|
|
207
269
|
const terminal = buildTerminalReport(prNumber, repo, batchData, mergeStatus, mergeStatus.state);
|
|
208
270
|
if (result.fingerprint) {
|
|
@@ -270,9 +332,13 @@ export async function runCheck(opts, context) {
|
|
|
270
332
|
}
|
|
271
333
|
const authorizedPartition = {
|
|
272
334
|
...partition,
|
|
273
|
-
ruleAutoResolveThreadIds: partition.ruleAutoResolveThreadIds.filter((id) =>
|
|
274
|
-
|
|
275
|
-
|
|
335
|
+
ruleAutoResolveThreadIds: partition.ruleAutoResolveThreadIds.filter((id) => {
|
|
336
|
+
const thread = batchData.reviewThreads.find((candidate) => candidate.id === id);
|
|
337
|
+
return (thread?.isResolved === false &&
|
|
338
|
+
canGenerateItemMutation(id, threadTranscriptBody(thread), thread.viewerCanResolve, "resolve"));
|
|
339
|
+
}),
|
|
340
|
+
ruleAutoResolveCommentIds: partition.ruleAutoResolveCommentIds.filter((id) => canGenerateItemMutation(id, batchData.comments.find((comment) => comment.id === id)?.body ?? "", batchData.comments.find((comment) => comment.id === id)?.viewerCanMinimize, "minimize")),
|
|
341
|
+
ruleAutoResolveReviewSummaryIds: partition.ruleAutoResolveReviewSummaryIds.filter((id) => canGenerateItemMutation(id, batchData.reviewSummaries.find((review) => review.id === id)?.body ?? "", batchData.reviewSummaries.find((review) => review.id === id)?.viewerCanMinimize, "minimize")),
|
|
276
342
|
};
|
|
277
343
|
if (opts.autoMinimizeSuppressed === true &&
|
|
278
344
|
(authorizedPartition.ruleAutoResolveThreadIds.length > 0 ||
|
|
@@ -292,6 +358,7 @@ export async function runCheck(opts, context) {
|
|
|
292
358
|
...authorizedRuleAutoResolveThreadIds,
|
|
293
359
|
...[...deniedRuleAutoResolveThreadIds].filter((id) => visibleMutationThreadIds.has(id)),
|
|
294
360
|
];
|
|
361
|
+
mergeStatus = withTrunkRequiredContexts(mergeStatus, unreported.requiredContexts);
|
|
295
362
|
const blockedByFilteredCheck = isBlockedByFilteredCheck(mergeStatus, verdict);
|
|
296
363
|
const queueCommit = batchData.isInMergeQueue
|
|
297
364
|
? batchData.mergeQueueEntry?.headCommitOid
|
|
@@ -303,10 +370,16 @@ export async function runCheck(opts, context) {
|
|
|
303
370
|
const report = {
|
|
304
371
|
pr: prNumber,
|
|
305
372
|
nodeId: batchData.nodeId,
|
|
373
|
+
...(batchData.transport && { transport: batchData.transport }),
|
|
374
|
+
...(batchData.transportUnavailable && {
|
|
375
|
+
transportUnavailable: batchData.transportUnavailable,
|
|
376
|
+
}),
|
|
306
377
|
headSha: batchData.headRefOid,
|
|
307
378
|
headRefName: unreported.headRefName,
|
|
308
379
|
repo: `${repo.owner}/${repo.name}`,
|
|
309
|
-
...(batchData.viewerAuthorization && {
|
|
380
|
+
...(batchData.viewerAuthorization && {
|
|
381
|
+
viewerAuthorization: batchData.viewerAuthorization,
|
|
382
|
+
}),
|
|
310
383
|
status,
|
|
311
384
|
baseBranch: batchData.baseRefName,
|
|
312
385
|
...(batchData.baseRefOid && { baseRefOid: batchData.baseRefOid }),
|
|
@@ -321,8 +394,12 @@ export async function runCheck(opts, context) {
|
|
|
321
394
|
...(ignoredAnnotated.length > 0 && { ignored: ignoredAnnotated }),
|
|
322
395
|
filteredNames: verdict.filteredNames,
|
|
323
396
|
blockedByFilteredCheck,
|
|
324
|
-
...(verdict.ignoredNames.length > 0 && {
|
|
325
|
-
|
|
397
|
+
...(verdict.ignoredNames.length > 0 && {
|
|
398
|
+
ignoredNames: verdict.ignoredNames,
|
|
399
|
+
}),
|
|
400
|
+
...(verdict.supersededNames.length > 0 && {
|
|
401
|
+
supersededNames: verdict.supersededNames,
|
|
402
|
+
}),
|
|
326
403
|
},
|
|
327
404
|
threads: {
|
|
328
405
|
actionable: threadVisibility.activeThreads,
|
|
@@ -358,7 +435,9 @@ export async function runCheck(opts, context) {
|
|
|
358
435
|
mergeQueue: {
|
|
359
436
|
enabled: Boolean(batchData.isMergeQueueEnabled),
|
|
360
437
|
inQueue: Boolean(batchData.isInMergeQueue),
|
|
361
|
-
...(batchData.autoMergeRequest && {
|
|
438
|
+
...(batchData.autoMergeRequest && {
|
|
439
|
+
autoMergeRequest: batchData.autoMergeRequest,
|
|
440
|
+
}),
|
|
362
441
|
...(batchData.mergeQueueEntry && { entry: batchData.mergeQueueEntry }),
|
|
363
442
|
...(batchData.latestMergeQueueRemoval && {
|
|
364
443
|
latestRemoval: batchData.latestMergeQueueRemoval,
|
|
@@ -369,7 +448,9 @@ export async function runCheck(opts, context) {
|
|
|
369
448
|
: batchData.removedMergeQueueChecksIncomplete) && {
|
|
370
449
|
checksIncomplete: true,
|
|
371
450
|
}),
|
|
372
|
-
...(headUpdatedAfterRemoval && {
|
|
451
|
+
...(headUpdatedAfterRemoval && {
|
|
452
|
+
headUpdatedAfterRemoval: true,
|
|
453
|
+
}),
|
|
373
454
|
...(removalsOnHead > 1 && { removalsOnHead }),
|
|
374
455
|
...(removalAcknowledged && { removalAcknowledged: true }),
|
|
375
456
|
},
|
|
@@ -377,15 +458,24 @@ export async function runCheck(opts, context) {
|
|
|
377
458
|
...(unreported.unreportedRequiredChecks && {
|
|
378
459
|
unreportedRequiredChecks: unreported.unreportedRequiredChecks,
|
|
379
460
|
}),
|
|
380
|
-
...(unreported.trunkBehindBy !== undefined && {
|
|
381
|
-
|
|
461
|
+
...(unreported.trunkBehindBy !== undefined && {
|
|
462
|
+
trunkBehindBy: unreported.trunkBehindBy,
|
|
463
|
+
}),
|
|
464
|
+
...(unreported.baseBehindBy !== undefined && {
|
|
465
|
+
baseBehindBy: unreported.baseBehindBy,
|
|
466
|
+
}),
|
|
382
467
|
...(unreported.actionsWorkflowInProgress && {
|
|
383
468
|
actionsWorkflowInProgress: true,
|
|
384
469
|
}),
|
|
385
|
-
...(unreported.stackBottomPr !== undefined && {
|
|
470
|
+
...(unreported.stackBottomPr !== undefined && {
|
|
471
|
+
stackBottomPr: unreported.stackBottomPr,
|
|
472
|
+
}),
|
|
386
473
|
};
|
|
387
474
|
if (result.fingerprint) {
|
|
388
475
|
await storePrFingerprint(stateKey, result.fingerprint, report, config);
|
|
476
|
+
await recordWaitDetectors(stateKey, config, detectors, result.fingerprint);
|
|
389
477
|
}
|
|
478
|
+
if (restSnapshot)
|
|
479
|
+
await storeRestSnapshotReport(stateKey, restSnapshot.digest, report, config);
|
|
390
480
|
return report;
|
|
391
481
|
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { NextCheck } from "../types/next-check.mts";
|
|
2
|
+
/**
|
|
3
|
+
* Steps that replace "iterate immediately" when Shepherd ran in event mode and the PR is
|
|
4
|
+
* waiting: end the turn, keep one wake-up, and let the next tick come from a PR event or the
|
|
5
|
+
* wake-up. Always printed after any state-specific sentence.
|
|
6
|
+
*/
|
|
7
|
+
export declare function eventWaitSteps(next: NextCheck): string[];
|
|
8
|
+
/** Replaces the `[FIX_CODE]` "iterate immediately" line when the tick ran in event mode. */
|
|
9
|
+
export declare function eventFixContinuation(next: NextCheck): string;
|
|
10
|
+
/** One aggregate step: sessions still run first, and only then does the turn end. */
|
|
11
|
+
export declare function eventAggregateStep(next: NextCheck, waiting: boolean): string;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { playbookPointer } from "./playbook-pointer.mjs";
|
|
2
|
+
function wakeUpClause(next) {
|
|
3
|
+
const kind = next.reason === "safety-net" ? "safety-net wake-up" : "wake-up";
|
|
4
|
+
return `Keep exactly one ${kind} at \`${next.at}\` (\`${next.reason}\`).`;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Steps that replace "iterate immediately" when Shepherd ran in event mode and the PR is
|
|
8
|
+
* waiting: end the turn, keep one wake-up, and let the next tick come from a PR event or the
|
|
9
|
+
* wake-up. Always printed after any state-specific sentence.
|
|
10
|
+
*/
|
|
11
|
+
export function eventWaitSteps(next) {
|
|
12
|
+
return [
|
|
13
|
+
`Event mode: end this turn now without sleeping or polling. ${playbookPointer("Cloud event loop")}`,
|
|
14
|
+
`${wakeUpClause(next)} When a PR event or that wake-up arrives, rerun this command with the same options and act only on Shepherd's output, never on the event payload.`,
|
|
15
|
+
];
|
|
16
|
+
}
|
|
17
|
+
/** Replaces the `[FIX_CODE]` "iterate immediately" line when the tick ran in event mode. */
|
|
18
|
+
export function eventFixContinuation(next) {
|
|
19
|
+
return `\`[FIX_CODE]\` is non-terminal. After the steps above, rerun this command once with the same options, then end the turn without sleeping. ${wakeUpClause(next)} ${playbookPointer("Cloud event loop")}`;
|
|
20
|
+
}
|
|
21
|
+
/** One aggregate step: sessions still run first, and only then does the turn end. */
|
|
22
|
+
export function eventAggregateStep(next, waiting) {
|
|
23
|
+
const lead = waiting
|
|
24
|
+
? "Event mode: end this turn now without sleeping or polling."
|
|
25
|
+
: "Event mode: once the steps above are done and the rerun still waits, end the turn without sleeping.";
|
|
26
|
+
return `${lead} ${wakeUpClause(next)} When a PR event or that wake-up arrives, rerun this selector with the same options and act only on Shepherd's output, never on the event payload. ${playbookPointer("Cloud event loop")}`;
|
|
27
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { IterateCommandOptions, IterateResult, PollSummaryCommandOptions, PollSummaryResult } from "../types.mts";
|
|
2
|
+
import { type PollCommandOptions } from "./poll.mts";
|
|
3
|
+
import { type AggregatePollCommandOptions } from "./poll-summary.mts";
|
|
4
|
+
/**
|
|
5
|
+
* One iterate tick. In event mode the tick runs exactly once with no settle window and no
|
|
6
|
+
* sleeping, persists seen markers immediately, and reports when to come back.
|
|
7
|
+
*/
|
|
8
|
+
export declare function runIterateForMode(opts: IterateCommandOptions): Promise<IterateResult>;
|
|
9
|
+
/** One aggregate tick; event mode adds `pollMode` and `nextCheck`. */
|
|
10
|
+
export declare function runPollSummaryForMode(opts: PollSummaryCommandOptions): Promise<PollSummaryResult>;
|
|
11
|
+
/** The default poll command: the sleeping loop in poll mode, one tick in event mode. */
|
|
12
|
+
export declare function runPollForMode(opts: PollCommandOptions): Promise<IterateResult>;
|
|
13
|
+
/** The aggregate poll command: the sleeping loop in poll mode, one tick in event mode. */
|
|
14
|
+
export declare function runAggregatePollForMode(opts: AggregatePollCommandOptions): Promise<PollSummaryResult>;
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { loadConfig } from "../config/load.mjs";
|
|
2
|
+
import { readStallState } from "../state/iterate-stall.mjs";
|
|
3
|
+
import { runWithDurableState } from "../state/durable-state.mjs";
|
|
4
|
+
import { eventAggregateStep, eventFixContinuation } from "./event-instructions.mjs";
|
|
5
|
+
import { earliestNextCheck, MERGE_QUEUE_RECHECK_SECONDS, nextCheckCandidates, SAFETY_NET_SECONDS, } from "./next-check.mjs";
|
|
6
|
+
import { isFixCodeContinuation } from "./iterate/check-instructions.mjs";
|
|
7
|
+
import { isHandedOffSelection } from "./poll-summary-explicit-instructions.mjs";
|
|
8
|
+
import { runIterate } from "./iterate/index.mjs";
|
|
9
|
+
import { resolvePollMode } from "./poll-mode.mjs";
|
|
10
|
+
import { readStackStallDeadline } from "./stack-stall.mjs";
|
|
11
|
+
import { runPoll } from "./poll.mjs";
|
|
12
|
+
import { runAggregatePoll, runPollSummary, } from "./poll-summary.mjs";
|
|
13
|
+
function isEventMode(requested) {
|
|
14
|
+
return resolvePollMode(requested, loadConfig().poll.mode) === "event";
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* One iterate tick. In event mode the tick runs exactly once with no settle window and no
|
|
18
|
+
* sleeping, persists seen markers immediately, and reports when to come back.
|
|
19
|
+
*/
|
|
20
|
+
export function runIterateForMode(opts) {
|
|
21
|
+
if (!isEventMode(opts.pollMode))
|
|
22
|
+
return runIterate(opts);
|
|
23
|
+
return runWithDurableState(() => runIterateEvent(opts));
|
|
24
|
+
}
|
|
25
|
+
/** One aggregate tick; event mode adds `pollMode` and `nextCheck`. */
|
|
26
|
+
export function runPollSummaryForMode(opts) {
|
|
27
|
+
if (!isEventMode(opts.pollMode))
|
|
28
|
+
return runPollSummary(opts);
|
|
29
|
+
const eventOpts = { ...opts, pollMode: "event" };
|
|
30
|
+
return runWithDurableState(async () => withAggregateNextCheck(await runPollSummary(eventOpts), eventOpts));
|
|
31
|
+
}
|
|
32
|
+
/** The default poll command: the sleeping loop in poll mode, one tick in event mode. */
|
|
33
|
+
export function runPollForMode(opts) {
|
|
34
|
+
if (!isEventMode(opts.pollMode))
|
|
35
|
+
return runPoll(opts);
|
|
36
|
+
const { intervalSeconds: _intervalSeconds, timeoutSeconds: _timeoutSeconds, debounceSeconds: _debounceSeconds, quietStatus: _quietStatus, untilTerminal: _untilTerminal, ...tick } = opts;
|
|
37
|
+
return runIterateForMode(tick);
|
|
38
|
+
}
|
|
39
|
+
/** The aggregate poll command: the sleeping loop in poll mode, one tick in event mode. */
|
|
40
|
+
export function runAggregatePollForMode(opts) {
|
|
41
|
+
return isEventMode(opts.pollMode) ? runPollSummaryForMode(opts) : runAggregatePoll(opts);
|
|
42
|
+
}
|
|
43
|
+
async function runIterateEvent(opts) {
|
|
44
|
+
const { pollMode: _pollMode, ...iterateOpts } = opts;
|
|
45
|
+
const sink = {};
|
|
46
|
+
const result = await runIterate({
|
|
47
|
+
...iterateOpts,
|
|
48
|
+
persistSeen: true,
|
|
49
|
+
fingerprintCache: false,
|
|
50
|
+
stallDeadlineSink: sink,
|
|
51
|
+
});
|
|
52
|
+
const nowMs = Date.now();
|
|
53
|
+
const stallDeadlineSeconds = earliestDeadline(await readStallDeadline(result, opts.stallTimeoutSeconds), result.action === "wait" ? sink.ciStartDeadlineSeconds : undefined);
|
|
54
|
+
const nextCheck = earliestNextCheck(nextCheckCandidates({
|
|
55
|
+
action: result.action,
|
|
56
|
+
remainingSeconds: result.remainingSeconds,
|
|
57
|
+
queued: result.mergeQueue?.inQueue === true,
|
|
58
|
+
restMerge: result.action === "merge" && result.merge.mode === "rest",
|
|
59
|
+
stackDraftHold: result.action === "wait" && result.stackDraftHold !== undefined,
|
|
60
|
+
stallDeadlineSeconds,
|
|
61
|
+
}, nowMs), nowMs);
|
|
62
|
+
const tagged = { ...result, pollMode: "event", ...(nextCheck && { nextCheck }) };
|
|
63
|
+
if (tagged.action !== "fix_code" || !nextCheck)
|
|
64
|
+
return tagged;
|
|
65
|
+
return {
|
|
66
|
+
...tagged,
|
|
67
|
+
fix: {
|
|
68
|
+
...tagged.fix,
|
|
69
|
+
instructions: tagged.fix.instructions.map((step) => isFixCodeContinuation(step) ? eventFixContinuation(nextCheck) : step),
|
|
70
|
+
},
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
function earliestDeadline(...deadlines) {
|
|
74
|
+
const known = deadlines.filter((d) => d !== undefined);
|
|
75
|
+
return known.length > 0 ? Math.min(...known) : undefined;
|
|
76
|
+
}
|
|
77
|
+
/** When an unchanged state would trip the stall timeout, or undefined when no timer is running. */
|
|
78
|
+
async function readStallDeadline(result, stallTimeoutSeconds) {
|
|
79
|
+
if (!["wait", "fix_code"].includes(result.action))
|
|
80
|
+
return undefined;
|
|
81
|
+
const timeout = stallTimeoutSeconds ?? loadConfig().iterate.stallTimeoutMinutes * 60;
|
|
82
|
+
const [owner, repo] = result.repo.split("/");
|
|
83
|
+
if (timeout <= 0 || !owner || !repo)
|
|
84
|
+
return undefined;
|
|
85
|
+
const read = await readStallState({ owner, repo, pr: result.pr });
|
|
86
|
+
return read.ok && read.state ? read.state.firstSeenAt + timeout : undefined;
|
|
87
|
+
}
|
|
88
|
+
async function withAggregateNextCheck(result, opts) {
|
|
89
|
+
const tagged = { ...result, pollMode: "event" };
|
|
90
|
+
const stallDeadlineSeconds = await readStackStallDeadline(result, opts.stallTimeoutSeconds ?? loadConfig().iterate.stallTimeoutMinutes * 60);
|
|
91
|
+
const nextCheck = aggregateNextCheck(result, stallDeadlineSeconds);
|
|
92
|
+
if (!nextCheck)
|
|
93
|
+
return tagged;
|
|
94
|
+
const instructions = (result.instructions ?? []).map(withoutPollingCadence);
|
|
95
|
+
const waiting = result.reason === "waiting" || result.reason === "timeout";
|
|
96
|
+
return {
|
|
97
|
+
...tagged,
|
|
98
|
+
nextCheck,
|
|
99
|
+
instructions: [
|
|
100
|
+
...instructions,
|
|
101
|
+
`${instructions.length + 1}. ${eventAggregateStep(nextCheck, waiting)}`,
|
|
102
|
+
],
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Event mode replaces polling: the appended event step owns the next wake-up, so a stack
|
|
107
|
+
* step's "recheck at the configured polling cadence" would contradict it. A pending stack
|
|
108
|
+
* merge resumes on that wake-up instead.
|
|
109
|
+
*/
|
|
110
|
+
function withoutPollingCadence(step) {
|
|
111
|
+
return step
|
|
112
|
+
.replace(/ Recheck(?: them)? at the configured polling cadence\./g, "")
|
|
113
|
+
.replace("rerun that command at the configured cadence to resume its UUID", "rerun that command after the wake-up below to resume its UUID");
|
|
114
|
+
}
|
|
115
|
+
function aggregateNextCheck(result, stallDeadlineSeconds) {
|
|
116
|
+
if (isHandedOffSelection(result) ||
|
|
117
|
+
result.reason === "all_terminal" ||
|
|
118
|
+
result.nextAction === "cancel" ||
|
|
119
|
+
result.nextAction === "escalate") {
|
|
120
|
+
return undefined;
|
|
121
|
+
}
|
|
122
|
+
const candidates = result.prs
|
|
123
|
+
.filter((item) => (item.remainingSeconds ?? 0) > 0)
|
|
124
|
+
.map((item) => ({ reason: "ready-delay", seconds: item.remainingSeconds }));
|
|
125
|
+
// A printed stack merge can stay pending, so recheck it like a REST merge. A mergeable
|
|
126
|
+
// stack that is queued or waiting prints no merge command, so it gets no such wake-up.
|
|
127
|
+
if (result.nextAction === "merge") {
|
|
128
|
+
candidates.push({ reason: "merge-pending", seconds: MERGE_QUEUE_RECHECK_SECONDS });
|
|
129
|
+
}
|
|
130
|
+
candidates.push(result.prs.some((item) => item.isInMergeQueue)
|
|
131
|
+
? { reason: "merge-queue", seconds: MERGE_QUEUE_RECHECK_SECONDS }
|
|
132
|
+
: { reason: "safety-net", seconds: SAFETY_NET_SECONDS });
|
|
133
|
+
const nowMs = Date.now();
|
|
134
|
+
if (stallDeadlineSeconds !== undefined) {
|
|
135
|
+
candidates.push({ reason: "stall-timeout", seconds: stallDeadlineSeconds - nowMs / 1000 });
|
|
136
|
+
}
|
|
137
|
+
return earliestNextCheck(candidates, nowMs);
|
|
138
|
+
}
|
|
@@ -2,6 +2,8 @@ import { loadConfig } from "../../config/load.mjs";
|
|
|
2
2
|
import { summarizeApiTelemetry } from "../../github/api-telemetry.mjs";
|
|
3
3
|
import { selectQuotaWarning } from "../quota-selection.mjs";
|
|
4
4
|
import { buildQuotaAwareContinuation } from "../../quota-warning.mjs";
|
|
5
|
+
import { getGithubTransport } from "../../github/transport.mjs";
|
|
6
|
+
import { isFixCodeContinuation } from "./check-instructions.mjs";
|
|
5
7
|
function shouldWarn(result) {
|
|
6
8
|
return ["wait", "mark_ready", "merge", "fix_code"].includes(result.action);
|
|
7
9
|
}
|
|
@@ -18,7 +20,7 @@ export async function attachApiUsage(result, persistWarning, preservePersistedWa
|
|
|
18
20
|
...band,
|
|
19
21
|
pollIntervalMinutes: Math.max(band.pollIntervalMinutes, minimumPollIntervalMinutes),
|
|
20
22
|
}));
|
|
21
|
-
quotaWarning = await selectQuotaWarning({ owner, repo }, bands, apiUsage, persistWarning);
|
|
23
|
+
quotaWarning = await selectQuotaWarning({ owner, repo }, bands, apiUsage, persistWarning, getGithubTransport());
|
|
22
24
|
}
|
|
23
25
|
}
|
|
24
26
|
const { quotaWarning: _deferredWarning, ...baseResult } = result;
|
|
@@ -32,7 +34,7 @@ export async function attachApiUsage(result, persistWarning, preservePersistedWa
|
|
|
32
34
|
const instructions = [...withWarning.fix.instructions];
|
|
33
35
|
const completion = instructions.at(-1);
|
|
34
36
|
if (completion !== undefined) {
|
|
35
|
-
if (
|
|
37
|
+
if (isFixCodeContinuation(completion)) {
|
|
36
38
|
instructions[instructions.length - 1] = buildQuotaAwareContinuation(quotaWarning, "`[FIX_CODE]` is non-terminal. After completing these steps,");
|
|
37
39
|
}
|
|
38
40
|
}
|
|
@@ -5,6 +5,10 @@ export function buildIterateBase(report, readyState) {
|
|
|
5
5
|
return {
|
|
6
6
|
pr: report.pr,
|
|
7
7
|
repo: report.repo,
|
|
8
|
+
...(report.transport && { transport: report.transport }),
|
|
9
|
+
...(report.transportUnavailable?.length && {
|
|
10
|
+
transportUnavailable: report.transportUnavailable,
|
|
11
|
+
}),
|
|
8
12
|
status: report.status,
|
|
9
13
|
state: report.mergeStatus.state,
|
|
10
14
|
mergeStateStatus: report.mergeStatus.mergeStateStatus,
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { graphql } from "../../github/client.mjs";
|
|
2
2
|
import { pollRateLimitRetryAfterMs } from "../poll-quota.mjs";
|
|
3
3
|
import { clearCheckBlocker, formatCheckBlockerRef, readCheckBlockers, } from "../../state/check-blockers.mjs";
|
|
4
|
+
import { rest } from "../../github/http.mjs";
|
|
5
|
+
import { githubOperation } from "../../github/transport.mjs";
|
|
4
6
|
const RATE_LIMIT = "cost limit nodeCount remaining resetAt used";
|
|
5
7
|
const PULL_QUERY = `query CheckBlockerPull($owner: String!, $name: String!, $number: Int!) {
|
|
6
8
|
_shepherdRateLimit: rateLimit { ${RATE_LIMIT} }
|
|
@@ -78,7 +80,10 @@ async function lookupBlocker(blocker) {
|
|
|
78
80
|
try {
|
|
79
81
|
const vars = { owner: blocker.owner, name: blocker.name, number: blocker.number };
|
|
80
82
|
if (blocker.kind === "issue") {
|
|
81
|
-
const { data } = await graphql(ISSUE_QUERY, vars)
|
|
83
|
+
const { data } = await githubOperation("CheckBlockerIssue", () => graphql(ISSUE_QUERY, vars), async () => {
|
|
84
|
+
const issue = await rest("GET", `/repos/${blocker.owner}/${blocker.name}/issues/${blocker.number}`);
|
|
85
|
+
return { data: { repository: { issue: { state: issue.state.toUpperCase() } } } };
|
|
86
|
+
});
|
|
82
87
|
const issue = data.repository?.issue;
|
|
83
88
|
if (!issue)
|
|
84
89
|
return ignore(blocker, "not found");
|
|
@@ -88,7 +93,14 @@ async function lookupBlocker(blocker) {
|
|
|
88
93
|
return "released";
|
|
89
94
|
return ignore(blocker, `unexpected state ${issue.state}`);
|
|
90
95
|
}
|
|
91
|
-
const { data } = await graphql(PULL_QUERY, vars)
|
|
96
|
+
const { data } = await githubOperation("CheckBlockerPull", () => graphql(PULL_QUERY, vars), async () => {
|
|
97
|
+
const pull = await rest("GET", `/repos/${blocker.owner}/${blocker.name}/pulls/${blocker.number}`);
|
|
98
|
+
return {
|
|
99
|
+
data: {
|
|
100
|
+
repository: { pullRequest: { state: pull.state.toUpperCase(), merged: pull.merged } },
|
|
101
|
+
},
|
|
102
|
+
};
|
|
103
|
+
});
|
|
92
104
|
const pull = data.repository?.pullRequest;
|
|
93
105
|
if (!pull)
|
|
94
106
|
return ignore(blocker, "not found");
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import type { AgentCheck, ResolveCommand, Review } from "../../types.mts";
|
|
2
|
-
/**
|
|
2
|
+
/** The `[FIX_CODE]` recurrence step, whether plain or rewritten by the quota warning. */
|
|
3
|
+
export declare function isFixCodeContinuation(step: string): boolean;
|
|
4
|
+
/** Build the stale-CR step for `## Changes-requested reviews`. Empty when no human CR is stale. */
|
|
3
5
|
export declare function buildCrStaleClause(reviews: Review[]): string;
|
|
4
6
|
/**
|
|
5
7
|
* Build the optional branch-update hint. Empty unless the branch is behind or conflicts with its
|
|
@@ -24,16 +26,13 @@ export declare function buildRepeatedWorkflowBranchRecoveryInstructions(baseBran
|
|
|
24
26
|
hasConflicts: boolean;
|
|
25
27
|
}, stackRebase?: string): string[];
|
|
26
28
|
/**
|
|
27
|
-
* Build the `
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
* Contrast with what *does* stay in the skill's "Review-mutation mechanics" playbook —
|
|
33
|
-
* dismiss-ID retention. The pointer below is load-bearing: without it, nothing in CLI output
|
|
34
|
-
* tells the agent that playbook exists.
|
|
29
|
+
* Build the `apply review` step, with the rendered command inline. The step stays here (not in
|
|
30
|
+
* the skill) because the *as-printed* command is invalid without `$DISMISS_MESSAGE`: an empty
|
|
31
|
+
* `--message` makes `apply review` reject the mutation. `--require-sha` needs no substitution:
|
|
32
|
+
* the rendered command reads the pushed HEAD itself. "Even if you changed no code": the
|
|
33
|
+
* command records each item's disposition either way.
|
|
35
34
|
*/
|
|
36
|
-
export declare function buildResolveCommandInstruction(resolveCommand: ResolveCommand): string[];
|
|
35
|
+
export declare function buildResolveCommandInstruction(resolveCommand: ResolveCommand, rendered: string): string[];
|
|
37
36
|
/** One pointer. Conclusion, rerun, and bare-check rules live in the CI playbook. */
|
|
38
37
|
export declare function buildFailingCheckInstructions(checks: AgentCheck[]): string[];
|
|
39
38
|
/** Update the PR branch after an external blocker merges or closes. Never rerun that job. */
|