pr-shepherd 0.56.6 → 0.57.1
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 +150 -280
- 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/codex-notices.d.mts +8 -0
- package/bin/classify/standard/codex-notices.mjs +34 -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 +7 -0
- package/bin/classify/standard/index.mjs +21 -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 +57 -16
- 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/captured-proxy-agent.d.mts +3 -0
- package/bin/github/captured-proxy-agent.mjs +8 -0
- 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 +32 -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/legacy-dispatcher.d.mts +6 -0
- package/bin/github/legacy-dispatcher.mjs +44 -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.d.mts +6 -1
- package/bin/github/poll-summary-readiness.mjs +13 -4
- 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 +35 -20
- 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 +4 -3
- 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 +3 -1
- package/bin/github/gql/pr-fingerprint.gql +0 -75
- package/plugins/pr-shepherd/skills/pr-shepherd/references/journal.md +0 -7
- package/plugins/pr-shepherd/skills/pr-shepherd/references/review-mutations.md +0 -9
- package/plugins/pr-shepherd/skills/pr-shepherd/references/stack-merge.md +0 -7
package/bin/api.d.mts
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
import { type GithubTransport } from "./github/transport.mts";
|
|
2
|
+
export type { GithubTransport } from "./github/transport.mts";
|
|
3
|
+
import { type ApplyMergeResult } from "./commands/apply-merge.mts";
|
|
4
|
+
import type { RestMergeAction, RestMergeStackGuard } from "./github/rest-merge.mts";
|
|
5
|
+
export type { RestMergeStackGuard } from "./github/rest-merge.mts";
|
|
6
|
+
import type { MergeMethod } from "./config/merge-method.mts";
|
|
1
7
|
import { type JournalResult } from "./commands/journal/index.mts";
|
|
2
8
|
import { type MarkFilesAsViewedResult } from "./commands/mark-files-as-viewed.mts";
|
|
3
9
|
import { type ApplyQueueRemovalResult } from "./commands/apply-queue-removal.mts";
|
|
@@ -5,12 +11,14 @@ import type { ResolveResult } from "./comments/resolve.mts";
|
|
|
5
11
|
import type { BuildSuggestionPatchesResult, CommitSuggestionResult, IterateCommandOptions, IterateResult, PollSummaryResult } from "./types.mts";
|
|
6
12
|
import { type ShepherdJournalExtraction } from "./journal/index.mts";
|
|
7
13
|
export interface CreatePrShepherdOptions {
|
|
14
|
+
/** GitHub transport retained for this client; individual calls may override it. */
|
|
15
|
+
transport?: GithubTransport;
|
|
8
16
|
/** Working directory used for git, config, and classification-rule lookups. */
|
|
9
17
|
cwd?: string;
|
|
10
18
|
}
|
|
11
19
|
/** A positive PR number, GitHub pull-request URL, or owner/repo#number reference. */
|
|
12
20
|
export type PrReference = number | string;
|
|
13
|
-
type IterateOptions = Omit<IterateCommandOptions, "format" | "prNumber" | "targetRepository" | "persistSeen" | "fingerprintCache" | "deferQuotaWarning" | "quotaWarningMinimumPollIntervalMinutes">;
|
|
21
|
+
type IterateOptions = Omit<IterateCommandOptions, "format" | "prNumber" | "targetRepository" | "persistSeen" | "fingerprintCache" | "stallDeadlineSink" | "deferQuotaWarning" | "quotaWarningMinimumPollIntervalMinutes">;
|
|
14
22
|
export type SingleIterateInput = IterateOptions & {
|
|
15
23
|
pr?: PrReference;
|
|
16
24
|
prs?: never;
|
|
@@ -34,6 +42,7 @@ export interface ReviewMutationsOperation {
|
|
|
34
42
|
dismissReviewIds?: string[];
|
|
35
43
|
/** Required when replying to a thread or dismissing a review. */
|
|
36
44
|
message?: string;
|
|
45
|
+
/** `HEAD` (this checkout's commit) or a full SHA the PR head must match before mutating. */
|
|
37
46
|
requireSha?: string;
|
|
38
47
|
}
|
|
39
48
|
export interface MarkFilesViewedOperation {
|
|
@@ -54,14 +63,25 @@ export interface AcknowledgeQueueRemovalOperation {
|
|
|
54
63
|
queueCommitOid: string;
|
|
55
64
|
removedAtUnix: number;
|
|
56
65
|
}
|
|
66
|
+
export interface MergeOperation {
|
|
67
|
+
type: "merge";
|
|
68
|
+
requireSha: string;
|
|
69
|
+
mergeAction: RestMergeAction;
|
|
70
|
+
mergeMethod?: MergeMethod;
|
|
71
|
+
expectedStack?: RestMergeStackGuard;
|
|
72
|
+
}
|
|
57
73
|
/** Operations run in this exact list order after validation. */
|
|
58
|
-
export type ApplyOperation = ReviewMutationsOperation | MarkFilesViewedOperation | AppendJournalOperation | AcknowledgeQueueRemovalOperation;
|
|
74
|
+
export type ApplyOperation = MergeOperation | ReviewMutationsOperation | MarkFilesViewedOperation | AppendJournalOperation | AcknowledgeQueueRemovalOperation;
|
|
59
75
|
export interface ApplyInput {
|
|
76
|
+
transport?: GithubTransport;
|
|
60
77
|
/** PR shared by every operation in this ordered apply request. */
|
|
61
78
|
pr?: PrReference;
|
|
62
79
|
operations: ApplyOperation[];
|
|
63
80
|
}
|
|
64
81
|
export type ApplyOperationResult = {
|
|
82
|
+
type: "merge";
|
|
83
|
+
result: ApplyMergeResult;
|
|
84
|
+
} | {
|
|
65
85
|
type: "review_mutations";
|
|
66
86
|
result: ResolveResult;
|
|
67
87
|
} | {
|
|
@@ -78,6 +98,7 @@ export interface ApplyResult {
|
|
|
78
98
|
operations: ApplyOperationResult[];
|
|
79
99
|
}
|
|
80
100
|
export interface BuildSuggestionPatchInput {
|
|
101
|
+
transport?: GithubTransport;
|
|
81
102
|
pr?: PrReference;
|
|
82
103
|
threadId: string;
|
|
83
104
|
message: string;
|
|
@@ -89,10 +110,12 @@ export interface SuggestionPatchInput {
|
|
|
89
110
|
description?: string;
|
|
90
111
|
}
|
|
91
112
|
export interface BuildSuggestionPatchesInput {
|
|
113
|
+
transport?: GithubTransport;
|
|
92
114
|
pr?: PrReference;
|
|
93
115
|
suggestions: SuggestionPatchInput[];
|
|
94
116
|
}
|
|
95
117
|
export interface GetJournalInput {
|
|
118
|
+
transport?: GithubTransport;
|
|
96
119
|
pr: PrReference;
|
|
97
120
|
}
|
|
98
121
|
export interface PrShepherd {
|
|
@@ -120,4 +143,3 @@ export declare class PartialApplyError extends Error {
|
|
|
120
143
|
* read/plan, ordered apply, and suggestion-patch operations.
|
|
121
144
|
*/
|
|
122
145
|
export declare function createPrShepherd(options?: CreatePrShepherdOptions): PrShepherd;
|
|
123
|
-
export {};
|
package/bin/api.mjs
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
/* eslint-disable max-lines */
|
|
2
2
|
import { resolve } from "node:path";
|
|
3
|
+
import { createGithubTransportRunner } from "./github/transport.mjs";
|
|
4
|
+
import { runApplyMerge, validateApplyMergeOptions, } from "./commands/apply-merge.mjs";
|
|
3
5
|
import { runCommitSuggestion } from "./commands/commit-suggestion.mjs";
|
|
4
6
|
import { runSuggestionPatches } from "./commands/suggestion-patches.mjs";
|
|
5
|
-
import {
|
|
6
|
-
import { runPollSummary } from "./commands/poll-summary.mjs";
|
|
7
|
+
import { runIterateForMode, runPollSummaryForMode } from "./commands/event-mode.mjs";
|
|
7
8
|
import { runJournal } from "./commands/journal/index.mjs";
|
|
8
9
|
import { validateJournalItem } from "./commands/journal/transform.mjs";
|
|
9
10
|
import { runMarkFilesAsViewed, } from "./commands/mark-files-as-viewed.mjs";
|
|
@@ -12,6 +13,7 @@ import { applyQueueRemovalAck, } from "./commands/apply-queue-removal.mjs";
|
|
|
12
13
|
import { runWithExecutionCwd } from "./execution-context.mjs";
|
|
13
14
|
import { parsePrReference, normalizeRepositoryIdentity, resolveParsedPrTarget, } from "./pr-reference.mjs";
|
|
14
15
|
import { getPullRequestBody, getRepoInfo } from "./github/client.mjs";
|
|
16
|
+
import { getLocalHeadSha } from "./commands/suggestion-patch-git.mjs";
|
|
15
17
|
import { extractShepherdJournal } from "./journal/index.mjs";
|
|
16
18
|
/** Raised before any API mutation when an input cannot be validated. */
|
|
17
19
|
export class PrShepherdValidationError extends Error {
|
|
@@ -38,22 +40,26 @@ export class PartialApplyError extends Error {
|
|
|
38
40
|
*/
|
|
39
41
|
export function createPrShepherd(options = {}) {
|
|
40
42
|
const cwd = options.cwd === undefined ? undefined : resolve(options.cwd);
|
|
43
|
+
const transportRunner = createGithubTransportRunner(options.transport);
|
|
44
|
+
function runInClient(input, work) {
|
|
45
|
+
return runWithExecutionCwd(cwd, () => transportRunner(work, input?.transport));
|
|
46
|
+
}
|
|
41
47
|
function iterate(input = {}) {
|
|
42
|
-
return
|
|
48
|
+
return runInClient(input, async () => {
|
|
43
49
|
validateIterateSelectors(input);
|
|
44
50
|
if ("prs" in input || "stack" in input) {
|
|
45
51
|
const target = await resolveAggregateIterateInput(input);
|
|
46
|
-
return
|
|
52
|
+
return runPollSummaryForMode(target);
|
|
47
53
|
}
|
|
48
54
|
const { pr: _pr, ...iterateOptions } = input;
|
|
49
55
|
const target = resolvePrReference(input.pr);
|
|
50
|
-
return
|
|
56
|
+
return runIterateForMode({ ...iterateOptions, ...target, format: "json" });
|
|
51
57
|
});
|
|
52
58
|
}
|
|
53
59
|
return Object.freeze({
|
|
54
60
|
iterate,
|
|
55
61
|
getJournal(input) {
|
|
56
|
-
return
|
|
62
|
+
return runInClient(input, async () => {
|
|
57
63
|
const { prNumber, targetRepository } = resolvePrReference(input.pr);
|
|
58
64
|
if (!prNumber)
|
|
59
65
|
throw new PrShepherdValidationError("getJournal requires a PR reference");
|
|
@@ -63,7 +69,7 @@ export function createPrShepherd(options = {}) {
|
|
|
63
69
|
});
|
|
64
70
|
},
|
|
65
71
|
apply(input) {
|
|
66
|
-
return
|
|
72
|
+
return runInClient(input, async () => {
|
|
67
73
|
validateApplyInput(input);
|
|
68
74
|
const { prNumber, targetRepository } = resolvePrReference(input.pr);
|
|
69
75
|
const results = [];
|
|
@@ -71,16 +77,32 @@ export function createPrShepherd(options = {}) {
|
|
|
71
77
|
const operation = input.operations[index];
|
|
72
78
|
try {
|
|
73
79
|
switch (operation.type) {
|
|
80
|
+
case "merge": {
|
|
81
|
+
const result = await runApplyMerge({
|
|
82
|
+
prNumber,
|
|
83
|
+
targetRepository,
|
|
84
|
+
requireSha: operation.requireSha,
|
|
85
|
+
mergeAction: operation.mergeAction,
|
|
86
|
+
mergeMethod: operation.mergeMethod,
|
|
87
|
+
expectedStack: operation.expectedStack,
|
|
88
|
+
});
|
|
89
|
+
results.push({ type: operation.type, result });
|
|
90
|
+
break;
|
|
91
|
+
}
|
|
74
92
|
case "review_mutations": {
|
|
75
93
|
const { type: _type, message, ...options } = operation;
|
|
76
94
|
const result = await runResolveMutate({
|
|
77
95
|
...options,
|
|
96
|
+
// `HEAD` names this checkout's commit, the same form the printed CLI command uses.
|
|
97
|
+
requireSha: options.requireSha === "HEAD" ? await getLocalHeadSha() : options.requireSha,
|
|
78
98
|
prNumber,
|
|
79
99
|
targetRepository,
|
|
80
100
|
dismissMessage: message,
|
|
81
101
|
format: "json",
|
|
82
102
|
});
|
|
83
103
|
results.push({ type: operation.type, result });
|
|
104
|
+
if (result.sessionRefusal)
|
|
105
|
+
return { operations: results };
|
|
84
106
|
break;
|
|
85
107
|
}
|
|
86
108
|
case "mark_files_viewed": {
|
|
@@ -130,7 +152,7 @@ export function createPrShepherd(options = {}) {
|
|
|
130
152
|
buildSuggestionPatch(input) {
|
|
131
153
|
validateSuggestionPatchInput(input);
|
|
132
154
|
const { pr: _pr, ...options } = input;
|
|
133
|
-
return
|
|
155
|
+
return runInClient(input, async () => {
|
|
134
156
|
const target = resolvePrReference(input.pr);
|
|
135
157
|
return runCommitSuggestion({ ...options, ...target, format: "json" });
|
|
136
158
|
});
|
|
@@ -138,7 +160,7 @@ export function createPrShepherd(options = {}) {
|
|
|
138
160
|
buildSuggestionPatches(input) {
|
|
139
161
|
validateSuggestionPatchesInput(input);
|
|
140
162
|
const { pr: _pr, ...options } = input;
|
|
141
|
-
return
|
|
163
|
+
return runInClient(input, async () => {
|
|
142
164
|
const target = resolvePrReference(input.pr);
|
|
143
165
|
return runSuggestionPatches({ ...options, ...target, format: "json" });
|
|
144
166
|
});
|
|
@@ -190,15 +212,29 @@ function validateApplyInput(input) {
|
|
|
190
212
|
if (!input || !Array.isArray(input.operations) || input.operations.length === 0) {
|
|
191
213
|
throw new PrShepherdValidationError("apply requires a non-empty operations array");
|
|
192
214
|
}
|
|
193
|
-
|
|
215
|
+
const parsed = validatePrReference(input.pr);
|
|
216
|
+
for (const operation of input.operations) {
|
|
194
217
|
validateOperation(operation);
|
|
195
|
-
|
|
218
|
+
if (operation.type === "merge" &&
|
|
219
|
+
operation.expectedStack !== undefined &&
|
|
220
|
+
parsed.number !== undefined &&
|
|
221
|
+
operation.expectedStack.prefix.at(-1)?.pr !== parsed.number)
|
|
222
|
+
throw new PrShepherdValidationError("expectedStack prefix must end at the requested PR");
|
|
223
|
+
}
|
|
196
224
|
}
|
|
197
225
|
function validateOperation(operation) {
|
|
198
226
|
if (!operation || typeof operation !== "object") {
|
|
199
227
|
throw new PrShepherdValidationError("apply operation must be an object");
|
|
200
228
|
}
|
|
201
229
|
switch (operation.type) {
|
|
230
|
+
case "merge":
|
|
231
|
+
try {
|
|
232
|
+
validateApplyMergeOptions(operation);
|
|
233
|
+
}
|
|
234
|
+
catch (error) {
|
|
235
|
+
throw new PrShepherdValidationError(error instanceof Error ? error.message : String(error));
|
|
236
|
+
}
|
|
237
|
+
return;
|
|
202
238
|
case "review_mutations":
|
|
203
239
|
validateReviewMutations(operation);
|
|
204
240
|
return;
|
|
@@ -254,8 +290,10 @@ function validateReviewMutations(operation) {
|
|
|
254
290
|
if (operation.message !== undefined && typeof operation.message !== "string") {
|
|
255
291
|
throw new PrShepherdValidationError("review_mutations.message must be a string");
|
|
256
292
|
}
|
|
257
|
-
if (operation.requireSha !== undefined &&
|
|
258
|
-
|
|
293
|
+
if (operation.requireSha !== undefined &&
|
|
294
|
+
operation.requireSha !== "HEAD" &&
|
|
295
|
+
!/^[0-9a-f]{40}$/.test(operation.requireSha)) {
|
|
296
|
+
throw new PrShepherdValidationError("review_mutations.requireSha must be HEAD or a full 40-character lowercase hex SHA");
|
|
259
297
|
}
|
|
260
298
|
}
|
|
261
299
|
function validateMarkFilesViewed(operation) {
|
|
@@ -21,6 +21,7 @@ import type { CheckRun, ClassifiedCheck } from "../types.mts";
|
|
|
21
21
|
*/
|
|
22
22
|
export declare function classifyChecks(checks: CheckRun[], opts?: {
|
|
23
23
|
additionalRelevantEvents?: string[];
|
|
24
|
+
requiredContexts?: readonly string[];
|
|
24
25
|
}): ClassifiedCheck[];
|
|
25
26
|
export interface CiVerdict {
|
|
26
27
|
/** True when all relevant (non-filtered, non-skipped, non-ignored) checks passed. */
|
package/bin/checks/classify.mjs
CHANGED
|
@@ -30,7 +30,7 @@ export function classifyChecks(checks, opts = {}) {
|
|
|
30
30
|
const isIgnored = buildMatcher(config.ignoreChecks ?? []);
|
|
31
31
|
const isProtected = buildMatcher(config.actions.neverCancelRuns ?? []);
|
|
32
32
|
const protectedRunIds = buildProtectedRunIds(checks, isProtected);
|
|
33
|
-
const supersededIndices = buildSupersededIndices(checks);
|
|
33
|
+
const supersededIndices = buildSupersededIndices(checks, opts.requiredContexts);
|
|
34
34
|
return checks.map((c, index) => {
|
|
35
35
|
if (isIgnored(c.name) && !isProtectedCheck(c, protectedRunIds)) {
|
|
36
36
|
return { ...c, category: "ignored" };
|
|
@@ -4,8 +4,12 @@ import type { CheckConclusion, ViewerAuthorization } from "../types.mts";
|
|
|
4
4
|
* (`actions: write`, which rides with push access). The rerun runs against the base
|
|
5
5
|
* repo where the run lives, so `repositoryPermission` — not `headRepositoryPermission`,
|
|
6
6
|
* which covers fork push access — is the right field to gate on.
|
|
7
|
+
*
|
|
8
|
+
* REST exposes no viewer capability fields, so on a REST snapshot an unknown role does not deny
|
|
9
|
+
* the rerun: the recommended `gh run rerun` is attempted and GitHub's response decides. A role
|
|
10
|
+
* GitHub did report still gates the rerun.
|
|
7
11
|
*/
|
|
8
|
-
export declare function canRerunWorkflows(auth: ViewerAuthorization | undefined): boolean;
|
|
12
|
+
export declare function canRerunWorkflows(auth: ViewerAuthorization | undefined, transport?: "rest"): boolean;
|
|
9
13
|
/** Failing-check rows for formatter/instructions — excludes annotation-only carriers. */
|
|
10
14
|
export declare function isFailingAgentCheck(check: {
|
|
11
15
|
conclusion: CheckConclusion;
|
|
@@ -6,10 +6,16 @@ const RERUN_CAPABLE_PERMISSIONS = new Set(["WRITE", "MAINTAIN", "ADMIN"]);
|
|
|
6
6
|
* (`actions: write`, which rides with push access). The rerun runs against the base
|
|
7
7
|
* repo where the run lives, so `repositoryPermission` — not `headRepositoryPermission`,
|
|
8
8
|
* which covers fork push access — is the right field to gate on.
|
|
9
|
+
*
|
|
10
|
+
* REST exposes no viewer capability fields, so on a REST snapshot an unknown role does not deny
|
|
11
|
+
* the rerun: the recommended `gh run rerun` is attempted and GitHub's response decides. A role
|
|
12
|
+
* GitHub did report still gates the rerun.
|
|
9
13
|
*/
|
|
10
|
-
export function canRerunWorkflows(auth) {
|
|
14
|
+
export function canRerunWorkflows(auth, transport) {
|
|
11
15
|
const permission = auth?.repositoryPermission;
|
|
12
|
-
|
|
16
|
+
if (permission === undefined)
|
|
17
|
+
return transport === "rest";
|
|
18
|
+
return permission !== null && RERUN_CAPABLE_PERMISSIONS.has(permission);
|
|
13
19
|
}
|
|
14
20
|
/** True for conclusions that belong under `## Failing checks` (not success/skipped/neutral). */
|
|
15
21
|
function isFailingCheckConclusion(conclusion) {
|
|
@@ -3,6 +3,12 @@ import type { CheckRun } from "../types.mts";
|
|
|
3
3
|
/**
|
|
4
4
|
* A later-created run supersedes an older cancellation as before. GitHub can start
|
|
5
5
|
* check jobs out of run-ID order, so a lower-ID run can also cover a cancellation
|
|
6
|
-
* when its matching successful job actually started and completed later.
|
|
6
|
+
* when its matching successful job actually started and completed later. Cancelled
|
|
7
|
+
* wrappers can report completion before start; compare both observed boundaries
|
|
8
|
+
* without treating that reversed interval as a successful execution.
|
|
9
|
+
*
|
|
10
|
+
* The lower-ID form never covers a required context: GitHub's required gate reads the
|
|
11
|
+
* latest (highest-ID) run, so that cancellation still fails it (github/gh-stack#466).
|
|
12
|
+
* Neither does a newer run that lacks the context, for the same reason.
|
|
7
13
|
*/
|
|
8
|
-
export declare function buildSupersededIndices(checks: CheckRun[]): Set<number>;
|
|
14
|
+
export declare function buildSupersededIndices(checks: CheckRun[], requiredContexts?: readonly string[]): Set<number>;
|
|
@@ -17,7 +17,7 @@ function numericRunId(check) {
|
|
|
17
17
|
const id = Number(check.runId);
|
|
18
18
|
return Number.isSafeInteger(id) ? id : undefined;
|
|
19
19
|
}
|
|
20
|
-
function validTimes(check) {
|
|
20
|
+
function validTimes(check, requireOrdered = true) {
|
|
21
21
|
const { startedAtUnix: start, completedAtUnix: completion } = check;
|
|
22
22
|
return (typeof start === "number" &&
|
|
23
23
|
Number.isFinite(start) &&
|
|
@@ -25,14 +25,21 @@ function validTimes(check) {
|
|
|
25
25
|
typeof completion === "number" &&
|
|
26
26
|
Number.isFinite(completion) &&
|
|
27
27
|
completion > 0 &&
|
|
28
|
-
completion >= start);
|
|
28
|
+
(!requireOrdered || completion >= start));
|
|
29
29
|
}
|
|
30
30
|
/**
|
|
31
31
|
* A later-created run supersedes an older cancellation as before. GitHub can start
|
|
32
32
|
* check jobs out of run-ID order, so a lower-ID run can also cover a cancellation
|
|
33
|
-
* when its matching successful job actually started and completed later.
|
|
33
|
+
* when its matching successful job actually started and completed later. Cancelled
|
|
34
|
+
* wrappers can report completion before start; compare both observed boundaries
|
|
35
|
+
* without treating that reversed interval as a successful execution.
|
|
36
|
+
*
|
|
37
|
+
* The lower-ID form never covers a required context: GitHub's required gate reads the
|
|
38
|
+
* latest (highest-ID) run, so that cancellation still fails it (github/gh-stack#466).
|
|
39
|
+
* Neither does a newer run that lacks the context, for the same reason.
|
|
34
40
|
*/
|
|
35
|
-
export function buildSupersededIndices(checks) {
|
|
41
|
+
export function buildSupersededIndices(checks, requiredContexts = []) {
|
|
42
|
+
const required = new Set(requiredContexts.map((context) => context.trim()));
|
|
36
43
|
const maxRunIdByGroup = new Map();
|
|
37
44
|
const runIds = checks.map(numericRunId);
|
|
38
45
|
checks.forEach((check, index) => {
|
|
@@ -52,14 +59,18 @@ export function buildSupersededIndices(checks) {
|
|
|
52
59
|
const runId = runIds[index];
|
|
53
60
|
if (group === undefined || runId === undefined)
|
|
54
61
|
return;
|
|
62
|
+
const isRequired = required.has(cancelled.name.trim());
|
|
55
63
|
if (maxRunIdByGroup.get(group) > runId) {
|
|
56
|
-
|
|
64
|
+
// A required context is covered only by a newer run of the same context.
|
|
65
|
+
if (!isRequired || hasNewerSameName(checks, runIds, cancelled, group, runId))
|
|
66
|
+
superseded.add(index);
|
|
57
67
|
return;
|
|
58
68
|
}
|
|
59
|
-
if (
|
|
69
|
+
if (isRequired ||
|
|
70
|
+
cancelled.status !== "COMPLETED" ||
|
|
60
71
|
!cancelled.workflowId ||
|
|
61
72
|
cancelled.event === null ||
|
|
62
|
-
!validTimes(cancelled))
|
|
73
|
+
!validTimes(cancelled, false))
|
|
63
74
|
return;
|
|
64
75
|
const covered = checks.some((success, candidateIndex) => {
|
|
65
76
|
const candidateRunId = runIds[candidateIndex];
|
|
@@ -81,3 +92,9 @@ export function buildSupersededIndices(checks) {
|
|
|
81
92
|
});
|
|
82
93
|
return superseded;
|
|
83
94
|
}
|
|
95
|
+
function hasNewerSameName(checks, runIds, cancelled, group, runId) {
|
|
96
|
+
return checks.some((check, index) => runIds[index] !== undefined &&
|
|
97
|
+
runIds[index] > runId &&
|
|
98
|
+
check.name.trim() === cancelled.name.trim() &&
|
|
99
|
+
groupKeyOf(check) === group);
|
|
100
|
+
}
|
|
@@ -6,5 +6,7 @@ export interface LoadedRule {
|
|
|
6
6
|
}
|
|
7
7
|
export declare function discoverRuleFiles(cwd: string): string[];
|
|
8
8
|
export declare function loadRules(files: string[]): Promise<LoadedRule[]>;
|
|
9
|
+
/** Local `.pr-shepherd/classification/` rules followed by the enabled bundled rules. */
|
|
10
|
+
export declare function loadClassifyRules(cwd: string, standardRuleNames?: readonly string[]): Promise<LoadedRule[]>;
|
|
9
11
|
/** Reset the rule cache — for use in tests. */
|
|
10
12
|
export declare function _resetRuleCache(): void;
|
package/bin/classify/loader.mjs
CHANGED
|
@@ -10,6 +10,7 @@ import { readdirSync, statSync } from "node:fs";
|
|
|
10
10
|
import { join, dirname, extname, basename } from "node:path";
|
|
11
11
|
import { homedir } from "node:os";
|
|
12
12
|
import { pathToFileURL } from "node:url";
|
|
13
|
+
import { STANDARD_RULES } from "./standard/index.mjs";
|
|
13
14
|
const CLASSIFICATION_DIR = ".pr-shepherd/classification";
|
|
14
15
|
const VALID_EXTENSIONS = new Set([".ts", ".mts", ".mjs", ".js"]);
|
|
15
16
|
export function discoverRuleFiles(cwd) {
|
|
@@ -60,6 +61,20 @@ export async function loadRules(files) {
|
|
|
60
61
|
ruleCache.set(cacheKey, rules);
|
|
61
62
|
return rules;
|
|
62
63
|
}
|
|
64
|
+
/** Bundled rules enabled by `classify.standard`, named `standard:<rule>`. */
|
|
65
|
+
function standardRules(names) {
|
|
66
|
+
return names.flatMap((name) => {
|
|
67
|
+
const rule = STANDARD_RULES[name];
|
|
68
|
+
return rule === undefined
|
|
69
|
+
? []
|
|
70
|
+
: [{ name: `standard:${name}`, file: `pr-shepherd:standard/${name}`, rule }];
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
/** Local `.pr-shepherd/classification/` rules followed by the enabled bundled rules. */
|
|
74
|
+
export async function loadClassifyRules(cwd, standardRuleNames = []) {
|
|
75
|
+
const local = await loadRules(discoverRuleFiles(cwd));
|
|
76
|
+
return [...local, ...standardRules(standardRuleNames)];
|
|
77
|
+
}
|
|
63
78
|
/** Reset the rule cache — for use in tests. */
|
|
64
79
|
export function _resetRuleCache() {
|
|
65
80
|
ruleCache.clear();
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { ClassifyItem, ClassifyItemKind } from "../types.mts";
|
|
2
|
+
/** True when GitHub reports a bot author whose normalized login is one of `logins`. */
|
|
3
|
+
export declare function isBotItem(item: ClassifyItem, logins: readonly string[], kinds: readonly ClassifyItemKind[]): boolean;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/** Lowercased login without the REST `[bot]` suffix, so GraphQL and REST logins compare equal. */
|
|
2
|
+
function normalizeLogin(login) {
|
|
3
|
+
return login.toLowerCase().replace(/\[bot\]$/, "");
|
|
4
|
+
}
|
|
5
|
+
/** True when GitHub reports a bot author whose normalized login is one of `logins`. */
|
|
6
|
+
export function isBotItem(item, logins, kinds) {
|
|
7
|
+
return (item.authorType === "Bot" &&
|
|
8
|
+
kinds.includes(item.kind) &&
|
|
9
|
+
logins.includes(normalizeLogin(item.author)));
|
|
10
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { isBotItem } from "./author.mjs";
|
|
2
|
+
/** Codecov's coverage report comment. Coverage gates still report through their status checks. */
|
|
3
|
+
const rule = (item) => {
|
|
4
|
+
if (!isBotItem(item, ["codecov"], ["pr-comment"]))
|
|
5
|
+
return null;
|
|
6
|
+
if (!/^#{1,6}\s*\[?Codecov\b/i.test(item.body.trimStart()))
|
|
7
|
+
return null;
|
|
8
|
+
return { autoResolve: true, suppress: true, reason: "Codecov coverage report" };
|
|
9
|
+
};
|
|
10
|
+
export default rule;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { ClassifyRule } from "../types.mts";
|
|
2
|
+
/**
|
|
3
|
+
* CodeRabbit progress, rate-limit, review-skipped and draft notices, plus its "Action not
|
|
4
|
+
* completed" command replies. The summarize comment is later edited in place into the PR
|
|
5
|
+
* walkthrough, so the rule only hides it from agent output and never minimizes it.
|
|
6
|
+
*/
|
|
7
|
+
declare const rule: ClassifyRule;
|
|
8
|
+
export default rule;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { isBotItem } from "./author.mjs";
|
|
2
|
+
const NOTICE_ENVELOPE = /^<!-- This is an auto-generated comment: (rate limited|skip review|review in progress) by coderabbit.ai -->\n([\s\S]*?)\n<!-- end of auto-generated comment: \1 by coderabbit.ai -->$/;
|
|
3
|
+
const COMMAND_REPLY = /^<!-- This is an auto-generated reply by CodeRabbit -->\n<!-- CodeRabbit review command invocation: v2:[a-f0-9]+ -->\n<details>\n<summary>⚠️ Action not completed<\/summary>\n\n(?:Review rate limited\.|Review skipped: \d+ files exceed the limit of \d+\.)\n\n(?:> Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits\. This command is applicable only when automatic reviews are paused\.|---\n\nYour included review limit is currently reached under our \[Fair Usage Limits Policy\]\(https:\/\/docs.coderabbit.ai\/management\/plans#fair-usage-limits-policy\)\. This review may still proceed through usage-based billing if eligible\. Your next included review will be available in \d+ minutes?\.)\n\n<\/details>$/;
|
|
4
|
+
/** Strips CodeRabbit's footer and header blocks so only the notice envelope remains. */
|
|
5
|
+
function stripChrome(body) {
|
|
6
|
+
return body
|
|
7
|
+
.trim()
|
|
8
|
+
.replace(/\n<!-- tips_start -->[\s\S]*?<!-- tips_end -->$/, "")
|
|
9
|
+
.trim()
|
|
10
|
+
.replace(/\n<!-- autopilot:start -->[\s\S]*?<!-- autopilot:end -->$/, "")
|
|
11
|
+
.trim()
|
|
12
|
+
.replace(/^<!-- This is an auto-generated comment: summarize by coderabbit.ai -->\s*/, "")
|
|
13
|
+
.replace(/^<!-- review_stack_entry_start -->[\s\S]*?<!-- review_stack_entry_end -->\s*/, "");
|
|
14
|
+
}
|
|
15
|
+
function isQuotedNotice(quoted) {
|
|
16
|
+
const onlyQuotedLines = quoted.split("\n").every((line) => !line.trim() || line.startsWith(">"));
|
|
17
|
+
if (!onlyQuotedLines)
|
|
18
|
+
return false;
|
|
19
|
+
return (quoted.includes("> ## Review limit reached\n") ||
|
|
20
|
+
quoted.includes("> ## Draft PR not reviewed\n") ||
|
|
21
|
+
quoted.includes("> ## Review skipped\n") ||
|
|
22
|
+
quoted.includes("> Currently processing new changes in this PR. This may take a few minutes, please wait..."));
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* CodeRabbit progress, rate-limit, review-skipped and draft notices, plus its "Action not
|
|
26
|
+
* completed" command replies. The summarize comment is later edited in place into the PR
|
|
27
|
+
* walkthrough, so the rule only hides it from agent output and never minimizes it.
|
|
28
|
+
*/
|
|
29
|
+
const rule = (item) => {
|
|
30
|
+
if (!isBotItem(item, ["coderabbitai"], ["pr-comment"]))
|
|
31
|
+
return null;
|
|
32
|
+
const body = stripChrome(item.body);
|
|
33
|
+
const quoted = body.match(NOTICE_ENVELOPE)?.[2]?.trim();
|
|
34
|
+
if (!(quoted && isQuotedNotice(quoted)) && !COMMAND_REPLY.test(body))
|
|
35
|
+
return null;
|
|
36
|
+
return { suppress: true, reason: "CodeRabbit progress, review-limit, or skipped-review notice" };
|
|
37
|
+
};
|
|
38
|
+
export default rule;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { ClassifyRule } from "../types.mts";
|
|
2
|
+
/**
|
|
3
|
+
* Codex quota notices, the review-activity status table, and no-findings notices on conversation
|
|
4
|
+
* comments. Each pattern matches the whole comment, so a notice with any appended finding stays
|
|
5
|
+
* visible. Review summaries and inline comments are left for the normal review path.
|
|
6
|
+
*/
|
|
7
|
+
declare const rule: ClassifyRule;
|
|
8
|
+
export default rule;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { isBotItem } from "./author.mjs";
|
|
2
|
+
const QUOTA_NOTICES = [
|
|
3
|
+
/^You have reached your Codex usage limits for security reviews\. Please try again later\.$/,
|
|
4
|
+
/^You have reached your Codex usage limits for code reviews\. You can see your limits in the \[Codex usage dashboard\]\(https:\/\/chatgpt.com\/codex\/cloud\/settings\/usage\)\.(?:\nTo continue using code reviews, add credits to your account and enable them for code reviews in your \[settings\]\(https:\/\/chatgpt.com\/codex\/cloud\/settings\/code-review\)\.)?$/,
|
|
5
|
+
/^Codex usage limits have been reached for code reviews\. Please check with the admins of this repo to increase the limits by adding credits\.\nRepo admins can enable using credits for code reviews in their \[settings\]\(https:\/\/chatgpt.com\/codex\/cloud\/settings\/code-review\)\.$/,
|
|
6
|
+
/^Codex usage limits have been reached\. Please try again later\.$/,
|
|
7
|
+
];
|
|
8
|
+
const ABOUT_BLOCK = /\n\n<details> <summary>ℹ️ About Codex (?:in GitHub|security reviews in GitHub)<\/summary>[\s\S]*?<\/details>$/;
|
|
9
|
+
const ACTIVITY_SUMMARY = /^<!-- codex-pull-request-review-summary -->\n(?:<!-- codex-security-review:v1 \{[^\n]*\} -->\n)?\n?## Codex Review Summary\n\nThis comment shows the latest Codex review activity on this pull request\.\n\n\| Review \| Status \| Commit \| Review trigger \|\n\| --- \| --- \| --- \| --- \|\n(?:\|[^\n]+\|\n?)+$/;
|
|
10
|
+
const CLEAN_REVIEW = /^Codex Review: Didn't find any major issues\. (?:Bravo\.|Breezy!|Hooray!|:\+1:)\n\n\*\*Reviewed commit:\*\* `[a-f0-9]+`$/;
|
|
11
|
+
const CLEAN_SECURITY = /^### 🛡️ Codex Security Review(?: · _Automatically triggered_)?\n\nSecurity review completed\. No security issues were found in this pull request\.\n\n\*\*Reviewed commit:\*\* `[a-f0-9]+`\n\n\[View security finding report\]\(https:\/\/chatgpt.com\/codex\/cloud\/tasks\/[a-zA-Z0-9_]+\)\n\n_Only the user who started this review can view the report in Codex\._$/;
|
|
12
|
+
/**
|
|
13
|
+
* Codex quota notices, the review-activity status table, and no-findings notices on conversation
|
|
14
|
+
* comments. Each pattern matches the whole comment, so a notice with any appended finding stays
|
|
15
|
+
* visible. Review summaries and inline comments are left for the normal review path.
|
|
16
|
+
*/
|
|
17
|
+
const rule = (item) => {
|
|
18
|
+
if (!isBotItem(item, ["chatgpt-codex-connector"], ["pr-comment"]))
|
|
19
|
+
return null;
|
|
20
|
+
const body = item.body.trim();
|
|
21
|
+
if (QUOTA_NOTICES.some((notice) => notice.test(body))) {
|
|
22
|
+
return { autoResolve: true, suppress: true, reason: "Codex usage-limit notice" };
|
|
23
|
+
}
|
|
24
|
+
// Strip only the trailing About block; extra findings after it stay visible.
|
|
25
|
+
const content = body.replace(ABOUT_BLOCK, "").trim();
|
|
26
|
+
if (ACTIVITY_SUMMARY.test(content)) {
|
|
27
|
+
return { autoResolve: true, suppress: true, reason: "Codex review-activity table" };
|
|
28
|
+
}
|
|
29
|
+
if (CLEAN_REVIEW.test(content) || CLEAN_SECURITY.test(content)) {
|
|
30
|
+
return { autoResolve: true, suppress: true, reason: "Codex no-findings notice" };
|
|
31
|
+
}
|
|
32
|
+
return null;
|
|
33
|
+
};
|
|
34
|
+
export default rule;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { isBotItem } from "./author.mjs";
|
|
2
|
+
const NOTICES = [
|
|
3
|
+
/^Looks like this PR is already up-to-date with [^\s!]+! If you'd still like to recreate it from scratch, overwriting any edits, you can request `@dependabot recreate`\.$/,
|
|
4
|
+
/^Looks like these dependencies are updatable in another way, so this is no longer needed\.$/,
|
|
5
|
+
];
|
|
6
|
+
/** Dependabot's replies that report no change to make. */
|
|
7
|
+
const rule = (item) => {
|
|
8
|
+
if (!isBotItem(item, ["dependabot"], ["pr-comment"]))
|
|
9
|
+
return null;
|
|
10
|
+
const body = item.body.trim();
|
|
11
|
+
if (!NOTICES.some((notice) => notice.test(body)))
|
|
12
|
+
return null;
|
|
13
|
+
return { autoResolve: true, suppress: true, reason: "Dependabot no-op reply" };
|
|
14
|
+
};
|
|
15
|
+
export default rule;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { isBotItem } from "./author.mjs";
|
|
2
|
+
/** Gemini Code Assist daily-quota and review-limit notices on conversation comments. A heading means a real review. */
|
|
3
|
+
const rule = (item) => {
|
|
4
|
+
if (!isBotItem(item, ["gemini-code-assist"], ["pr-comment"]))
|
|
5
|
+
return null;
|
|
6
|
+
if (/^#{1,6}\s/m.test(item.body))
|
|
7
|
+
return null;
|
|
8
|
+
if (!/You have reached your daily quota limit|Review limit reached/i.test(item.body)) {
|
|
9
|
+
return null;
|
|
10
|
+
}
|
|
11
|
+
return { autoResolve: true, suppress: true, reason: "Gemini quota or review-limit notice" };
|
|
12
|
+
};
|
|
13
|
+
export default rule;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { ClassifyRule } from "../types.mts";
|
|
2
|
+
/**
|
|
3
|
+
* Bundled classification rules that `classify.standard` can enable by name.
|
|
4
|
+
* Each rule matches conversation comments (`pr-comment`) only.
|
|
5
|
+
*/
|
|
6
|
+
export declare const STANDARD_RULES: Readonly<Record<string, ClassifyRule>>;
|
|
7
|
+
export declare const STANDARD_RULE_NAMES: readonly string[];
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import coderabbitNotices from "./coderabbit-notices.mjs";
|
|
2
|
+
import codecovReport from "./codecov-report.mjs";
|
|
3
|
+
import codexNotices from "./codex-notices.mjs";
|
|
4
|
+
import dependabotNotices from "./dependabot-notices.mjs";
|
|
5
|
+
import geminiNotices from "./gemini-notices.mjs";
|
|
6
|
+
import kiloNoIssues from "./kilo-no-issues.mjs";
|
|
7
|
+
import sourceryNotices from "./sourcery-notices.mjs";
|
|
8
|
+
/**
|
|
9
|
+
* Bundled classification rules that `classify.standard` can enable by name.
|
|
10
|
+
* Each rule matches conversation comments (`pr-comment`) only.
|
|
11
|
+
*/
|
|
12
|
+
export const STANDARD_RULES = {
|
|
13
|
+
"coderabbit-notices": coderabbitNotices,
|
|
14
|
+
"codecov-report": codecovReport,
|
|
15
|
+
"codex-notices": codexNotices,
|
|
16
|
+
"dependabot-notices": dependabotNotices,
|
|
17
|
+
"gemini-notices": geminiNotices,
|
|
18
|
+
"kilo-no-issues": kiloNoIssues,
|
|
19
|
+
"sourcery-notices": sourceryNotices,
|
|
20
|
+
};
|
|
21
|
+
export const STANDARD_RULE_NAMES = Object.keys(STANDARD_RULES);
|