pr-shepherd 0.56.5 → 0.57.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/plugin.json +1 -1
- package/README.md +44 -27
- package/bin/api.d.mts +25 -3
- package/bin/api.mjs +51 -13
- package/bin/checks/classify.d.mts +1 -0
- package/bin/checks/classify.mjs +1 -1
- package/bin/checks/conclusions.d.mts +5 -1
- package/bin/checks/conclusions.mjs +8 -2
- package/bin/checks/superseded.d.mts +8 -2
- package/bin/checks/superseded.mjs +24 -7
- package/bin/classify/loader.d.mts +2 -0
- package/bin/classify/loader.mjs +15 -0
- package/bin/classify/standard/author.d.mts +3 -0
- package/bin/classify/standard/author.mjs +10 -0
- package/bin/classify/standard/codecov-report.d.mts +4 -0
- package/bin/classify/standard/codecov-report.mjs +10 -0
- package/bin/classify/standard/coderabbit-notices.d.mts +8 -0
- package/bin/classify/standard/coderabbit-notices.mjs +38 -0
- package/bin/classify/standard/coderabbit-review-summary.d.mts +8 -0
- package/bin/classify/standard/coderabbit-review-summary.mjs +37 -0
- package/bin/classify/standard/codex-notices.d.mts +7 -0
- package/bin/classify/standard/codex-notices.mjs +36 -0
- package/bin/classify/standard/codex-review-summary.d.mts +7 -0
- package/bin/classify/standard/codex-review-summary.mjs +20 -0
- package/bin/classify/standard/dependabot-notices.d.mts +4 -0
- package/bin/classify/standard/dependabot-notices.mjs +15 -0
- package/bin/classify/standard/gemini-notices.d.mts +4 -0
- package/bin/classify/standard/gemini-notices.mjs +13 -0
- package/bin/classify/standard/index.d.mts +4 -0
- package/bin/classify/standard/index.mjs +22 -0
- package/bin/classify/standard/kilo-no-issues.d.mts +4 -0
- package/bin/classify/standard/kilo-no-issues.mjs +17 -0
- package/bin/classify/standard/sourcery-notices.d.mts +8 -0
- package/bin/classify/standard/sourcery-notices.mjs +20 -0
- package/bin/cli/api-usage-formatter.mjs +6 -1
- package/bin/cli/apply-merge-handler.d.mts +3 -0
- package/bin/cli/apply-merge-handler.mjs +73 -0
- package/bin/cli/arg-flags.d.mts +2 -0
- package/bin/cli/arg-flags.mjs +47 -0
- package/bin/cli/args.mjs +10 -41
- package/bin/cli/clean-handler.d.mts +1 -0
- package/bin/cli/clean-handler.mjs +71 -0
- package/bin/cli/default-poll.mjs +3 -0
- package/bin/cli/event-state-scope.d.mts +19 -0
- package/bin/cli/event-state-scope.mjs +60 -0
- package/bin/cli/fix-formatter.mjs +5 -11
- package/bin/cli/handlers.d.mts +0 -1
- package/bin/cli/handlers.mjs +8 -64
- package/bin/cli/help-command-pages.d.mts +62 -18
- package/bin/cli/help-command-pages.mjs +59 -15
- package/bin/cli/help-iterate-poll-pages.d.mts +2 -2
- package/bin/cli/help-iterate-poll-pages.mjs +6 -0
- package/bin/cli/help-log-file-page.d.mts +1 -1
- package/bin/cli/help-log-file-page.mjs +4 -1
- package/bin/cli/help-top-page.d.mts +1 -1
- package/bin/cli/help-top-page.mjs +5 -0
- package/bin/cli/help.d.mts +63 -19
- package/bin/cli/help.mjs +2 -0
- package/bin/cli/iterate-branch-segment.d.mts +2 -0
- package/bin/cli/iterate-branch-segment.mjs +12 -7
- package/bin/cli/iterate-flags.d.mts +7 -1
- package/bin/cli/iterate-flags.mjs +38 -0
- package/bin/cli/iterate-formatter.d.mts +6 -6
- package/bin/cli/iterate-formatter.mjs +56 -22
- package/bin/cli/iterate-instructions.mjs +45 -15
- package/bin/cli/iterate-lean.mjs +39 -14
- package/bin/cli/iterate-merge-formatter.d.mts +6 -0
- package/bin/cli/iterate-merge-formatter.mjs +24 -14
- package/bin/cli/iterate-verbose.mjs +3 -6
- package/bin/cli/list-formatters.mjs +3 -1
- package/bin/cli/mutate-formatter.mjs +10 -5
- package/bin/cli/next-check-format.d.mts +7 -0
- package/bin/cli/next-check-format.mjs +10 -0
- package/bin/cli/playbook-handler.d.mts +5 -0
- package/bin/cli/playbook-handler.mjs +40 -0
- package/bin/cli/poll-handler.mjs +7 -6
- package/bin/cli/poll-summary-formatter.mjs +11 -2
- package/bin/cli/poll-targets.mjs +2 -0
- package/bin/cli/resolve-validators.mjs +2 -2
- package/bin/cli/runner.mjs +6 -1
- package/bin/cli/stack-layer-view.d.mts +33 -0
- package/bin/cli/stack-layer-view.mjs +1 -0
- package/bin/cli/stack-overview.d.mts +10 -28
- package/bin/cli/stack-overview.mjs +39 -14
- package/bin/cli/transport-args.d.mts +5 -0
- package/bin/cli/transport-args.mjs +23 -0
- package/bin/cli/transport-formatter.d.mts +9 -0
- package/bin/cli/transport-formatter.mjs +13 -0
- package/bin/cli-parser.mjs +62 -7
- package/bin/commands/apply-merge-options.d.mts +4 -0
- package/bin/commands/apply-merge-options.mjs +34 -0
- package/bin/commands/apply-merge-output.d.mts +7 -0
- package/bin/commands/apply-merge-output.mjs +20 -0
- package/bin/commands/apply-merge-pull.d.mts +20 -0
- package/bin/commands/apply-merge-pull.mjs +15 -0
- package/bin/commands/apply-merge.d.mts +18 -0
- package/bin/commands/apply-merge.mjs +126 -0
- package/bin/commands/apply-queue-removal.mjs +7 -0
- package/bin/commands/check-annotations.mjs +28 -18
- package/bin/commands/check-execution-context.d.mts +5 -0
- package/bin/commands/check-execution-context.mjs +16 -1
- package/bin/commands/check-fingerprint.d.mts +26 -2
- package/bin/commands/check-fingerprint.mjs +64 -28
- package/bin/commands/check-terminal-report.mjs +11 -1
- package/bin/commands/check-unreported.d.mts +6 -2
- package/bin/commands/check-unreported.mjs +32 -12
- package/bin/commands/check-wait-detectors.d.mts +35 -0
- package/bin/commands/check-wait-detectors.mjs +107 -0
- package/bin/commands/check.d.mts +4 -2
- package/bin/commands/check.mjs +130 -40
- package/bin/commands/event-instructions.d.mts +11 -0
- package/bin/commands/event-instructions.mjs +27 -0
- package/bin/commands/event-mode.d.mts +14 -0
- package/bin/commands/event-mode.mjs +138 -0
- package/bin/commands/iterate/api-usage.mjs +4 -2
- package/bin/commands/iterate/base.mjs +4 -0
- package/bin/commands/iterate/check-blocker-gate.mjs +14 -2
- package/bin/commands/iterate/check-instructions.d.mts +9 -10
- package/bin/commands/iterate/check-instructions.mjs +23 -22
- package/bin/commands/iterate/classify.mjs +19 -5
- package/bin/commands/iterate/escalate.mjs +13 -3
- package/bin/commands/iterate/fix-code.mjs +40 -19
- package/bin/commands/iterate/fix-instruction-threads.d.mts +0 -8
- package/bin/commands/iterate/fix-instruction-threads.mjs +0 -16
- package/bin/commands/iterate/fix-loop-instruction.d.mts +9 -0
- package/bin/commands/iterate/fix-loop-instruction.mjs +35 -0
- package/bin/commands/iterate/helpers.mjs +15 -2
- package/bin/commands/iterate/index.mjs +26 -4
- package/bin/commands/iterate/mark-ready.mjs +50 -10
- package/bin/commands/iterate/merge-plan.d.mts +19 -0
- package/bin/commands/iterate/merge-plan.mjs +88 -0
- package/bin/commands/iterate/merge-state.mjs +3 -0
- package/bin/commands/iterate/merge.d.mts +4 -15
- package/bin/commands/iterate/merge.mjs +18 -51
- package/bin/commands/iterate/merged-base-pull-requests.d.mts +2 -6
- package/bin/commands/iterate/merged-base-pull-requests.mjs +15 -11
- package/bin/commands/iterate/native-stack-rebase.d.mts +6 -5
- package/bin/commands/iterate/native-stack-rebase.mjs +24 -7
- package/bin/commands/iterate/render.d.mts +8 -2
- package/bin/commands/iterate/render.mjs +28 -42
- package/bin/commands/iterate/stack-trunk-conflict.d.mts +4 -2
- package/bin/commands/iterate/stack-trunk-conflict.mjs +44 -19
- package/bin/commands/iterate/stale-ancestry.mjs +4 -1
- package/bin/commands/iterate/stall.d.mts +5 -1
- package/bin/commands/iterate/stall.mjs +19 -7
- package/bin/commands/iterate/thread-mutation-routing.d.mts +1 -0
- package/bin/commands/iterate/thread-mutation-routing.mjs +4 -2
- package/bin/commands/iterate/unreported-required.mjs +5 -2
- package/bin/commands/mark-files-as-viewed.mjs +7 -0
- package/bin/commands/next-check.d.mts +31 -0
- package/bin/commands/next-check.mjs +46 -0
- package/bin/commands/playbook.d.mts +13 -0
- package/bin/commands/playbook.mjs +48 -0
- package/bin/commands/poll-mode.d.mts +8 -0
- package/bin/commands/poll-mode.mjs +14 -0
- package/bin/commands/poll-progress.d.mts +1 -0
- package/bin/commands/poll-progress.mjs +6 -3
- package/bin/commands/poll-quota.d.mts +3 -2
- package/bin/commands/poll-quota.mjs +7 -3
- package/bin/commands/poll-summary-explicit-instructions.d.mts +2 -0
- package/bin/commands/poll-summary-explicit-instructions.mjs +10 -1
- package/bin/commands/poll-summary-instructions.mjs +16 -17
- package/bin/commands/poll-summary.mjs +42 -17
- package/bin/commands/poll.d.mts +0 -1
- package/bin/commands/poll.mjs +11 -19
- package/bin/commands/quota-selection.d.mts +2 -1
- package/bin/commands/quota-selection.mjs +12 -7
- package/bin/commands/resolve-mutate.mjs +33 -5
- package/bin/commands/rest-stack-merge-readiness.d.mts +4 -0
- package/bin/commands/rest-stack-merge-readiness.mjs +74 -0
- package/bin/commands/rule-auto-resolve.mjs +9 -3
- package/bin/commands/shepherd-journal.d.mts +5 -4
- package/bin/commands/shepherd-journal.mjs +9 -8
- package/bin/commands/stack-drain.d.mts +1 -9
- package/bin/commands/stack-drain.mjs +50 -37
- package/bin/commands/stack-handoffs.d.mts +10 -0
- package/bin/commands/stack-handoffs.mjs +25 -0
- package/bin/commands/stack-stall.d.mts +5 -0
- package/bin/commands/stack-stall.mjs +11 -0
- package/bin/commands/stack-work.d.mts +5 -0
- package/bin/commands/stack-work.mjs +32 -0
- package/bin/comments/existing-reply-scan.d.mts +17 -0
- package/bin/comments/existing-reply-scan.mjs +41 -0
- package/bin/comments/rate-limit.mjs +2 -2
- package/bin/comments/resolve.d.mts +7 -1
- package/bin/comments/resolve.mjs +108 -18
- package/bin/comments/rest-reply.d.mts +9 -0
- package/bin/comments/rest-reply.mjs +95 -0
- package/bin/comments/rest-review-mutations.d.mts +22 -0
- package/bin/comments/rest-review-mutations.mjs +125 -0
- package/bin/comments/review-visibility.d.mts +1 -1
- package/bin/comments/review-visibility.mjs +3 -2
- package/bin/comments/sha-poll.mjs +7 -3
- package/bin/comments/thread-visibility.mjs +10 -5
- package/bin/comments/uncertain-replies.d.mts +11 -0
- package/bin/comments/uncertain-replies.mjs +121 -0
- package/bin/comments/uncertain-reply-guards.d.mts +10 -0
- package/bin/comments/uncertain-reply-guards.mjs +94 -0
- package/bin/comments/visible-comments.d.mts +1 -1
- package/bin/comments/visible-comments.mjs +4 -2
- package/bin/config/load.d.mts +37 -1
- package/bin/config/load.mjs +73 -1
- package/bin/config.json +6 -2
- package/bin/exit-codes.d.mts +3 -0
- package/bin/exit-codes.mjs +8 -0
- package/bin/github/api-telemetry-aggregate.d.mts +15 -4
- package/bin/github/api-telemetry-aggregate.mjs +57 -18
- package/bin/github/api-telemetry.d.mts +4 -0
- package/bin/github/api-telemetry.mjs +22 -8
- package/bin/github/apply-review-preflight.d.mts +20 -0
- package/bin/github/apply-review-preflight.mjs +61 -0
- package/bin/github/base-behind-cache.d.mts +15 -0
- package/bin/github/base-behind-cache.mjs +18 -0
- package/bin/github/batch-parse-suites.d.mts +4 -2
- package/bin/github/batch-parse-suites.mjs +6 -1
- package/bin/github/batch-parser-helpers.mjs +40 -2
- package/bin/github/batch-parsers.mjs +1 -0
- package/bin/github/batch-raw-rules.d.mts +26 -0
- package/bin/github/batch-raw-types.d.mts +8 -6
- package/bin/github/batch-stack-evidence.d.mts +28 -0
- package/bin/github/batch-stack-evidence.mjs +62 -0
- package/bin/github/batch.d.mts +15 -2
- package/bin/github/batch.mjs +34 -17
- package/bin/github/check-annotations-batch.d.mts +0 -5
- package/bin/github/check-annotations-batch.mjs +25 -4
- package/bin/github/check-annotations.mjs +3 -1
- package/bin/github/client.d.mts +8 -19
- package/bin/github/client.mjs +45 -13
- package/bin/github/fingerprint-fields.d.mts +8 -0
- package/bin/github/fingerprint-fields.mjs +6 -1
- package/bin/github/fingerprint.d.mts +4 -2
- package/bin/github/fingerprint.mjs +6 -38
- package/bin/github/github-fetch.d.mts +2 -0
- package/bin/github/github-fetch.mjs +19 -0
- package/bin/github/gql/base-behind.gql +3 -0
- package/bin/github/gql/batch-pr-page.gql +16 -0
- package/bin/github/gql/batch-pr.gql +57 -0
- package/bin/github/gql/commit-check-contexts.gql +17 -0
- package/bin/github/gql/get-pr-body.gql +1 -0
- package/bin/github/gql/poll-stack-summary.gql +1 -0
- package/bin/github/gql/poll-summary-check-contexts.gql +5 -0
- package/bin/github/gql/poll-summary-fragment.gql +65 -15
- package/bin/github/gql/stack-handoff-check-runs.gql +42 -0
- package/bin/github/gql/upper-layer-conflict-target.gql +0 -15
- package/bin/github/graphql-http.mjs +9 -4
- package/bin/github/graphql-internal-retry.d.mts +2 -0
- package/bin/github/graphql-internal-retry.mjs +1 -1
- package/bin/github/graphql-quota-probe.d.mts +6 -0
- package/bin/github/graphql-quota-probe.mjs +56 -0
- package/bin/github/graphql-session-refusal.d.mts +8 -0
- package/bin/github/graphql-session-refusal.mjs +14 -0
- package/bin/github/http-request.d.mts +1 -1
- package/bin/github/http-request.mjs +22 -6
- package/bin/github/http-utils.mjs +6 -0
- package/bin/github/merge-target-rules.d.mts +16 -3
- package/bin/github/merge-target-rules.mjs +79 -44
- package/bin/github/mutation-policy.d.mts +6 -0
- package/bin/github/mutation-policy.mjs +21 -0
- package/bin/github/poll-summary-annotation-probe.mjs +17 -10
- package/bin/github/poll-summary-check-blockers.d.mts +1 -1
- package/bin/github/poll-summary-check-blockers.mjs +2 -2
- package/bin/github/poll-summary-check-hydration.mjs +25 -10
- package/bin/github/poll-summary-checks.d.mts +2 -2
- package/bin/github/poll-summary-checks.mjs +9 -6
- package/bin/github/poll-summary-command.d.mts +2 -0
- package/bin/github/poll-summary-command.mjs +24 -0
- package/bin/github/poll-summary-fingerprint.d.mts +1 -1
- package/bin/github/poll-summary-fingerprint.mjs +4 -2
- package/bin/github/poll-summary-handoff-fields.d.mts +3 -0
- package/bin/github/poll-summary-handoff-fields.mjs +73 -0
- package/bin/github/poll-summary-projector.d.mts +1 -1
- package/bin/github/poll-summary-projector.mjs +17 -24
- package/bin/github/poll-summary-raw.d.mts +70 -10
- package/bin/github/poll-summary-readiness.mjs +4 -1
- package/bin/github/poll-summary-rest-queue.d.mts +3 -0
- package/bin/github/poll-summary-rest-queue.mjs +12 -0
- package/bin/github/poll-summary-review.d.mts +1 -1
- package/bin/github/poll-summary-review.mjs +23 -11
- package/bin/github/poll-summary-route.mjs +19 -3
- package/bin/github/poll-summary-stack-page.d.mts +11 -0
- package/bin/github/poll-summary-stack-page.mjs +27 -0
- package/bin/github/poll-summary-unreported.d.mts +6 -3
- package/bin/github/poll-summary-unreported.mjs +15 -7
- package/bin/github/poll-summary.d.mts +4 -1
- package/bin/github/poll-summary.mjs +48 -34
- package/bin/github/queries.d.mts +9 -5
- package/bin/github/queries.mjs +10 -6
- package/bin/github/rate-limit-sample.d.mts +7 -0
- package/bin/github/rate-limit-sample.mjs +12 -0
- package/bin/github/reply-recovery-read.d.mts +50 -0
- package/bin/github/reply-recovery-read.mjs +118 -0
- package/bin/github/reply-thread-transcripts.d.mts +0 -1
- package/bin/github/reply-thread-transcripts.mjs +24 -1
- package/bin/github/rest-annotation-read.d.mts +5 -0
- package/bin/github/rest-annotation-read.mjs +44 -0
- package/bin/github/rest-batch-read.d.mts +12 -0
- package/bin/github/rest-batch-read.mjs +57 -0
- package/bin/github/rest-batch-snapshot.d.mts +30 -0
- package/bin/github/rest-batch-snapshot.mjs +115 -0
- package/bin/github/rest-batch-unavailable.d.mts +5 -0
- package/bin/github/rest-batch-unavailable.mjs +16 -0
- package/bin/github/rest-check-read.d.mts +34 -0
- package/bin/github/rest-check-read.mjs +124 -0
- package/bin/github/rest-comment-authorship.d.mts +7 -0
- package/bin/github/rest-comment-authorship.mjs +11 -0
- package/bin/github/rest-conditional-scope.d.mts +20 -0
- package/bin/github/rest-conditional-scope.mjs +44 -0
- package/bin/github/rest-explicit-summary-read.d.mts +3 -0
- package/bin/github/rest-explicit-summary-read.mjs +8 -0
- package/bin/github/rest-feedback-read.d.mts +36 -0
- package/bin/github/rest-feedback-read.mjs +147 -0
- package/bin/github/rest-feedback-validation.d.mts +5 -0
- package/bin/github/rest-feedback-validation.mjs +28 -0
- package/bin/github/rest-http.d.mts +12 -0
- package/bin/github/rest-http.mjs +108 -23
- package/bin/github/rest-identities.d.mts +22 -0
- package/bin/github/rest-identities.mjs +134 -0
- package/bin/github/rest-merge-stack-guard.d.mts +14 -0
- package/bin/github/rest-merge-stack-guard.mjs +41 -0
- package/bin/github/rest-merge.d.mts +29 -0
- package/bin/github/rest-merge.mjs +56 -0
- package/bin/github/rest-merged-base-read.d.mts +9 -0
- package/bin/github/rest-merged-base-read.mjs +48 -0
- package/bin/github/rest-pr-core.d.mts +52 -0
- package/bin/github/rest-pr-core.mjs +60 -0
- package/bin/github/rest-reader-core.d.mts +16 -0
- package/bin/github/rest-reader-core.mjs +154 -0
- package/bin/github/rest-review-read.d.mts +11 -0
- package/bin/github/rest-review-read.mjs +47 -0
- package/bin/github/rest-rules-read.d.mts +9 -0
- package/bin/github/rest-rules-read.mjs +154 -0
- package/bin/github/rest-session-refusal.d.mts +5 -0
- package/bin/github/rest-session-refusal.mjs +21 -0
- package/bin/github/rest-snapshot-context.d.mts +10 -0
- package/bin/github/rest-snapshot-context.mjs +1 -0
- package/bin/github/rest-stack-read.d.mts +21 -0
- package/bin/github/rest-stack-read.mjs +47 -0
- package/bin/github/rest-stack-summary.d.mts +8 -0
- package/bin/github/rest-stack-summary.mjs +62 -0
- package/bin/github/rest-summary-read.d.mts +7 -0
- package/bin/github/rest-summary-read.mjs +112 -0
- package/bin/github/rest-terminal-batch.d.mts +14 -0
- package/bin/github/rest-terminal-batch.mjs +45 -0
- package/bin/github/rest-text.mjs +7 -3
- package/bin/github/rest-thread-read.d.mts +4 -0
- package/bin/github/rest-thread-read.mjs +35 -0
- package/bin/github/rest-viewer-read.d.mts +2 -0
- package/bin/github/rest-viewer-read.mjs +41 -0
- package/bin/github/stack-bottom.d.mts +3 -0
- package/bin/github/stack-bottom.mjs +14 -0
- package/bin/github/stack-handoff-context.d.mts +25 -0
- package/bin/github/stack-handoff-context.mjs +12 -0
- package/bin/github/stack-handoff-page.d.mts +17 -0
- package/bin/github/stack-handoff-page.mjs +306 -0
- package/bin/github/stack-handoff.d.mts +16 -0
- package/bin/github/stack-handoff.mjs +115 -0
- package/bin/github/stack-order.d.mts +6 -0
- package/bin/github/stack-order.mjs +13 -0
- package/bin/github/stack-read.d.mts +7 -3
- package/bin/github/stack-read.mjs +22 -11
- package/bin/github/stack-size-hint.d.mts +3 -0
- package/bin/github/stack-size-hint.mjs +14 -0
- package/bin/github/suggestion-thread.mjs +27 -1
- package/bin/github/thread-comments.mjs +9 -1
- package/bin/github/transport-evidence.d.mts +20 -0
- package/bin/github/transport-evidence.mjs +26 -0
- package/bin/github/transport-mode.d.mts +2 -0
- package/bin/github/transport-mode.mjs +5 -0
- package/bin/github/transport.d.mts +19 -0
- package/bin/github/transport.mjs +126 -0
- package/bin/github/unsupported-rest.d.mts +4 -0
- package/bin/github/unsupported-rest.mjs +7 -0
- package/bin/mcp/server.mjs +52 -3
- package/bin/merge-status/derive.d.mts +2 -0
- package/bin/merge-status/derive.mjs +17 -13
- package/bin/merge-status/required-check-requirements.d.mts +7 -0
- package/bin/merge-status/required-check-requirements.mjs +15 -0
- package/bin/merge-status/requirements-format.d.mts +5 -0
- package/bin/merge-status/requirements-format.mjs +41 -12
- package/bin/merge-status/requirements.mjs +18 -7
- package/bin/state/base.mjs +41 -0
- package/bin/state/durable-state.d.mts +6 -0
- package/bin/state/durable-state.mjs +41 -0
- package/bin/state/graphql-quota-policy.mjs +23 -16
- package/bin/state/merge-request.d.mts +25 -0
- package/bin/state/merge-request.mjs +145 -0
- package/bin/state/pr-fingerprint.d.mts +15 -0
- package/bin/state/pr-fingerprint.mjs +22 -7
- package/bin/state/rest-cache.d.mts +3 -0
- package/bin/state/rest-cache.mjs +1 -0
- package/bin/state/rest-snapshot-report.d.mts +21 -0
- package/bin/state/rest-snapshot-report.mjs +52 -0
- package/bin/state/seen-comments.d.mts +3 -0
- package/bin/state/seen-comments.mjs +18 -0
- package/bin/types/api-usage.d.mts +9 -1
- package/bin/types/escalate.d.mts +1 -1
- package/bin/types/github.d.mts +23 -9
- package/bin/types/iterate.d.mts +24 -2
- package/bin/types/merge-action.d.mts +1 -1
- package/bin/types/merge-requirements.d.mts +7 -7
- package/bin/types/next-check.d.mts +12 -0
- package/bin/types/next-check.mjs +1 -0
- package/bin/types/poll-summary.d.mts +21 -0
- package/bin/types/report.d.mts +13 -1
- package/bin/types/review-thread.d.mts +1 -1
- package/bin/types.d.mts +1 -0
- package/bin/types.mjs +1 -0
- package/package.json +3 -2
- package/plugins/pr-shepherd/.codex-plugin/plugin.json +1 -1
- package/plugins/pr-shepherd/.codex.mcp.json +1 -1
- package/plugins/pr-shepherd/.mcp.json +1 -1
- package/plugins/pr-shepherd/skills/mark-files-as-viewed/SKILL.md +1 -1
- package/plugins/pr-shepherd/skills/pr-shepherd/SKILL.md +14 -51
- package/plugins/pr-shepherd/skills/pr-shepherd/references/ci-failure-triage.md +12 -16
- package/plugins/pr-shepherd/skills/pr-shepherd/references/cloud-event-loop.md +14 -0
- package/plugins/pr-shepherd/skills/pr-shepherd/references/create-pr.md +10 -0
- package/plugins/pr-shepherd/skills/pr-shepherd/references/fix-code-loop.md +10 -0
- package/plugins/pr-shepherd/skills/pr-shepherd/references/mcp-fallback.md +9 -0
- package/plugins/pr-shepherd/skills/reduce-pr-noise/references/classifiers.md +2 -0
- package/bin/github/gql/pr-fingerprint.gql +0 -75
- package/plugins/pr-shepherd/skills/pr-shepherd/references/journal.md +0 -7
- package/plugins/pr-shepherd/skills/pr-shepherd/references/review-mutations.md +0 -9
- package/plugins/pr-shepherd/skills/pr-shepherd/references/stack-merge.md +0 -7
package/README.md
CHANGED
|
@@ -15,7 +15,7 @@ An agent finishing a PR should think about code, not reconstruct GitHub state or
|
|
|
15
15
|
|
|
16
16
|
Highlights:
|
|
17
17
|
|
|
18
|
-
-
|
|
18
|
+
- GraphQL by default, with a supported REST transport for Claude Code cloud sessions and narrowly defined automatic fallback. REST may expose less context; missing fields remain unknown. MCP `iterate` is one tick and the client owns recurrence; `--debounce` is a poll-dispatcher settle window, not an MCP tool.
|
|
19
19
|
- CI summaries include failed checks, and the failed job/step plus a log excerpt when triage can fetch them. Job and log details are omitted for `STARTUP_FAILURE` and `CANCELLED`; agents may still inspect logs.
|
|
20
20
|
- Handles GitHub comment types (comments, threads, replies) and their states, including first-look, outdated, resolved, minimized, and edited.
|
|
21
21
|
- `apply` batches resolve / reply / minimize / dismiss. `build_suggestion_patches` validates and returns ordered diffs without mutating git.
|
|
@@ -34,8 +34,8 @@ Each tick returns exactly one action:
|
|
|
34
34
|
- `WAIT` — no immediate action; continue with the next poll.
|
|
35
35
|
- `MARK_READY` — the CLI converted an eligible draft PR to ready; continue polling.
|
|
36
36
|
- `FIX_CODE` — agent work is required; complete it, push when needed, then continue polling. Push access to the PR head branch is a usage precondition.
|
|
37
|
-
- `MERGE` — run the emitted head-pinned
|
|
38
|
-
- `CANCEL` — stop polling this pull request because it merged, closed, or completed its ready-delay.
|
|
37
|
+
- `MERGE` — run the emitted head-pinned merge or queue command for the selected transport. GitHub is authoritative for the result and reports any authorization failure. Queue operations can use REST.
|
|
38
|
+
- `CANCEL` — stop polling this pull request because it merged, closed, or completed its ready-delay. It prints no instructions; continue any remaining pull requests or issues from the original request.
|
|
39
39
|
- `ESCALATE` — stop polling until a human provides direction. Native stacks reach this only after their autonomous one-PR sessions are exhausted.
|
|
40
40
|
|
|
41
41
|
Native-stack summaries additionally use stack-level `SHEPHERD`: run the listed one-PR sessions,
|
|
@@ -48,14 +48,12 @@ Example shape:
|
|
|
48
48
|
|
|
49
49
|
# PR #123 [FIX_CODE]
|
|
50
50
|
|
|
51
|
-
**status** `UNRESOLVED_COMMENTS` · **
|
|
51
|
+
**status** `UNRESOLVED_COMMENTS` · **repo** `owner/repo`
|
|
52
52
|
**summary** 3 passing
|
|
53
|
-
Approvals: None [Not Required]
|
|
54
|
-
Conversations Resolved: No [Not Required]
|
|
55
53
|
|
|
56
54
|
## Review threads
|
|
57
55
|
|
|
58
|
-
### `threadId=PRRT_kwDOSGizTs58XB1L` — `src/commands/iterate/index.mts:42` (@alice ·
|
|
56
|
+
### `threadId=PRRT_kwDOSGizTs58XB1L` — `src/commands/iterate/index.mts:42` (@alice · MEMBER)
|
|
59
57
|
|
|
60
58
|
> The variable name is misleading.
|
|
61
59
|
|
|
@@ -64,21 +62,14 @@ Conversations Resolved: No [Not Required]
|
|
|
64
62
|
- `24697658766` — `CI › lint / typecheck / test (22.x)` [conclusion: FAILURE]
|
|
65
63
|
> oxfmt
|
|
66
64
|
|
|
67
|
-
## Post-fix actions
|
|
68
|
-
|
|
69
|
-
- base: `main`
|
|
70
|
-
- apply review: `pr-shepherd apply review 123 --reply-thread-ids PRRT_kwDOSGizTs58XB1L --message "$DISMISS_MESSAGE" --require-sha "$HEAD_SHA"`
|
|
71
|
-
|
|
72
65
|
## Instructions
|
|
73
66
|
|
|
74
|
-
1.
|
|
75
|
-
2.
|
|
76
|
-
3.
|
|
77
|
-
4.
|
|
78
|
-
5.
|
|
79
|
-
6.
|
|
80
|
-
7. Run the `apply review:` command above. Playbook: "Review-mutation mechanics".
|
|
81
|
-
8. `[FIX_CODE]` is non-terminal. Iterate immediately with the same options.
|
|
67
|
+
1. Fix each warranted item.
|
|
68
|
+
2. Triage `## Failing checks`. Playbook: "CI failure triage".
|
|
69
|
+
3. Commit and push any changes.
|
|
70
|
+
4. Journal key decisions or rejections with URLs or IDs: `pr-shepherd apply journal 123 '- <decision>'`
|
|
71
|
+
5. `$DISMISS_MESSAGE`: one sentence on what changed. Run even if no code changed: `pr-shepherd apply review 123 --reply-thread-ids PRRT_kwDOSGizTs58XB1L --message "$DISMISS_MESSAGE" --require-sha HEAD`
|
|
72
|
+
6. Rerun Shepherd now.
|
|
82
73
|
```
|
|
83
74
|
|
|
84
75
|
See [docs/actions.md](docs/actions.md) for the complete output contract and [docs/escalations.md](docs/escalations.md) for the exact finite human-handoff boundary. Iterate/poll PR outcomes use exit codes `0` and `10`–`16`; command and GitHub failures use `sysexits.h` codes — [docs/exit-codes.md](docs/exit-codes.md).
|
|
@@ -94,7 +85,7 @@ This system is opinionated and works best with PRs that use required status chec
|
|
|
94
85
|
- Draft PRs can be marked ready automatically when clean; disable with `actions.autoMarkReady: false` or `--no-auto-mark-ready`.
|
|
95
86
|
- With `--merge`, actionable review threads/comments/reviews/summaries are held back (`WAIT`, with raw deferred-work counts) while a PR sits in the merge queue, since a Shepherd-initiated push would eject it; set `actions.workWhileQueued: true` to act on them immediately instead. Failing checks and merge conflicts are never deferred.
|
|
96
87
|
- The CLI never performs git mutations itself — it only emits commit/push instructions for the agent to run. Push access to the PR head is a usage precondition; GitHub viewer fields do not create a separate push-authorization handoff.
|
|
97
|
-
- Generated iterate mutations
|
|
88
|
+
- Generated iterate mutations use capability fields when the transport supplies them. With REST, capability is unknown and otherwise eligible mutations are attempted; GitHub's response is authoritative. Explicit `apply` operations forward the caller's requested IDs and surface GitHub's result.
|
|
98
89
|
- `build_suggestion_patches` turns one or more ordered GitHub suggestion threads into checked patches and commit metadata, but never edits the working tree or git history. Local HEAD may be ahead when the live PR head is its ancestor.
|
|
99
90
|
|
|
100
91
|
## Usage
|
|
@@ -135,6 +126,9 @@ pr-shepherd 42 --debounce 5m # wait 5m after first FIX_CODE or stack S
|
|
|
135
126
|
pr-shepherd 42 --ready-delay 15m
|
|
136
127
|
pr-shepherd 42 --merge # request head-pinned auto-merge/queue; GitHub reports the result
|
|
137
128
|
pr-shepherd iterate 42 # single tick
|
|
129
|
+
pr-shepherd 42 --instructions playbook # fold invariant fix_code steps into a playbook pointer (default: inline)
|
|
130
|
+
pr-shepherd 42 --poll-mode event # one tick, no sleeping; prints nextCheck (default under CLAUDE_CODE_REMOTE=true)
|
|
131
|
+
pr-shepherd playbook "Fix-code loop" # print a bundled skill playbook (no name lists them)
|
|
138
132
|
pr-shepherd owner/repo#42 # poll a PR in an explicit repository
|
|
139
133
|
pr-shepherd https://github.com/owner/repo/pull/42
|
|
140
134
|
pr-shepherd 42 43 44 # summarize an explicit same-repository set
|
|
@@ -144,13 +138,16 @@ pr-shepherd --stack 43 # summarize every PR in a native GitHub s
|
|
|
144
138
|
A user-supplied `--merge` authorizes the agent to run the emitted merge/enqueue commands for the
|
|
145
139
|
selected PRs or stack without another conversational confirmation. Host permission checks still apply.
|
|
146
140
|
|
|
147
|
-
Multi-PR and `--stack` polling use compact, read-only
|
|
141
|
+
Multi-PR and `--stack` polling use compact, read-only summaries from the selected transport.
|
|
142
|
+
GraphQL mode uses GraphQL summaries; REST mode preserves unavailable fields as unknown. They return when work is
|
|
148
143
|
needed, every selected PR is complete, the bounded timeout expires, or `--until-terminal` crosses a
|
|
149
144
|
configured GraphQL quota-warning band. Explicit PR sets give each actionable row an exact single-PR
|
|
150
145
|
`pollCommand`, so independent rows can proceed before the next aggregate poll.
|
|
151
146
|
|
|
152
147
|
Native-stack rows are ordered bottom-to-top. `--stack` never performs a mutation itself. Every
|
|
153
|
-
|
|
148
|
+
row marks ownership by comparing its author with the authenticated viewer; REST reads `/user`
|
|
149
|
+
for that identity without inferring viewer permissions. Sessions act only on rows marked `owned`. Every
|
|
150
|
+
owned layer that still has work gets its own one-PR session on the same tick, including a clean draft
|
|
154
151
|
whose session marks it ready. Layers do not wait for a lower layer's READY receipt, so their
|
|
155
152
|
ready-delays overlap. With automatic mark-ready disabled, the instructions ask the agent to mark
|
|
156
153
|
a clean draft ready after its probe. A queued stack, or one whose remaining layers can only wait,
|
|
@@ -161,14 +158,20 @@ until then, `SHEPHERD` remains the immediate action and lists the human blockers
|
|
|
161
158
|
|
|
162
159
|
With `--stack --merge`, the highest open layer whose open lower layers all have current READY
|
|
163
160
|
receipts, and whose bottom open layer GitHub has retargeted onto the stack base, returns `MERGE`
|
|
164
|
-
with
|
|
161
|
+
with the transport-specific stack merge command and allowed method. GraphQL mode uses
|
|
162
|
+
`gh stack merge <that PR number> --yes`; REST mode uses the SHA-pinned
|
|
163
|
+
`pr-shepherd apply merge` command, using the trunk's known queue policy even when the named layer
|
|
164
|
+
targets its parent branch. The command binds the observed stack, trunk, and ordered prefix with
|
|
165
|
+
`--expected-stack` and rejects a changed stack before submission. Unknown REST queue policy uses
|
|
166
|
+
`default` without a merge method. Known queue requests omit the configured direct merge method.
|
|
167
|
+
That lands the named layer and every
|
|
165
168
|
unmerged layer below it. When the base uses a merge queue, the same command queues the prefix
|
|
166
169
|
together and GitHub evaluates each layer from the bottom; a failure ejects that layer and those
|
|
167
170
|
above it. For a `failed_checks` removal on the layer's first ejection, the one-PR session emits a head-, queue-commit-, and timestamp-pinned local acknowledgment command; run it only when the failure does not reproduce after updating from the latest base, the head did not change, and no source changes or other blockers remain. Fresh source checks and a new READY receipt then let the aggregate selector recover the eligible prefix. Manual or stale removals cannot use this path. Layers above the prefix keep their one-PR sessions. After the merge, GitHub retargets
|
|
168
171
|
the next layer, so the rerun continues until the stack returns `CANCEL`. API and MCP aggregate
|
|
169
172
|
calls perform one summary tick and leave recurrence to the caller.
|
|
170
173
|
|
|
171
|
-
Polling defaults can be set under `poll` in `.pr-shepherdrc.yml`: `intervalSeconds` (built-in 60 for one PR), `stackIntervalFactor` (built-in 2, so `--stack` and multi-PR polls wait 120s), `timeoutSeconds`, `debounceSeconds`, and `
|
|
174
|
+
Polling defaults can be set under `poll` in `.pr-shepherdrc.yml`: `intervalSeconds` (built-in 60 for one PR), `stackIntervalFactor` (built-in 2, so `--stack` and multi-PR polls wait 120s), `timeoutSeconds`, `debounceSeconds`, `quietStatus`, and `reconcileSeconds` (built-in 900; the longest an idle GraphQL wait replays its last snapshot while REST change detectors are unchanged). Explicit `--interval` overrides either period for that invocation and is not multiplied. Other explicit flags override configuration, including `--no-quiet-status` when a shared config enables quiet output. Quiet status remains off by default. Quota-warning bands stay multiples of `intervalSeconds`; the dispatcher sleeps the slower of the effective interval and the active band, so a default stack waits 120s until a tighter band is slower than that.
|
|
172
175
|
|
|
173
176
|
### Apply Review And Journal Changes, Or Select Files
|
|
174
177
|
|
|
@@ -193,7 +196,8 @@ containers and ignores journal-shaped examples hidden in Markdown constructs. Th
|
|
|
193
196
|
including append and reconciliation helpers, is documented in [docs/api.md](docs/api.md).
|
|
194
197
|
|
|
195
198
|
MCP clients can call `extract_journal({ body: prBody })` for the same pure result without writing a
|
|
196
|
-
file, or `get_journal({ pr: "owner/repo#123" })` to fetch a PR body through
|
|
199
|
+
file, or `get_journal({ pr: "owner/repo#123" })` to fetch a PR body through the selected
|
|
200
|
+
transport and extract it.
|
|
197
201
|
Both return the typed extraction JSON in `structuredContent` and `content`; neither mutates the PR.
|
|
198
202
|
|
|
199
203
|
For shell automation that already has a PR body, use the equivalent local-only command:
|
|
@@ -209,6 +213,8 @@ Unsupported platforms fail closed with that same exit code.
|
|
|
209
213
|
|
|
210
214
|
### Clean Local State
|
|
211
215
|
|
|
216
|
+
In Claude Code cloud sessions, [event mode](docs/cloud.md) runs one tick per event or wake-up instead of sleeping, and the default state directory moves into the repository's common directory.
|
|
217
|
+
|
|
212
218
|
`pr-shepherd` stores seen markers, fix-attempt counters, stall fingerprints, ready-delay markers, and logs under `$PR_SHEPHERD_STATE_DIR` (default: `pr-shepherd-state` in the per-user temp dir; see [configuration](docs/configuration.md#environment-variables)).
|
|
213
219
|
|
|
214
220
|
```sh
|
|
@@ -314,6 +320,17 @@ For guided noise reduction, use the plugin's `reduce-pr-noise` skill. It loads f
|
|
|
314
320
|
|
|
315
321
|
### Classification rules
|
|
316
322
|
|
|
323
|
+
For common vendor bot noise (CodeRabbit and Gemini rate-limit notices, Codex usage-limit and review boilerplate, Codecov reports, and more), enable the bundled rules instead of writing your own:
|
|
324
|
+
|
|
325
|
+
```yaml
|
|
326
|
+
# .pr-shepherdrc.yml
|
|
327
|
+
classify:
|
|
328
|
+
standard:
|
|
329
|
+
all: true
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
See [`classify.standard`](docs/configuration.md#classifystandard--default-) for the rule list and per-rule overrides. Write custom rules for repository-specific policy.
|
|
333
|
+
|
|
317
334
|
Drop `.ts` / `.mts` / `.mjs` / `.js` files under `.pr-shepherd/classification/` to suppress and/or auto-resolve specific bot comments — useful for silencing repetitive noise like rate-limit notices from `gemini-code-assist` or "Reviews paused" from `coderabbitai`.
|
|
318
335
|
|
|
319
336
|
```ts
|
|
@@ -328,7 +345,7 @@ const rule: ClassifyRule = (item) => {
|
|
|
328
345
|
export default rule;
|
|
329
346
|
```
|
|
330
347
|
|
|
331
|
-
`suppress: true` hides the item from agent output. `autoResolve: true` queues it for the minimize/resolve mutation. `reason` is an optional note. When both flags apply together and `actions.autoMinimizeSuppressed` is `true` (the default), Shepherd
|
|
348
|
+
`suppress: true` hides the item from agent output. `autoResolve: true` queues it for the minimize/resolve mutation. `reason` is an optional note. When both flags apply together and `actions.autoMinimizeSuppressed` is `true` (the default), Shepherd attempts supported operations and relies on GitHub's response when capability is unknown. Confirmed successes are recorded on `threads.autoResolved` and `comments.autoMinimized`, printed once as `## Classification auto-resolve` before `## Instructions` (the same `ruleAutoResolve` object in JSON), and appended as one Shepherd Journal list item attributed to the token login. Distinct rule reasons are included. Failed IDs stay on the generated `apply review` command, and each failure is an extra bullet in that section. A journal write failure is reported the same way and does not undo the GitHub resolve or minimize. `actions.autoMinimizeSuppressed: false` leaves the IDs on that command and does not mutate, journal, or print the line. Denied review mutations are surfaced once then skipped; REST comment minimization is unsupported and is surfaced as a one-look skip. See [transport behavior](docs/rest.md).
|
|
332
349
|
|
|
333
350
|
TypeScript rules are loaded by the runtime's native TypeScript support; keep them to erasable syntax such as type annotations and `import type`. Runtime TypeScript features that need transpilation, such as enums, namespaces, parameter properties, and decorators, are not supported. Use `.mts` for portable ESM rules across Node, Bun, and Deno.
|
|
334
351
|
|
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
|
+
}
|