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
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { readRestPages, restRepoPath, restString, restNumber, restCollection, restObject, } from "./rest-reader-core.mjs";
|
|
2
|
+
import { recordRestIdentity, resolveRestIdentity } from "./rest-identities.mjs";
|
|
3
|
+
import { toCheckAnnotation } from "./check-annotation-shape.mjs";
|
|
4
|
+
import { readRestPull } from "./rest-pr-core.mjs";
|
|
5
|
+
/** An annotation fallback can follow a GraphQL snapshot with no persisted REST check IDs. */
|
|
6
|
+
export async function ensureRestCheckIdentities(checkRunIds, scope) {
|
|
7
|
+
if (!scope || checkRunIds.length === 0)
|
|
8
|
+
return;
|
|
9
|
+
const identities = await Promise.allSettled(checkRunIds.map((id) => resolveRestIdentity(id, "check")));
|
|
10
|
+
if (identities.every((identity) => identity.status === "fulfilled"))
|
|
11
|
+
return;
|
|
12
|
+
const repo = { owner: scope.stateKey.owner, name: scope.stateKey.repo };
|
|
13
|
+
const pr = scope.stateKey.pr;
|
|
14
|
+
const sha = scope.headSha ?? (await readRestPull(pr, repo)).head.sha;
|
|
15
|
+
const checks = await readRestPages(`${restRepoPath(repo)}/commits/${encodeURIComponent(sha)}/check-runs?filter=all`, (body) => restCollection(body, "check_runs"));
|
|
16
|
+
await Promise.all(checks.nodes.map((value) => {
|
|
17
|
+
const check = restObject(value, "check run identity");
|
|
18
|
+
return recordRestIdentity(repo, pr, restString(check.node_id, "check node_id"), restNumber(check.id, "check id"), "check");
|
|
19
|
+
}));
|
|
20
|
+
}
|
|
21
|
+
export async function readRestCheckAnnotations(checkRunId, scope) {
|
|
22
|
+
await ensureRestCheckIdentities([checkRunId], scope);
|
|
23
|
+
const identity = await resolveRestIdentity(checkRunId, "check");
|
|
24
|
+
const result = await readRestPages(`${restRepoPath(identity.repo)}/check-runs/${identity.numericId}/annotations`);
|
|
25
|
+
return result.nodes.map((raw) => toCheckAnnotation(checkRunId, {
|
|
26
|
+
fullDatabaseId: null,
|
|
27
|
+
path: restString(raw.path, "annotation path"),
|
|
28
|
+
annotationLevel: restString(raw.annotation_level, "annotation level").toUpperCase(),
|
|
29
|
+
title: typeof raw.title === "string" ? raw.title : null,
|
|
30
|
+
message: restString(raw.message, "annotation message"),
|
|
31
|
+
rawDetails: typeof raw.raw_details === "string" ? raw.raw_details : null,
|
|
32
|
+
blobUrl: typeof raw.blob_href === "string" ? raw.blob_href : null,
|
|
33
|
+
location: {
|
|
34
|
+
start: {
|
|
35
|
+
line: restNumber(raw.start_line, "annotation start_line"),
|
|
36
|
+
column: typeof raw.start_column === "number" ? raw.start_column : null,
|
|
37
|
+
},
|
|
38
|
+
end: {
|
|
39
|
+
line: restNumber(raw.end_line, "annotation end_line"),
|
|
40
|
+
column: typeof raw.end_column === "number" ? raw.end_column : null,
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
}));
|
|
44
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { RepoInfo } from "./client.mts";
|
|
2
|
+
import type { BatchResult } from "./batch.mts";
|
|
3
|
+
import type { RawSummaryPr } from "./poll-summary-raw.mts";
|
|
4
|
+
import type { RestSnapshotContext } from "./rest-snapshot-context.mts";
|
|
5
|
+
/** REST uses multiple resources; retry a moving head/base once rather than combining revisions. */
|
|
6
|
+
export declare function fetchRestPrBatch(pr: number, repo: RepoInfo, opts?: {
|
|
7
|
+
includeReceiptSummary?: boolean;
|
|
8
|
+
terminalShortCircuit?: boolean;
|
|
9
|
+
snapshotContext?: RestSnapshotContext;
|
|
10
|
+
viewerLogin?: string | null;
|
|
11
|
+
}): Promise<BatchResult>;
|
|
12
|
+
export declare function fetchRestRawSummaryPr(pr: number, repo: RepoInfo, snapshotContext?: RestSnapshotContext, viewerLogin?: string | null): Promise<RawSummaryPr>;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { readRestPull, restPullRevision } from "./rest-pr-core.mjs";
|
|
2
|
+
import { readRestSnapshot } from "./rest-batch-snapshot.mjs";
|
|
3
|
+
import { isRestPullMerged, restMergedBatchData } from "./rest-terminal-batch.mjs";
|
|
4
|
+
import { restSummary } from "./rest-summary-read.mjs";
|
|
5
|
+
import { markReadyAnnotationProbeComplete } from "./poll-summary-annotation-probe.mjs";
|
|
6
|
+
import { hydratePollSummaryChecks } from "./poll-summary-check-hydration.mjs";
|
|
7
|
+
import { GitHubRequestError } from "./errors.mjs";
|
|
8
|
+
import { EXIT } from "../exit-codes.mjs";
|
|
9
|
+
/** REST uses multiple resources; retry a moving head/base once rather than combining revisions. */
|
|
10
|
+
export async function fetchRestPrBatch(pr, repo, opts = {}) {
|
|
11
|
+
for (let attempt = 0; attempt < 2; attempt++) {
|
|
12
|
+
const pull = await readRestPull(pr, repo);
|
|
13
|
+
if (opts.terminalShortCircuit && isRestPullMerged(pull)) {
|
|
14
|
+
return { data: restMergedBatchData(pull), checkSuitesComplete: true };
|
|
15
|
+
}
|
|
16
|
+
const snapshot = await readRestSnapshot(pull, repo, opts.snapshotContext, opts.viewerLogin);
|
|
17
|
+
const latest = await readRestPull(pr, repo);
|
|
18
|
+
if (restPullRevision(pull) !== restPullRevision(latest))
|
|
19
|
+
continue;
|
|
20
|
+
opts.snapshotContext?.recordPullRevision(pr, restPullRevision(latest));
|
|
21
|
+
const receiptSummary = restSummary(snapshot.data, pull, snapshot.feedback, snapshot.checks, snapshot.rules.baseRef);
|
|
22
|
+
// Match the canonical check window hashed by aggregate stack reconciliation.
|
|
23
|
+
await hydratePollSummaryChecks(receiptSummary, repo);
|
|
24
|
+
markReadyAnnotationProbeComplete(receiptSummary);
|
|
25
|
+
return {
|
|
26
|
+
data: snapshot.data,
|
|
27
|
+
rateLimit: snapshot.checks.rateLimit,
|
|
28
|
+
checkSuitesComplete: true,
|
|
29
|
+
...(snapshot.checks.suites.length === 0 && { headCheckSuitesEmpty: true }),
|
|
30
|
+
headWorkflowSuites: snapshot.checks.suites.flatMap((suite) => {
|
|
31
|
+
const run = snapshot.checks.workflowRuns.find((run) => run.check_suite_id === suite.id);
|
|
32
|
+
return run
|
|
33
|
+
? [
|
|
34
|
+
{
|
|
35
|
+
status: suite.status.toUpperCase(),
|
|
36
|
+
conclusion: suite.conclusion?.toUpperCase() ?? null,
|
|
37
|
+
workflowRun: { event: run.event },
|
|
38
|
+
},
|
|
39
|
+
]
|
|
40
|
+
: [];
|
|
41
|
+
}),
|
|
42
|
+
...(opts.includeReceiptSummary && { receiptSummary }),
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
throw new GitHubRequestError("Pull request changed while REST snapshot was being read; retry", {
|
|
46
|
+
status: 409,
|
|
47
|
+
exitCodeOverride: EXIT.TEMPFAIL,
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
export async function fetchRestRawSummaryPr(pr, repo, snapshotContext, viewerLogin) {
|
|
51
|
+
const snapshot = await fetchRestPrBatch(pr, repo, {
|
|
52
|
+
includeReceiptSummary: true,
|
|
53
|
+
snapshotContext,
|
|
54
|
+
viewerLogin,
|
|
55
|
+
});
|
|
56
|
+
return snapshot.receiptSummary;
|
|
57
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { RepoInfo } from "./client.mts";
|
|
2
|
+
import type { BatchPrData } from "../types.mts";
|
|
3
|
+
import { type RestPull } from "./rest-pr-core.mts";
|
|
4
|
+
import type { RestSnapshotContext } from "./rest-snapshot-context.mts";
|
|
5
|
+
export declare function readRestSnapshot(pull: RestPull, repo: RepoInfo, context?: RestSnapshotContext, knownViewerLogin?: string | null): Promise<{
|
|
6
|
+
data: BatchPrData;
|
|
7
|
+
feedback: {
|
|
8
|
+
threads: import("../types.mts").ReviewThread[];
|
|
9
|
+
comments: import("../types.mts").PrComment[];
|
|
10
|
+
reviews: import("./rest-feedback-read.mts").RestReview[];
|
|
11
|
+
unavailable: {
|
|
12
|
+
field: string;
|
|
13
|
+
reason: string;
|
|
14
|
+
}[];
|
|
15
|
+
viewerLogin: string | null;
|
|
16
|
+
};
|
|
17
|
+
checks: {
|
|
18
|
+
nodes: import("./batch-raw-types.mts").RawContextNode[];
|
|
19
|
+
suites: import("./rest-check-read.mts").RestSuite[];
|
|
20
|
+
workflowRuns: import("./rest-check-read.mts").RestWorkflowRun[];
|
|
21
|
+
rateLimit: import("./http-utils.mts").RateLimitInfo | undefined;
|
|
22
|
+
};
|
|
23
|
+
rules: {
|
|
24
|
+
baseRef?: import("./batch-raw-rules.mts").RawBaseRef;
|
|
25
|
+
unavailable: Array<{
|
|
26
|
+
field: string;
|
|
27
|
+
reason: string;
|
|
28
|
+
}>;
|
|
29
|
+
};
|
|
30
|
+
}>;
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { restPullRefs } from "./rest-pr-core.mjs";
|
|
2
|
+
import { readRestFeedback, restReviewToReview } from "./rest-feedback-read.mjs";
|
|
3
|
+
import { readRestCommitChecks } from "./rest-check-read.mjs";
|
|
4
|
+
import { readRestBranchRules } from "./rest-rules-read.mjs";
|
|
5
|
+
import { readRestStackMembership } from "./rest-stack-read.mjs";
|
|
6
|
+
import { mergeStartupFailureChecks } from "../checks/startup-failures.mjs";
|
|
7
|
+
import { parseCheckNodes } from "./batch-parse-checks.mjs";
|
|
8
|
+
import { parseBranchRules } from "./batch-parsers-rules.mjs";
|
|
9
|
+
import { isReviewStale } from "./batch-parser-helpers.mjs";
|
|
10
|
+
import { readRest as rest, restRepoPath, restObject, restString } from "./rest-reader-core.mjs";
|
|
11
|
+
import { restLatestReviews, restPendingReviews } from "./rest-review-read.mjs";
|
|
12
|
+
import { REST_BATCH_UNAVAILABLE } from "./rest-batch-unavailable.mjs";
|
|
13
|
+
export async function readRestSnapshot(pull, repo, context, knownViewerLogin) {
|
|
14
|
+
const [feedback, checks, rules, stack] = await Promise.all([
|
|
15
|
+
readRestFeedback(pull.number, repo, context ? context.viewerLogin : knownViewerLogin),
|
|
16
|
+
readRestCommitChecks(pull.head.sha, repo, pull.number),
|
|
17
|
+
context ? context.readBranchRules(pull.base.ref) : readRestBranchRules(repo, pull.base.ref),
|
|
18
|
+
context ? Promise.resolve(context.stack) : readRestStackMembership(pull.number, repo),
|
|
19
|
+
]);
|
|
20
|
+
const repository = restObject(context?.repository ?? (await rest("GET", restRepoPath(repo))), "repository merge settings");
|
|
21
|
+
const allowedMergeMethods = [
|
|
22
|
+
...(repository.allow_merge_commit === true ? ["merge"] : []),
|
|
23
|
+
...(repository.allow_squash_merge === true ? ["squash"] : []),
|
|
24
|
+
...(repository.allow_rebase_merge === true ? ["rebase"] : []),
|
|
25
|
+
];
|
|
26
|
+
const latestReviews = restLatestReviews(feedback.reviews);
|
|
27
|
+
const requested = [
|
|
28
|
+
...(pull.requested_reviewers ?? []).map((reviewer) => ({ login: reviewer.login })),
|
|
29
|
+
...(pull.requested_teams ?? []).map((team) => ({ login: team.name })),
|
|
30
|
+
];
|
|
31
|
+
const changes = feedback.reviews.filter((review) => review.state === "CHANGES_REQUESTED" &&
|
|
32
|
+
!["APPROVED", "DISMISSED"].includes(latestReviews.get(review.user?.login.toLowerCase() ?? "")?.state ?? ""));
|
|
33
|
+
const transportUnavailable = [
|
|
34
|
+
...feedback.unavailable,
|
|
35
|
+
...rules.unavailable,
|
|
36
|
+
...REST_BATCH_UNAVAILABLE,
|
|
37
|
+
];
|
|
38
|
+
const data = {
|
|
39
|
+
nodeId: pull.node_id,
|
|
40
|
+
...(feedback.viewerLogin && { viewerLogin: feedback.viewerLogin }),
|
|
41
|
+
...restPullRefs(pull),
|
|
42
|
+
state: restPullRefs(pull).state,
|
|
43
|
+
isDraft: pull.draft,
|
|
44
|
+
mergeable: pull.mergeable === true ? "MERGEABLE" : pull.mergeable === false ? "CONFLICTING" : "UNKNOWN",
|
|
45
|
+
mergeStateStatus: pull.mergeable_state.toUpperCase(),
|
|
46
|
+
reviewDecision: null,
|
|
47
|
+
...(pull.auto_merge !== undefined && {
|
|
48
|
+
autoMergeRequest: pull.auto_merge
|
|
49
|
+
? {
|
|
50
|
+
mergeMethod: restString(pull.auto_merge.merge_method, "auto-merge merge_method").toUpperCase(),
|
|
51
|
+
...(pull.auto_merge.enabled_by?.login && {
|
|
52
|
+
enabledBy: restString(pull.auto_merge.enabled_by.login, "auto-merge enabled_by login"),
|
|
53
|
+
}),
|
|
54
|
+
}
|
|
55
|
+
: null,
|
|
56
|
+
}),
|
|
57
|
+
headRepoWithOwner: pull.head.repo?.full_name ?? null,
|
|
58
|
+
reviewRequests: requested,
|
|
59
|
+
latestReviews: [...restPendingReviews(feedback.reviews), ...latestReviews.values()],
|
|
60
|
+
reviewThreads: feedback.threads,
|
|
61
|
+
comments: feedback.comments,
|
|
62
|
+
changesRequestedReviews: changes.map((review) => {
|
|
63
|
+
const mapped = restReviewToReview(review);
|
|
64
|
+
if (isReviewStale(mapped, pull.head.sha, feedback.threads))
|
|
65
|
+
mapped.staleReview = true;
|
|
66
|
+
return mapped;
|
|
67
|
+
}),
|
|
68
|
+
reviewSummaries: feedback.reviews
|
|
69
|
+
.filter((review) => review.state === "COMMENTED" && review.body?.trim())
|
|
70
|
+
.map(restReviewToReview),
|
|
71
|
+
approvedReviews: feedback.reviews
|
|
72
|
+
.filter((review) => review.state === "APPROVED")
|
|
73
|
+
.map(restReviewToReview),
|
|
74
|
+
checks: mergeStartupFailureChecks(parseCheckNodes(checks.nodes), checks.suites.flatMap((suite) => {
|
|
75
|
+
const run = checks.workflowRuns.find((run) => run.check_suite_id === suite.id);
|
|
76
|
+
if (suite.conclusion?.toUpperCase() !== "STARTUP_FAILURE" || !run)
|
|
77
|
+
return [];
|
|
78
|
+
return [
|
|
79
|
+
{
|
|
80
|
+
name: run.name || `workflow run ${run.id}`,
|
|
81
|
+
status: "COMPLETED",
|
|
82
|
+
conclusion: "STARTUP_FAILURE",
|
|
83
|
+
source: "startup_failure",
|
|
84
|
+
detailsUrl: run.html_url,
|
|
85
|
+
event: run.event,
|
|
86
|
+
runId: String(run.id),
|
|
87
|
+
},
|
|
88
|
+
];
|
|
89
|
+
})),
|
|
90
|
+
branchProtection: rules.baseRef?.branchProtectionRule
|
|
91
|
+
? {
|
|
92
|
+
requiresApprovingReviews: rules.baseRef.branchProtectionRule.requiresApprovingReviews,
|
|
93
|
+
requiredApprovingReviewCount: rules.baseRef.branchProtectionRule.requiredApprovingReviewCount,
|
|
94
|
+
requiresConversationResolution: rules.baseRef.branchProtectionRule.requiresConversationResolution,
|
|
95
|
+
requiresStatusChecks: rules.baseRef.branchProtectionRule.requiresStatusChecks,
|
|
96
|
+
requiredStatusCheckContexts: rules.baseRef.branchProtectionRule.requiredStatusCheckContexts ?? [],
|
|
97
|
+
}
|
|
98
|
+
: null,
|
|
99
|
+
...(rules.baseRef && { branchRules: parseBranchRules(rules.baseRef) }),
|
|
100
|
+
...(typeof repository.allow_merge_commit === "boolean" &&
|
|
101
|
+
typeof repository.allow_squash_merge === "boolean" &&
|
|
102
|
+
typeof repository.allow_rebase_merge === "boolean" && { allowedMergeMethods }),
|
|
103
|
+
stack: stack
|
|
104
|
+
? {
|
|
105
|
+
number: stack.number,
|
|
106
|
+
size: stack.pull_requests.length,
|
|
107
|
+
position: stack.pull_requests.findIndex((member) => member.number === pull.number) + 1,
|
|
108
|
+
baseRefName: stack.base.ref,
|
|
109
|
+
}
|
|
110
|
+
: null,
|
|
111
|
+
transport: "rest",
|
|
112
|
+
transportUnavailable,
|
|
113
|
+
};
|
|
114
|
+
return { data, feedback, checks, rules };
|
|
115
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/** Batch fields no REST endpoint supplies; they stay unknown rather than defaulting to false. */
|
|
2
|
+
export const REST_BATCH_UNAVAILABLE = [
|
|
3
|
+
{
|
|
4
|
+
field: "reviewDecision",
|
|
5
|
+
reason: "REST does not expose an aggregate review decision; latest review states are supplied",
|
|
6
|
+
},
|
|
7
|
+
{ field: "viewerAuthorization", reason: "REST does not expose viewer capability fields" },
|
|
8
|
+
{
|
|
9
|
+
field: "comments.isMinimized",
|
|
10
|
+
reason: "REST does not expose minimization state or support minimizing comments",
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
field: "mergeQueue",
|
|
14
|
+
reason: "REST does not expose queue membership, entry or removal history",
|
|
15
|
+
},
|
|
16
|
+
];
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { RepoInfo } from "./client.mts";
|
|
2
|
+
import type { RawContextNode } from "./batch-raw-types.mts";
|
|
3
|
+
export interface RestSuite {
|
|
4
|
+
id: number;
|
|
5
|
+
node_id: string;
|
|
6
|
+
status: string;
|
|
7
|
+
conclusion: string | null;
|
|
8
|
+
created_at: string;
|
|
9
|
+
updated_at: string;
|
|
10
|
+
}
|
|
11
|
+
export interface RestWorkflowRun {
|
|
12
|
+
id: number;
|
|
13
|
+
check_suite_id: number;
|
|
14
|
+
event: string;
|
|
15
|
+
workflow_id: number;
|
|
16
|
+
name: string;
|
|
17
|
+
created_at: string;
|
|
18
|
+
updated_at: string;
|
|
19
|
+
html_url: string;
|
|
20
|
+
}
|
|
21
|
+
export declare function readRestCommitChecks(oid: string, repo: RepoInfo, pr?: number): Promise<{
|
|
22
|
+
nodes: RawContextNode[];
|
|
23
|
+
suites: RestSuite[];
|
|
24
|
+
workflowRuns: RestWorkflowRun[];
|
|
25
|
+
rateLimit: import("./http-utils.mts").RateLimitInfo | undefined;
|
|
26
|
+
}>;
|
|
27
|
+
export declare function readRestAnnotationCounts(oid: string, repo: RepoInfo): Promise<{
|
|
28
|
+
__typename: "CheckRun";
|
|
29
|
+
id: string;
|
|
30
|
+
annotations: {
|
|
31
|
+
totalCount: number;
|
|
32
|
+
};
|
|
33
|
+
}[]>;
|
|
34
|
+
export declare function readRestBehind(repo: RepoInfo, base: string, head: string): Promise<number>;
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { readRestPages, restRepoPath, restCollection, restString, restNumber, malformedRest, } from "./rest-reader-core.mjs";
|
|
2
|
+
import { recordRestIdentity } from "./rest-identities.mjs";
|
|
3
|
+
import { readRest as rest } from "./rest-reader-core.mjs";
|
|
4
|
+
export async function readRestCommitChecks(oid, repo, pr = 0) {
|
|
5
|
+
const prefix = restRepoPath(repo);
|
|
6
|
+
const checks = await readRestPages(`${prefix}/commits/${encodeURIComponent(oid)}/check-runs?filter=latest`, (body) => restCollection(body, "check_runs"));
|
|
7
|
+
const suites = await readRestPages(`${prefix}/commits/${encodeURIComponent(oid)}/check-suites`, (body) => restCollection(body, "check_suites"));
|
|
8
|
+
const statuses = await readRestPages(`${prefix}/commits/${encodeURIComponent(oid)}/statuses`);
|
|
9
|
+
const workflowRuns = await readRestPages(`${prefix}/actions/runs?head_sha=${encodeURIComponent(oid)}`, (body) => restCollection(body, "workflow_runs"));
|
|
10
|
+
for (const suite of suites.nodes) {
|
|
11
|
+
restNumber(suite.id, "check suite id");
|
|
12
|
+
restString(suite.status, "check suite status");
|
|
13
|
+
if (suite.conclusion !== null)
|
|
14
|
+
restString(suite.conclusion, "check suite conclusion");
|
|
15
|
+
}
|
|
16
|
+
for (const run of workflowRuns.nodes) {
|
|
17
|
+
restNumber(run.id, "workflow run id");
|
|
18
|
+
restNumber(run.check_suite_id, "workflow check suite id");
|
|
19
|
+
restNumber(run.workflow_id, "workflow id");
|
|
20
|
+
restString(run.event, "workflow event");
|
|
21
|
+
}
|
|
22
|
+
const workflows = new Map(workflowRuns.nodes.map((run) => [run.check_suite_id, run]));
|
|
23
|
+
const suiteMap = new Map(suites.nodes.map((suite) => [suite.id, suite]));
|
|
24
|
+
const nodes = [];
|
|
25
|
+
const checkIds = new Set();
|
|
26
|
+
for (const check of checks.nodes) {
|
|
27
|
+
restNumber(check.id, "check run id");
|
|
28
|
+
restString(check.node_id, "check run node_id");
|
|
29
|
+
restString(check.name, "check run name");
|
|
30
|
+
restString(check.status, "check run status");
|
|
31
|
+
if (!["QUEUED", "IN_PROGRESS", "COMPLETED", "WAITING", "PENDING", "REQUESTED"].includes(check.status.toUpperCase()))
|
|
32
|
+
malformedRest("unknown check run status");
|
|
33
|
+
if (check.conclusion !== null &&
|
|
34
|
+
![
|
|
35
|
+
"ACTION_REQUIRED",
|
|
36
|
+
"CANCELLED",
|
|
37
|
+
"FAILURE",
|
|
38
|
+
"NEUTRAL",
|
|
39
|
+
"SKIPPED",
|
|
40
|
+
"STALE",
|
|
41
|
+
"STARTUP_FAILURE",
|
|
42
|
+
"SUCCESS",
|
|
43
|
+
"TIMED_OUT",
|
|
44
|
+
].includes(restString(check.conclusion, "check conclusion").toUpperCase()))
|
|
45
|
+
malformedRest("unknown check conclusion");
|
|
46
|
+
restNumber(check.output?.annotations_count, "check run annotation count");
|
|
47
|
+
if (checkIds.has(check.node_id))
|
|
48
|
+
throw new Error("REST check run pagination duplicated an ID");
|
|
49
|
+
checkIds.add(check.node_id);
|
|
50
|
+
await recordRestIdentity(repo, pr, check.node_id, String(check.id), "check");
|
|
51
|
+
const suite = check.check_suite ? suiteMap.get(check.check_suite.id) : undefined;
|
|
52
|
+
const run = check.check_suite ? workflows.get(check.check_suite.id) : undefined;
|
|
53
|
+
nodes.push({
|
|
54
|
+
__typename: "CheckRun",
|
|
55
|
+
id: check.node_id,
|
|
56
|
+
name: check.name,
|
|
57
|
+
status: check.status.toUpperCase(),
|
|
58
|
+
conclusion: check.conclusion?.toUpperCase() ?? null,
|
|
59
|
+
detailsUrl: check.details_url,
|
|
60
|
+
startedAt: check.started_at,
|
|
61
|
+
completedAt: check.completed_at,
|
|
62
|
+
title: check.output.title,
|
|
63
|
+
summary: check.output.summary,
|
|
64
|
+
annotations: { totalCount: check.output.annotations_count, nodes: [] },
|
|
65
|
+
checkSuite: suite
|
|
66
|
+
? {
|
|
67
|
+
createdAt: suite.created_at,
|
|
68
|
+
updatedAt: suite.updated_at,
|
|
69
|
+
workflowRun: run
|
|
70
|
+
? {
|
|
71
|
+
databaseId: run.id,
|
|
72
|
+
event: run.event,
|
|
73
|
+
createdAt: run.created_at,
|
|
74
|
+
updatedAt: run.updated_at,
|
|
75
|
+
workflow: { name: run.name, databaseId: run.workflow_id },
|
|
76
|
+
}
|
|
77
|
+
: null,
|
|
78
|
+
}
|
|
79
|
+
: null,
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
// REST statuses include history; only the latest status for each context is current.
|
|
83
|
+
const latest = new Map();
|
|
84
|
+
for (const status of statuses.nodes) {
|
|
85
|
+
restString(status.context, "status context");
|
|
86
|
+
restString(status.state, "status state");
|
|
87
|
+
if (!["PENDING", "EXPECTED", "SUCCESS", "FAILURE", "ERROR"].includes(status.state.toUpperCase()))
|
|
88
|
+
malformedRest("unknown status context state");
|
|
89
|
+
if (!Number.isFinite(Date.parse(status.created_at)))
|
|
90
|
+
malformedRest("status context created_at");
|
|
91
|
+
const old = latest.get(status.context);
|
|
92
|
+
if (!old ||
|
|
93
|
+
Date.parse(status.created_at) > Date.parse(old.created_at) ||
|
|
94
|
+
(status.created_at === old.created_at && status.id > old.id))
|
|
95
|
+
latest.set(status.context, status);
|
|
96
|
+
}
|
|
97
|
+
for (const status of latest.values())
|
|
98
|
+
nodes.push({
|
|
99
|
+
__typename: "StatusContext",
|
|
100
|
+
context: status.context,
|
|
101
|
+
state: status.state.toUpperCase(),
|
|
102
|
+
targetUrl: status.target_url,
|
|
103
|
+
description: status.description,
|
|
104
|
+
createdAt: status.created_at,
|
|
105
|
+
});
|
|
106
|
+
return {
|
|
107
|
+
nodes,
|
|
108
|
+
suites: suites.nodes,
|
|
109
|
+
workflowRuns: workflowRuns.nodes,
|
|
110
|
+
rateLimit: workflowRuns.rateLimit ?? checks.rateLimit,
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
export async function readRestAnnotationCounts(oid, repo) {
|
|
114
|
+
const checks = await readRestPages(`${restRepoPath(repo)}/commits/${encodeURIComponent(oid)}/check-runs?filter=latest`, (body) => restCollection(body, "check_runs"));
|
|
115
|
+
return checks.nodes.map((check) => ({
|
|
116
|
+
__typename: "CheckRun",
|
|
117
|
+
id: restString(check.node_id, "check node_id"),
|
|
118
|
+
annotations: { totalCount: restNumber(check.output?.annotations_count, "annotations_count") },
|
|
119
|
+
}));
|
|
120
|
+
}
|
|
121
|
+
export async function readRestBehind(repo, base, head) {
|
|
122
|
+
const comparison = await rest("GET", `${restRepoPath(repo)}/compare/${encodeURIComponent(base)}...${encodeURIComponent(head)}`);
|
|
123
|
+
return restNumber(comparison.behind_by, "compare behind_by");
|
|
124
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { RestComment } from "./rest-feedback-read.mts";
|
|
2
|
+
export declare function restCommentAuthorFields(comment: RestComment, viewerLogin?: string | null): {
|
|
3
|
+
author: string;
|
|
4
|
+
authorType: import("../types.mts").AuthorType;
|
|
5
|
+
viewerDidAuthor?: true | undefined;
|
|
6
|
+
authorAssociation: import("../types.mts").CommentAuthorAssociation;
|
|
7
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { mapAuthorType } from "./batch-parser-helpers.mjs";
|
|
2
|
+
export function restCommentAuthorFields(comment, viewerLogin) {
|
|
3
|
+
const login = typeof comment.user?.login === "string" ? comment.user.login : undefined;
|
|
4
|
+
return {
|
|
5
|
+
author: login ?? "unknown",
|
|
6
|
+
authorType: mapAuthorType(comment.user?.type, login),
|
|
7
|
+
...(viewerLogin &&
|
|
8
|
+
login?.toLowerCase() === viewerLogin.toLowerCase() && { viewerDidAuthor: true }),
|
|
9
|
+
...(comment.author_association && { authorAssociation: comment.author_association }),
|
|
10
|
+
};
|
|
11
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { StateKey } from "../state/rest-cache.mts";
|
|
2
|
+
export interface RestSnapshotState {
|
|
3
|
+
/**
|
|
4
|
+
* True when at least one conditional read answered 304 and every other read was a settled body
|
|
5
|
+
* without an ETag (fingerprinted by content instead). Any changed ETag-bearing body is fresh.
|
|
6
|
+
*/
|
|
7
|
+
allNotModified: boolean;
|
|
8
|
+
/** Stable digest of every (path, validator) the snapshot observed. */
|
|
9
|
+
digest: string;
|
|
10
|
+
}
|
|
11
|
+
export declare function withRestConditionalScope<T>(key: StateKey, fn: () => Promise<T>): Promise<T>;
|
|
12
|
+
export declare function currentRestConditionalKey(): StateKey | undefined;
|
|
13
|
+
/**
|
|
14
|
+
* Record how one read was answered. `contentBody` is passed only for a settled 200 that carried
|
|
15
|
+
* no ETag: a route that cannot answer 304 (the Claude Code cloud proxy's `/ccr/review_threads`
|
|
16
|
+
* may not send validators) is then validated by a hash of its content, so an unchanged body
|
|
17
|
+
* still lets the snapshot's digest match. Every other non-304 read is fresh and blocks reuse.
|
|
18
|
+
*/
|
|
19
|
+
export declare function recordRestConditionalRead(path: string, notModified: boolean, etag: string | undefined, contentBody?: unknown): void;
|
|
20
|
+
export declare function restSnapshotState(): RestSnapshotState | undefined;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
2
|
+
import { createHash } from "node:crypto";
|
|
3
|
+
const storage = new AsyncLocalStorage();
|
|
4
|
+
export function withRestConditionalScope(key, fn) {
|
|
5
|
+
return storage.run({ key, fresh: 0, notModified: 0, etags: new Map() }, fn);
|
|
6
|
+
}
|
|
7
|
+
export function currentRestConditionalKey() {
|
|
8
|
+
return storage.getStore()?.key;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Record how one read was answered. `contentBody` is passed only for a settled 200 that carried
|
|
12
|
+
* no ETag: a route that cannot answer 304 (the Claude Code cloud proxy's `/ccr/review_threads`
|
|
13
|
+
* may not send validators) is then validated by a hash of its content, so an unchanged body
|
|
14
|
+
* still lets the snapshot's digest match. Every other non-304 read is fresh and blocks reuse.
|
|
15
|
+
*/
|
|
16
|
+
export function recordRestConditionalRead(path, notModified, etag, contentBody) {
|
|
17
|
+
const scope = storage.getStore();
|
|
18
|
+
if (scope === undefined)
|
|
19
|
+
return;
|
|
20
|
+
if (notModified)
|
|
21
|
+
scope.notModified += 1;
|
|
22
|
+
else if (etag !== undefined || contentBody === undefined)
|
|
23
|
+
scope.fresh += 1;
|
|
24
|
+
scope.etags.set(path, etag ?? (contentBody === undefined ? "" : `content:${contentDigest(contentBody)}`));
|
|
25
|
+
}
|
|
26
|
+
function contentDigest(body) {
|
|
27
|
+
return createHash("sha256")
|
|
28
|
+
.update(JSON.stringify(body) ?? "")
|
|
29
|
+
.digest("hex")
|
|
30
|
+
.slice(0, 16);
|
|
31
|
+
}
|
|
32
|
+
export function restSnapshotState() {
|
|
33
|
+
const scope = storage.getStore();
|
|
34
|
+
if (scope === undefined)
|
|
35
|
+
return undefined;
|
|
36
|
+
const hash = createHash("sha256");
|
|
37
|
+
for (const [path, etag] of [...scope.etags].sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0))) {
|
|
38
|
+
hash.update(`${path}\0${etag}\0`);
|
|
39
|
+
}
|
|
40
|
+
return {
|
|
41
|
+
allNotModified: scope.fresh === 0 && scope.notModified > 0,
|
|
42
|
+
digest: hash.digest("hex").slice(0, 16),
|
|
43
|
+
};
|
|
44
|
+
}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { RepoInfo } from "./client.mts";
|
|
2
|
+
/** One principal read for this explicit PR chunk, without assuming its PRs are standalone. */
|
|
3
|
+
export declare function readRestExplicitSummary(prs: number[], repo: RepoInfo): Promise<import("./poll-summary-raw.mts").RawSummaryPr[]>;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { fetchRestRawSummaryPr } from "./rest-batch-read.mjs";
|
|
2
|
+
import { readRestViewerLogin } from "./rest-viewer-read.mjs";
|
|
3
|
+
import { mapPool } from "../util/pool.mjs";
|
|
4
|
+
/** One principal read for this explicit PR chunk, without assuming its PRs are standalone. */
|
|
5
|
+
export async function readRestExplicitSummary(prs, repo) {
|
|
6
|
+
const viewerLogin = await readRestViewerLogin();
|
|
7
|
+
return mapPool(prs, 4, (pr) => fetchRestRawSummaryPr(pr, repo, undefined, viewerLogin));
|
|
8
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { RepoInfo } from "./client.mts";
|
|
2
|
+
import type { PrComment, Review, ReviewThread, CommentAuthorAssociation } from "../types.mts";
|
|
3
|
+
export interface RestComment {
|
|
4
|
+
id: number;
|
|
5
|
+
node_id: string;
|
|
6
|
+
body: string;
|
|
7
|
+
html_url: string;
|
|
8
|
+
created_at: string;
|
|
9
|
+
updated_at: string;
|
|
10
|
+
user: {
|
|
11
|
+
login: string;
|
|
12
|
+
type: string;
|
|
13
|
+
} | null;
|
|
14
|
+
author_association: CommentAuthorAssociation;
|
|
15
|
+
in_reply_to_id?: number;
|
|
16
|
+
pull_request_review_id?: number;
|
|
17
|
+
path?: string;
|
|
18
|
+
line?: number | null;
|
|
19
|
+
start_line?: number | null;
|
|
20
|
+
}
|
|
21
|
+
export interface RestReview extends RestComment {
|
|
22
|
+
state: string;
|
|
23
|
+
commit_id: string;
|
|
24
|
+
submitted_at?: string | null;
|
|
25
|
+
}
|
|
26
|
+
export declare function readRestFeedback(pr: number, repo: RepoInfo, knownViewerLogin?: string | null): Promise<{
|
|
27
|
+
threads: ReviewThread[];
|
|
28
|
+
comments: PrComment[];
|
|
29
|
+
reviews: RestReview[];
|
|
30
|
+
unavailable: {
|
|
31
|
+
field: string;
|
|
32
|
+
reason: string;
|
|
33
|
+
}[];
|
|
34
|
+
viewerLogin: string | null;
|
|
35
|
+
}>;
|
|
36
|
+
export declare function restReviewToReview(review: RestReview): Review;
|