pr-shepherd 0.56.5 → 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 +40 -19
- 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.d.mts +6 -5
- package/bin/commands/iterate/native-stack-rebase.mjs +24 -7
- package/bin/commands/iterate/render.d.mts +8 -2
- package/bin/commands/iterate/render.mjs +28 -42
- package/bin/commands/iterate/stack-trunk-conflict.d.mts +4 -2
- package/bin/commands/iterate/stack-trunk-conflict.mjs +44 -19
- 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/gql/upper-layer-conflict-target.gql +0 -15
- 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 +16 -3
- package/bin/github/merge-target-rules.mjs +79 -44
- 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 +6 -3
- package/bin/github/poll-summary-unreported.mjs +15 -7
- package/bin/github/poll-summary.d.mts +4 -1
- package/bin/github/poll-summary.mjs +48 -34
- package/bin/github/queries.d.mts +9 -5
- package/bin/github/queries.mjs +10 -6
- 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 -3
- package/bin/github/stack-read.mjs +22 -11
- 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
|
@@ -1,38 +1,55 @@
|
|
|
1
|
+
import { githubOperation } from "./transport.mjs";
|
|
2
|
+
import { readRestBehind } from "./rest-check-read.mjs";
|
|
3
|
+
import { readRestBranchRules } from "./rest-rules-read.mjs";
|
|
1
4
|
import { EXIT, ShepherdError } from "../exit-codes.mjs";
|
|
2
5
|
import { parseBranchRules } from "./batch-parsers-rules.mjs";
|
|
3
6
|
import { graphqlWithRateLimit } from "./client.mjs";
|
|
4
7
|
import { missingRepositoryError } from "./errors.mjs";
|
|
8
|
+
import { cachedBaseBehind, storeBaseBehind, } from "./base-behind-cache.mjs";
|
|
5
9
|
import { BASE_BEHIND_QUERY, REF_RULES_QUERY } from "./queries.mjs";
|
|
6
|
-
import { readStackTopology } from "./stack-read.mjs";
|
|
10
|
+
import { readStackTopology, verifiedBottomOpenLayer } from "./stack-read.mjs";
|
|
7
11
|
/**
|
|
8
12
|
* Required status contexts for the branch GitHub actually merges into.
|
|
9
|
-
* A native stack uses the trunk ref, and `
|
|
13
|
+
* A native stack uses the trunk ref, and `trunkBehindBy` compares that trunk against the bottom
|
|
14
|
+
* open layer. The trunk rules and the stack topology come from this tick's `BatchPr` when the
|
|
15
|
+
* context holds them; otherwise `RefRules` and `PollStackTopology` read them.
|
|
10
16
|
*/
|
|
11
17
|
export async function loadMergeTargetStatus(input, context) {
|
|
12
18
|
const trunk = input.stack?.baseRefName;
|
|
13
19
|
if (!trunk)
|
|
14
20
|
return { contexts: [...input.localContexts] };
|
|
15
|
-
|
|
21
|
+
const repo = { owner: input.owner, name: input.name };
|
|
22
|
+
let headRef = input.headRefOid || input.headRefName;
|
|
16
23
|
let stackBottomPr = input.pr;
|
|
17
24
|
if (trunk !== input.baseRefName) {
|
|
18
|
-
const bottom = await bottomOpenLayer(input.pr,
|
|
19
|
-
headRef = bottom.
|
|
25
|
+
const bottom = await bottomOpenLayer(input.pr, repo, context);
|
|
26
|
+
headRef = bottom.headRefOid;
|
|
20
27
|
stackBottomPr = bottom.number;
|
|
21
28
|
}
|
|
22
|
-
const
|
|
29
|
+
const embedded = context?.trunkRules(input.pr, repo, trunk);
|
|
30
|
+
if (embedded) {
|
|
31
|
+
return {
|
|
32
|
+
contexts: embedded.contexts,
|
|
33
|
+
trunkBehindBy: () => loadBaseBehindBy(input.owner, input.name, trunk, headRef, {
|
|
34
|
+
stateKey: { owner: input.owner, repo: input.name, pr: input.pr },
|
|
35
|
+
slot: "trunk-behind",
|
|
36
|
+
...(embedded.tipOid && { baseTipOid: embedded.tipOid }),
|
|
37
|
+
}),
|
|
38
|
+
stackBottomPr,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
const loaded = await loadRefRules(input.owner, input.name, `refs/heads/${trunk}`, headRef);
|
|
23
42
|
return {
|
|
24
43
|
contexts: loaded.contexts,
|
|
25
|
-
|
|
44
|
+
trunkBehindBy: () => Promise.resolve(loaded.behindBy),
|
|
26
45
|
stackBottomPr,
|
|
27
46
|
};
|
|
28
47
|
}
|
|
29
|
-
async function bottomOpenLayer(pr, repo,
|
|
48
|
+
async function bottomOpenLayer(pr, repo, context) {
|
|
30
49
|
const topology = await (context?.readStackTopology(pr, repo) ?? readStackTopology(pr, repo));
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
}
|
|
35
|
-
return bottom;
|
|
50
|
+
// GitHub can retain a merged parent's branch as the lowest open layer's
|
|
51
|
+
// base. Stack order, rather than retargeting, determines the review target.
|
|
52
|
+
return verifiedBottomOpenLayer(topology.ordered, pr);
|
|
36
53
|
}
|
|
37
54
|
/**
|
|
38
55
|
* Commits on the PR base that `headRef` does not contain.
|
|
@@ -41,37 +58,55 @@ async function bottomOpenLayer(pr, repo, trunk, context) {
|
|
|
41
58
|
* `mergeStateStatus` stays `BLOCKED` when a conversation or an expected check
|
|
42
59
|
* is also open, so this compare is the behind count that status hides.
|
|
43
60
|
*/
|
|
44
|
-
export async function loadBaseBehindBy(owner, name, baseRefName, headRef) {
|
|
45
|
-
const
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
qualifiedName
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
61
|
+
export async function loadBaseBehindBy(owner, name, baseRefName, headRef, cache) {
|
|
62
|
+
const cached = await cachedBaseBehind(cache, headRef);
|
|
63
|
+
if (cached !== undefined)
|
|
64
|
+
return cached;
|
|
65
|
+
return githubOperation("BaseBehind", async () => {
|
|
66
|
+
const qualifiedName = `refs/heads/${baseRefName}`;
|
|
67
|
+
const { data } = await graphqlWithRateLimit(BASE_BEHIND_QUERY, {
|
|
68
|
+
owner,
|
|
69
|
+
repo: name,
|
|
70
|
+
qualifiedName,
|
|
71
|
+
headRef,
|
|
72
|
+
});
|
|
73
|
+
if (!data.repository)
|
|
74
|
+
throw missingRepositoryError({ owner, name });
|
|
75
|
+
const ref = data.repository.ref;
|
|
76
|
+
if (!ref) {
|
|
77
|
+
throw new ShepherdError(`Branch ${qualifiedName} was not found in ${owner}/${name}`, EXIT.TEMPFAIL);
|
|
78
|
+
}
|
|
79
|
+
if (!ref.compare)
|
|
80
|
+
return 0;
|
|
81
|
+
await storeBaseBehind(cache, ref.target?.oid, headRef, ref.compare.behindBy);
|
|
82
|
+
return ref.compare.behindBy;
|
|
83
|
+
}, () => readRestBehind({ owner, name }, baseRefName, headRef));
|
|
59
84
|
}
|
|
60
|
-
async function
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
85
|
+
export async function loadRefRules(owner, name, qualifiedName, headRef) {
|
|
86
|
+
return githubOperation("RefRules", async () => {
|
|
87
|
+
const { data } = await graphqlWithRateLimit(REF_RULES_QUERY, {
|
|
88
|
+
owner,
|
|
89
|
+
repo: name,
|
|
90
|
+
qualifiedName,
|
|
91
|
+
headRef,
|
|
92
|
+
});
|
|
93
|
+
if (!data.repository)
|
|
94
|
+
throw missingRepositoryError({ owner, name });
|
|
95
|
+
const ref = data.repository.ref;
|
|
96
|
+
if (!ref) {
|
|
97
|
+
throw new ShepherdError(`Branch ${qualifiedName} was not found in ${owner}/${name}`, EXIT.TEMPFAIL);
|
|
98
|
+
}
|
|
99
|
+
return {
|
|
100
|
+
contexts: parseBranchRules(ref).requiredStatusCheckContexts,
|
|
101
|
+
behindBy: ref.compare?.behindBy ?? 0,
|
|
102
|
+
};
|
|
103
|
+
}, async () => {
|
|
104
|
+
const rules = await readRestBranchRules({ owner, name }, qualifiedName.replace(/^refs\/heads\//, ""));
|
|
105
|
+
if (rules.unavailable.length > 0)
|
|
106
|
+
throw new ShepherdError(rules.unavailable.map((item) => item.reason).join("; "), EXIT.UNAVAILABLE);
|
|
107
|
+
return {
|
|
108
|
+
contexts: parseBranchRules(rules.baseRef).requiredStatusCheckContexts,
|
|
109
|
+
behindBy: await readRestBehind({ owner, name }, qualifiedName.replace(/^refs\/heads\//, ""), headRef),
|
|
110
|
+
};
|
|
66
111
|
});
|
|
67
|
-
if (!data.repository)
|
|
68
|
-
throw missingRepositoryError({ owner, name });
|
|
69
|
-
const ref = data.repository.ref;
|
|
70
|
-
if (!ref) {
|
|
71
|
-
throw new ShepherdError(`Branch ${qualifiedName} was not found in ${owner}/${name}`, EXIT.TEMPFAIL);
|
|
72
|
-
}
|
|
73
|
-
return {
|
|
74
|
-
contexts: parseBranchRules(ref).requiredStatusCheckContexts,
|
|
75
|
-
behindBy: ref.compare?.behindBy ?? 0,
|
|
76
|
-
};
|
|
77
112
|
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export type GithubMutationOperation = "reply" | "resolve" | "dismiss" | "ready" | "minimize" | "view";
|
|
2
|
+
/**
|
|
3
|
+
* Whether iterate may generate a mutation from the capability data available on
|
|
4
|
+
* this transport. Explicit `apply` requests do not use this policy.
|
|
5
|
+
*/
|
|
6
|
+
export declare function canGenerateGithubMutation(capability: boolean | undefined, operation: GithubMutationOperation): boolean;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { getGithubTransport, isCcrTransport } from "./transport.mjs";
|
|
2
|
+
/**
|
|
3
|
+
* Whether iterate may generate a mutation from the capability data available on
|
|
4
|
+
* this transport. Explicit `apply` requests do not use this policy.
|
|
5
|
+
*/
|
|
6
|
+
export function canGenerateGithubMutation(capability, operation) {
|
|
7
|
+
if (capability === false)
|
|
8
|
+
return false;
|
|
9
|
+
const transport = getGithubTransport();
|
|
10
|
+
if (transport === "graphql")
|
|
11
|
+
return capability === true;
|
|
12
|
+
if (operation === "minimize" || operation === "view")
|
|
13
|
+
return false;
|
|
14
|
+
if (operation === "resolve" || operation === "ready")
|
|
15
|
+
return isCcrTransport();
|
|
16
|
+
if (capability === true)
|
|
17
|
+
return true;
|
|
18
|
+
if (operation === "reply" || operation === "dismiss")
|
|
19
|
+
return true;
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { githubOperation } from "./transport.mjs";
|
|
2
|
+
import { readRestAnnotationCounts } from "./rest-check-read.mjs";
|
|
1
3
|
import { graphqlWithRateLimit } from "./client.mjs";
|
|
2
4
|
import { isCurrentSummaryReady } from "./poll-summary-readiness.mjs";
|
|
3
5
|
import { summarizePollSummaryChecks } from "./poll-summary-checks.mjs";
|
|
@@ -78,16 +80,21 @@ async function collectProbePages(oid, repo) {
|
|
|
78
80
|
}
|
|
79
81
|
async function fetchProbePage(oid, repo, before) {
|
|
80
82
|
try {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
83
|
+
return await githubOperation("PollSummaryAnnotationProbe", async () => {
|
|
84
|
+
const { data } = await graphqlWithRateLimit(POLL_SUMMARY_ANNOTATION_PROBE_QUERY, {
|
|
85
|
+
owner: repo.owner,
|
|
86
|
+
repo: repo.name,
|
|
87
|
+
oid,
|
|
88
|
+
before,
|
|
89
|
+
});
|
|
90
|
+
const object = data.repository?.object;
|
|
91
|
+
if (object?.__typename !== "Commit" || object.oid !== oid)
|
|
92
|
+
return null;
|
|
93
|
+
return object.statusCheckRollup?.contexts ?? null;
|
|
94
|
+
}, async () => ({
|
|
95
|
+
pageInfo: { hasPreviousPage: false, startCursor: null },
|
|
96
|
+
nodes: await readRestAnnotationCounts(oid, repo),
|
|
97
|
+
}));
|
|
91
98
|
}
|
|
92
99
|
catch {
|
|
93
100
|
return null;
|
|
@@ -10,7 +10,7 @@ type Routed = Pick<PollSummaryItem, "action" | "reasons">;
|
|
|
10
10
|
export declare function applyOpenCheckBlockers(raw: RawSummaryPr, repo: {
|
|
11
11
|
owner: string;
|
|
12
12
|
name: string;
|
|
13
|
-
}, routed: Routed, checks: PollSummaryChecks, review: PollSummaryReview, stack: boolean): Promise<Routed & {
|
|
13
|
+
}, routed: Routed, checks: PollSummaryChecks, review: PollSummaryReview, stack: boolean, requiredContexts?: readonly string[]): Promise<Routed & {
|
|
14
14
|
pollProbe?: true;
|
|
15
15
|
}>;
|
|
16
16
|
export {};
|
|
@@ -6,12 +6,12 @@ import { failingSummaryCheckNames } from "./poll-summary-checks.mjs";
|
|
|
6
6
|
* deferred stay on the routed action. Stack rows are probed so the planner
|
|
7
7
|
* does not start a one-PR session for a wait it would otherwise shepherd.
|
|
8
8
|
*/
|
|
9
|
-
export async function applyOpenCheckBlockers(raw, repo, routed, checks, review, stack) {
|
|
9
|
+
export async function applyOpenCheckBlockers(raw, repo, routed, checks, review, stack, requiredContexts) {
|
|
10
10
|
if (routed.action !== "fix_code" || !routed.reasons.includes("failing-checks"))
|
|
11
11
|
return routed;
|
|
12
12
|
if ((review.actionable ?? 0) > 0 || checks.incomplete)
|
|
13
13
|
return routed;
|
|
14
|
-
const names = failingSummaryCheckNames(raw);
|
|
14
|
+
const names = failingSummaryCheckNames(raw, requiredContexts);
|
|
15
15
|
if (names.length === 0)
|
|
16
16
|
return routed;
|
|
17
17
|
const gate = await resolveCheckBlockerGate({ owner: repo.owner, repo: repo.name, pr: raw.number }, names.map((name) => ({ name })));
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { githubOperation } from "./transport.mjs";
|
|
2
|
+
import { readRestCommitChecks } from "./rest-check-read.mjs";
|
|
1
3
|
import { graphqlWithRateLimit } from "./client.mjs";
|
|
2
4
|
import { POLL_SUMMARY_CHECK_PAGE_QUERY } from "./queries.mjs";
|
|
3
5
|
/**
|
|
@@ -27,7 +29,10 @@ async function hydrateCommitContexts(commit, repo) {
|
|
|
27
29
|
const older = await fetchOlderContexts(commit.oid, pageInfo.startCursor, repo);
|
|
28
30
|
if (!older)
|
|
29
31
|
break;
|
|
30
|
-
|
|
32
|
+
if (older.fullSnapshot)
|
|
33
|
+
nodes.splice(0, nodes.length, ...older.nodes);
|
|
34
|
+
else
|
|
35
|
+
nodes.unshift(...older.nodes);
|
|
31
36
|
pageInfo = older.pageInfo;
|
|
32
37
|
}
|
|
33
38
|
// A window that shifted between pages can repeat or skip contexts; the
|
|
@@ -42,14 +47,24 @@ async function hydrateCommitContexts(commit, repo) {
|
|
|
42
47
|
};
|
|
43
48
|
}
|
|
44
49
|
async function fetchOlderContexts(oid, before, repo) {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
+
return githubOperation("PollSummaryCheckPage", async () => {
|
|
51
|
+
const { data } = await graphqlWithRateLimit(POLL_SUMMARY_CHECK_PAGE_QUERY, {
|
|
52
|
+
owner: repo.owner,
|
|
53
|
+
repo: repo.name,
|
|
54
|
+
oid,
|
|
55
|
+
before,
|
|
56
|
+
});
|
|
57
|
+
const object = data.repository?.object;
|
|
58
|
+
if (object?.__typename !== "Commit" || object.oid !== oid)
|
|
59
|
+
return null;
|
|
60
|
+
return object.statusCheckRollup?.contexts ?? null;
|
|
61
|
+
}, async () => {
|
|
62
|
+
const checks = await readRestCommitChecks(oid, repo);
|
|
63
|
+
return {
|
|
64
|
+
fullSnapshot: true,
|
|
65
|
+
totalCount: checks.nodes.length,
|
|
66
|
+
pageInfo: { hasPreviousPage: false },
|
|
67
|
+
nodes: checks.nodes,
|
|
68
|
+
};
|
|
50
69
|
});
|
|
51
|
-
const object = data.repository?.object;
|
|
52
|
-
if (object?.__typename !== "Commit" || object.oid !== oid)
|
|
53
|
-
return null;
|
|
54
|
-
return object.statusCheckRollup?.contexts ?? null;
|
|
55
70
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { PollSummaryChecks } from "../types.mts";
|
|
2
2
|
import type { RawSummaryPr } from "./poll-summary-raw.mts";
|
|
3
|
-
export declare function summarizePollSummaryChecks(raw: RawSummaryPr): PollSummaryChecks;
|
|
3
|
+
export declare function summarizePollSummaryChecks(raw: RawSummaryPr, requiredContexts?: readonly string[]): PollSummaryChecks;
|
|
4
4
|
/** Names of failing checks in the loaded summary rollup. */
|
|
5
|
-
export declare function failingSummaryCheckNames(raw: RawSummaryPr): string[];
|
|
5
|
+
export declare function failingSummaryCheckNames(raw: RawSummaryPr, requiredContexts?: readonly string[]): string[];
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { classifyChecks } from "../checks/classify.mjs";
|
|
2
2
|
import { parseCreatedAt } from "./batch-parser-helpers.mjs";
|
|
3
|
-
export function summarizePollSummaryChecks(raw) {
|
|
3
|
+
export function summarizePollSummaryChecks(raw, requiredContexts) {
|
|
4
4
|
const rollups = summaryRollups(raw);
|
|
5
5
|
const counts = {};
|
|
6
|
-
for (const check of classifiedSummaryChecks(raw)) {
|
|
6
|
+
for (const check of classifiedSummaryChecks(raw, requiredContexts)) {
|
|
7
7
|
const key = {
|
|
8
8
|
passed: "passing",
|
|
9
9
|
failing: "failing",
|
|
@@ -22,8 +22,8 @@ export function summarizePollSummaryChecks(raw) {
|
|
|
22
22
|
return summary;
|
|
23
23
|
}
|
|
24
24
|
/** Names of failing checks in the loaded summary rollup. */
|
|
25
|
-
export function failingSummaryCheckNames(raw) {
|
|
26
|
-
return classifiedSummaryChecks(raw)
|
|
25
|
+
export function failingSummaryCheckNames(raw, requiredContexts) {
|
|
26
|
+
return classifiedSummaryChecks(raw, requiredContexts)
|
|
27
27
|
.filter((check) => check.category === "failing")
|
|
28
28
|
.map((check) => check.name);
|
|
29
29
|
}
|
|
@@ -36,9 +36,12 @@ function summaryRollups(raw) {
|
|
|
36
36
|
},
|
|
37
37
|
].flatMap(({ rollup, scope }) => (rollup ? [{ rollup, scope }] : []));
|
|
38
38
|
}
|
|
39
|
-
function classifiedSummaryChecks(raw) {
|
|
39
|
+
function classifiedSummaryChecks(raw, requiredContexts) {
|
|
40
40
|
// A successful check on the queue commit cannot cover a PR-head cancellation, or vice versa.
|
|
41
|
-
return summaryRollups(raw).flatMap(({ rollup, scope }) => classifyChecks(checkRuns(rollup, scope),
|
|
41
|
+
return summaryRollups(raw).flatMap(({ rollup, scope }) => classifyChecks(checkRuns(rollup, scope), {
|
|
42
|
+
...(scope === "merge_group" && { additionalRelevantEvents: ["merge_group"] }),
|
|
43
|
+
...(requiredContexts && { requiredContexts }),
|
|
44
|
+
}));
|
|
42
45
|
}
|
|
43
46
|
function checkRuns(rollup, scope) {
|
|
44
47
|
return rollup.contexts.nodes.map((context) => {
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { loadConfig } from "../config/load.mjs";
|
|
2
|
+
import { formatPrUrl } from "../pr-reference.mjs";
|
|
3
|
+
import { buildPrShepherdCommand } from "../cli/runner.mjs";
|
|
4
|
+
export function pollCommandFields(repo, pr, isDraft, opts) {
|
|
5
|
+
const autoMarkReadyDisabled = opts.noAutoMarkReady || loadConfig().actions.autoMarkReady === false;
|
|
6
|
+
const boundedDraft = isDraft && autoMarkReadyDisabled;
|
|
7
|
+
const args = boundedDraft
|
|
8
|
+
? [formatPrUrl(repo, pr), "--timeout", "1s", "--debounce", "0s", "--no-auto-mark-ready"]
|
|
9
|
+
: [formatPrUrl(repo, pr), "--until-terminal"];
|
|
10
|
+
if (opts.merge && opts.stackPrNumber === undefined)
|
|
11
|
+
args.push("--merge");
|
|
12
|
+
if (opts.readyDelaySeconds !== undefined)
|
|
13
|
+
args.push("--ready-delay", `${opts.readyDelaySeconds}s`);
|
|
14
|
+
if (opts.stallTimeoutSeconds !== undefined)
|
|
15
|
+
args.push("--stall-timeout", `${opts.stallTimeoutSeconds}s`);
|
|
16
|
+
if (opts.instructions)
|
|
17
|
+
args.push("--instructions", opts.instructions);
|
|
18
|
+
if (opts.pollMode === "event")
|
|
19
|
+
args.push("--poll-mode", "event");
|
|
20
|
+
if (opts.noAutoMarkReady && !boundedDraft)
|
|
21
|
+
args.push("--no-auto-mark-ready");
|
|
22
|
+
const pollCommand = buildPrShepherdCommand(args).text;
|
|
23
|
+
return boundedDraft ? { pollCommand, pollProbe: true } : { pollCommand };
|
|
24
|
+
}
|
|
@@ -5,4 +5,4 @@ import type { RawSummaryPr } from "./poll-summary-raw.mts";
|
|
|
5
5
|
* computed merge state are checked separately: including them here would
|
|
6
6
|
* invalidate a READY receipt merely because a ready PR entered the queue.
|
|
7
7
|
*/
|
|
8
|
-
export declare function fingerprintRawSummaryPr(
|
|
8
|
+
export declare function fingerprintRawSummaryPr(summary: RawSummaryPr): string | null;
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
|
+
import { withoutHandoffFields } from "./poll-summary-handoff-fields.mjs";
|
|
2
3
|
/**
|
|
3
4
|
* Bind receipts to the review and head-commit CI evidence shared by one-PR
|
|
4
5
|
* completion and stack reconciliation. Queue entry, queue checks, and GitHub's
|
|
5
6
|
* computed merge state are checked separately: including them here would
|
|
6
7
|
* invalidate a READY receipt merely because a ready PR entered the queue.
|
|
7
8
|
*/
|
|
8
|
-
export function fingerprintRawSummaryPr(
|
|
9
|
+
export function fingerprintRawSummaryPr(summary) {
|
|
10
|
+
const raw = withoutHandoffFields(summary);
|
|
9
11
|
if (!raw.updatedAt || !raw.headRefOid || !raw.baseRefOid)
|
|
10
12
|
return null;
|
|
11
13
|
const reviewTruncated = raw.comments.pageInfo.hasPreviousPage ||
|
|
@@ -13,6 +15,7 @@ export function fingerprintRawSummaryPr(raw) {
|
|
|
13
15
|
raw.reviewThreads.pageInfo.hasPreviousPage ||
|
|
14
16
|
raw.reviewThreads.nodes.some((thread) => thread.comments.pageInfo.hasPreviousPage);
|
|
15
17
|
const evidence = {
|
|
18
|
+
...(raw.transport === "rest" && { transport: "rest" }),
|
|
16
19
|
number: raw.number,
|
|
17
20
|
state: raw.state,
|
|
18
21
|
lifecycleEvents: raw.lifecycleEvents,
|
|
@@ -32,7 +35,6 @@ export function fingerprintRawSummaryPr(raw) {
|
|
|
32
35
|
...raw.reviewThreads,
|
|
33
36
|
nodes: raw.reviewThreads.nodes.map((thread) => ({
|
|
34
37
|
...thread,
|
|
35
|
-
rootComments: thread.rootComments && hideBodies(thread.rootComments),
|
|
36
38
|
comments: hideBodies(thread.comments),
|
|
37
39
|
})),
|
|
38
40
|
},
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The GraphQL summary selects these fields only so a routed stack layer's first
|
|
3
|
+
* tick can skip `BatchPr` (see `stack-handoff.mts`). They are not readiness
|
|
4
|
+
* evidence, and some (an edited hidden comment's `updatedAt`) change after a PR
|
|
5
|
+
* settles, so READY-receipt fingerprints leave them out. REST summaries never
|
|
6
|
+
* carry them. A thread comment's `isMinimized` stays: the fingerprint hides
|
|
7
|
+
* minimized bodies, as it already did for comments and reviews.
|
|
8
|
+
*/
|
|
9
|
+
const COMMENT = ["viewerCanMinimize", "createdAt", "updatedAt"];
|
|
10
|
+
const REVIEW = [...COMMENT, "url", "commit"];
|
|
11
|
+
const THREAD = ["viewerCanReply", "viewerCanResolve", "line", "startLine"];
|
|
12
|
+
const THREAD_COMMENT = ["pullRequestReview", "path", "line", "startLine", "createdAt", "updatedAt"];
|
|
13
|
+
const STATUS_CONTEXT = ["createdAt", "targetUrl", "description"];
|
|
14
|
+
function omit(value, keys) {
|
|
15
|
+
const copy = { ...value };
|
|
16
|
+
for (const key of keys)
|
|
17
|
+
delete copy[key];
|
|
18
|
+
return copy;
|
|
19
|
+
}
|
|
20
|
+
function omitEach(connection, keys) {
|
|
21
|
+
return { ...connection, nodes: connection.nodes.map((node) => omit(node, keys)) };
|
|
22
|
+
}
|
|
23
|
+
/** `raw` without the fields only the handoff reads. */
|
|
24
|
+
export function withoutHandoffFields(raw) {
|
|
25
|
+
if (raw.transport === "rest")
|
|
26
|
+
return raw;
|
|
27
|
+
return {
|
|
28
|
+
...raw,
|
|
29
|
+
...(raw.reviewRequests && {
|
|
30
|
+
reviewRequests: {
|
|
31
|
+
nodes: raw.reviewRequests.nodes.map(({ requestedReviewer }) => ({
|
|
32
|
+
requestedReviewer: requestedReviewer && omit(requestedReviewer, ["name"]),
|
|
33
|
+
})),
|
|
34
|
+
},
|
|
35
|
+
}),
|
|
36
|
+
comments: omitEach(raw.comments, COMMENT),
|
|
37
|
+
reviews: omitEach(raw.reviews, REVIEW),
|
|
38
|
+
reviewThreads: {
|
|
39
|
+
...raw.reviewThreads,
|
|
40
|
+
nodes: raw.reviewThreads.nodes.map((thread) => ({
|
|
41
|
+
...omit(thread, THREAD),
|
|
42
|
+
comments: omitEach(thread.comments, THREAD_COMMENT),
|
|
43
|
+
})),
|
|
44
|
+
},
|
|
45
|
+
commits: {
|
|
46
|
+
...omit(raw.commits, ["totalCount"]),
|
|
47
|
+
nodes: raw.commits.nodes.map(({ commit }) => {
|
|
48
|
+
const rollup = commit.statusCheckRollup;
|
|
49
|
+
return {
|
|
50
|
+
commit: {
|
|
51
|
+
...commit,
|
|
52
|
+
statusCheckRollup: rollup && {
|
|
53
|
+
...omit(rollup, ["state"]),
|
|
54
|
+
contexts: {
|
|
55
|
+
...rollup.contexts,
|
|
56
|
+
nodes: rollup.contexts.nodes.map((node) => node.__typename === "StatusContext"
|
|
57
|
+
? omit(node, STATUS_CONTEXT)
|
|
58
|
+
: {
|
|
59
|
+
...node,
|
|
60
|
+
checkSuite: node.checkSuite && {
|
|
61
|
+
...omit(node.checkSuite, ["updatedAt"]),
|
|
62
|
+
workflowRun: node.checkSuite.workflowRun &&
|
|
63
|
+
omit(node.checkSuite.workflowRun, ["updatedAt"]),
|
|
64
|
+
},
|
|
65
|
+
}),
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
},
|
|
69
|
+
};
|
|
70
|
+
}),
|
|
71
|
+
},
|
|
72
|
+
};
|
|
73
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import type { PollSummaryCommandOptions, PollSummaryItem } from "../types.mts";
|
|
2
2
|
import type { RepoInfo } from "./client.mts";
|
|
3
3
|
import type { RawSummaryPr } from "./poll-summary-raw.mts";
|
|
4
|
-
export declare function summarizePollSummaryPr(raw: RawSummaryPr, repo: RepoInfo, opts: PollSummaryCommandOptions, viewerCanAdminister?: boolean, mergeTargetContexts?: readonly string[], viewerLogin?: string | null): Promise<PollSummaryItem>;
|
|
4
|
+
export declare function summarizePollSummaryPr(raw: RawSummaryPr, repo: RepoInfo, opts: PollSummaryCommandOptions, viewerCanAdminister?: boolean | undefined, mergeTargetContexts?: readonly string[], viewerLogin?: string | null): Promise<PollSummaryItem>;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
+
import { pollCommandFields } from "./poll-summary-command.mjs";
|
|
1
2
|
import { loadConfig } from "../config/load.mjs";
|
|
2
3
|
import { updateReadyDelay } from "../commands/ready-delay.mjs";
|
|
3
4
|
import { formatPrUrl } from "../pr-reference.mjs";
|
|
4
|
-
import { buildPrShepherdCommand } from "../cli/runner.mjs";
|
|
5
5
|
import { loadSeenMap } from "../state/seen-comments.mjs";
|
|
6
6
|
import { isReadyReceiptCurrent, readReadyReceipt } from "../state/ready-receipts.mjs";
|
|
7
7
|
import { summarizePollSummaryChecks } from "./poll-summary-checks.mjs";
|
|
@@ -11,12 +11,16 @@ import { isCurrentSummaryReady } from "./poll-summary-readiness.mjs";
|
|
|
11
11
|
import { applyOpenCheckBlockers } from "./poll-summary-check-blockers.mjs";
|
|
12
12
|
import { normalizePollSummaryState, routePollSummary } from "./poll-summary-route.mjs";
|
|
13
13
|
import { hydrateReadyAnnotationProbe, readyFingerprint } from "./poll-summary-annotation-probe.mjs";
|
|
14
|
-
import { applyUnreportedRequiredChecks } from "./poll-summary-unreported.mjs";
|
|
15
|
-
|
|
14
|
+
import { applyUnreportedRequiredChecks, summaryRequiredContexts, } from "./poll-summary-unreported.mjs";
|
|
15
|
+
import { aliasThreadSeenMarkers } from "./rest-identities.mjs";
|
|
16
|
+
import { restQueueRequirement } from "./poll-summary-rest-queue.mjs";
|
|
17
|
+
export async function summarizePollSummaryPr(raw, repo, opts, viewerCanAdminister = undefined, mergeTargetContexts, viewerLogin = null) {
|
|
16
18
|
const repoName = `${repo.owner}/${repo.name}`;
|
|
17
19
|
const seen = await loadSeenMap({ owner: repo.owner, repo: repo.name, pr: raw.number });
|
|
18
|
-
|
|
19
|
-
|
|
20
|
+
await aliasThreadSeenMarkers(repo, raw.number, raw.reviewThreads.nodes.map(({ id }) => id), seen);
|
|
21
|
+
const required = summaryRequiredContexts(raw, mergeTargetContexts);
|
|
22
|
+
const checks = summarizePollSummaryChecks(raw, required);
|
|
23
|
+
applyUnreportedRequiredChecks(raw, checks, required);
|
|
20
24
|
const review = await summarizePollSummaryReview(raw, seen, viewerCanAdminister);
|
|
21
25
|
const blockingReviewerInProgress = detectBlockingReviewer(raw);
|
|
22
26
|
const removalEvent = currentQueueRemovalEvent(raw);
|
|
@@ -74,12 +78,15 @@ export async function summarizePollSummaryPr(raw, repo, opts, viewerCanAdministe
|
|
|
74
78
|
: removalEvent
|
|
75
79
|
? projectQueueRemoval(removalEvent)
|
|
76
80
|
: undefined;
|
|
77
|
-
const blocked = await applyOpenCheckBlockers(raw, repo, { action, reasons }, checks, review, opts.stackPrNumber !== undefined);
|
|
81
|
+
const blocked = await applyOpenCheckBlockers(raw, repo, { action, reasons }, checks, review, opts.stackPrNumber !== undefined, required);
|
|
78
82
|
action = blocked.action;
|
|
79
83
|
reasons = blocked.reasons;
|
|
84
|
+
const requiresMergeQueue = raw.transport === "rest" ? restQueueRequirement(raw) : undefined;
|
|
80
85
|
return {
|
|
81
86
|
pr: raw.number,
|
|
82
87
|
repo: repoName,
|
|
88
|
+
...(raw.transport && { transport: raw.transport }),
|
|
89
|
+
...(raw.transportUnavailable?.length && { transportUnavailable: raw.transportUnavailable }),
|
|
83
90
|
title: raw.title,
|
|
84
91
|
url: raw.url || formatPrUrl(repoName, raw.number),
|
|
85
92
|
...(raw.author?.login && { authorLogin: raw.author.login }),
|
|
@@ -97,6 +104,7 @@ export async function summarizePollSummaryPr(raw, repo, opts, viewerCanAdministe
|
|
|
97
104
|
baseRefName: raw.baseRefName,
|
|
98
105
|
...(raw.isDraft && { isDraft: true }),
|
|
99
106
|
...(raw.isInMergeQueue && { isInMergeQueue: true }),
|
|
107
|
+
...(requiresMergeQueue !== undefined && { requiresMergeQueue }),
|
|
100
108
|
...(queueRemoval && { queueRemoval }),
|
|
101
109
|
...(blockingReviewerInProgress && { blockingReviewerInProgress: true }),
|
|
102
110
|
...(remainingSeconds !== undefined && { remainingSeconds }),
|
|
@@ -125,24 +133,9 @@ function projectQueueRemoval(removal) {
|
|
|
125
133
|
}
|
|
126
134
|
function detectBlockingReviewer(raw) {
|
|
127
135
|
const prefixes = (loadConfig().mergeStatus?.blockingReviewerLogins ?? []).map((login) => login.toLowerCase());
|
|
128
|
-
|
|
136
|
+
// A team reviewer has a name, not a login, so it never matches a login prefix.
|
|
137
|
+
const matches = (author) => typeof author?.login === "string" &&
|
|
138
|
+
prefixes.some((prefix) => author.login.toLowerCase().startsWith(prefix));
|
|
129
139
|
return ((raw.reviewRequests?.nodes ?? []).some((request) => matches(request.requestedReviewer)) ||
|
|
130
140
|
(raw.latestReviews?.nodes ?? []).some((review) => review.state === "PENDING" && matches(review.author)));
|
|
131
141
|
}
|
|
132
|
-
function pollCommandFields(repo, pr, isDraft, opts) {
|
|
133
|
-
const autoMarkReadyDisabled = opts.noAutoMarkReady || loadConfig().actions.autoMarkReady === false;
|
|
134
|
-
const boundedDraft = isDraft && autoMarkReadyDisabled;
|
|
135
|
-
const args = boundedDraft
|
|
136
|
-
? [formatPrUrl(repo, pr), "--timeout", "1s", "--debounce", "0s", "--no-auto-mark-ready"]
|
|
137
|
-
: [formatPrUrl(repo, pr), "--until-terminal"];
|
|
138
|
-
if (opts.merge && opts.stackPrNumber === undefined)
|
|
139
|
-
args.push("--merge");
|
|
140
|
-
if (opts.readyDelaySeconds !== undefined)
|
|
141
|
-
args.push("--ready-delay", `${opts.readyDelaySeconds}s`);
|
|
142
|
-
if (opts.stallTimeoutSeconds !== undefined)
|
|
143
|
-
args.push("--stall-timeout", `${opts.stallTimeoutSeconds}s`);
|
|
144
|
-
if (opts.noAutoMarkReady && !boundedDraft)
|
|
145
|
-
args.push("--no-auto-mark-ready");
|
|
146
|
-
const pollCommand = buildPrShepherdCommand(args).text;
|
|
147
|
-
return boundedDraft ? { pollCommand, pollProbe: true } : { pollCommand };
|
|
148
|
-
}
|