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/bin/commands/poll.mjs
CHANGED
|
@@ -2,18 +2,14 @@ import { runIterate } from "./iterate/index.mjs";
|
|
|
2
2
|
import { sleep } from "../util/sleep.mjs";
|
|
3
3
|
import { withPollApiUsage } from "./poll-run.mjs";
|
|
4
4
|
import { loadConfig } from "../config/load.mjs";
|
|
5
|
-
import { quotaPollIntervalMs } from "./poll-quota.mjs";
|
|
5
|
+
import { carryQuotaWarning, quotaPollIntervalMs } from "./poll-quota.mjs";
|
|
6
6
|
import { onePrCancelFromPulls, onePrRateLimitTargets } from "./poll-rate-limit-cancel.mjs";
|
|
7
7
|
import { createUntilTerminalRateLimitRetry } from "./poll-rate-limit-wait.mjs";
|
|
8
|
-
import { writeDebounceProgress, writeWaitProgress } from "./poll-progress.mjs";
|
|
9
|
-
|
|
10
|
-
if (result.ruleAutoResolve?.summary)
|
|
11
|
-
process.stderr.write(`${result.ruleAutoResolve.summary}\n`);
|
|
12
|
-
}
|
|
8
|
+
import { writeDebounceProgress, writeRuleAutoResolveProgress, writeWaitProgress, } from "./poll-progress.mjs";
|
|
9
|
+
import { getGithubTransport } from "../github/transport.mjs";
|
|
13
10
|
const DEFAULT_POLL_DEBOUNCE_SECONDS = 60;
|
|
14
11
|
const MAX_TIMER_MS = 2 ** 31 - 1;
|
|
15
12
|
const TIMER_DRIFT_TOLERANCE_MS = 500;
|
|
16
|
-
/** @deprecated Hidden implementation for the legacy `poll` alias. */
|
|
17
13
|
export function runPoll(opts) {
|
|
18
14
|
return withPollApiUsage(() => runPollCore(opts), opts.untilTerminal === true, opts.intervalSeconds / 60);
|
|
19
15
|
}
|
|
@@ -32,7 +28,6 @@ async function runPollCore(opts) {
|
|
|
32
28
|
const untilTerminal = untilTerminalOpt === true;
|
|
33
29
|
let lastWaitSignature = null;
|
|
34
30
|
let pendingQuotaWarning;
|
|
35
|
-
// Pin the PR resolved by the first tick; branch inference only matches OPEN PRs.
|
|
36
31
|
let prNumber = opts.prNumber;
|
|
37
32
|
let debounceUntil = null;
|
|
38
33
|
const rateLimitRetry = createUntilTerminalRateLimitRetry();
|
|
@@ -42,7 +37,6 @@ async function runPollCore(opts) {
|
|
|
42
37
|
const remainingBefore = untilTerminal
|
|
43
38
|
? Number.POSITIVE_INFINITY
|
|
44
39
|
: timeoutMs - (Date.now() - start);
|
|
45
|
-
// Cache only internal continuation ticks; returned ticks must fetch BatchPr.
|
|
46
40
|
const allowCache = debounceUntil === null && remainingBefore + TIMER_DRIFT_TOLERANCE_MS >= intervalMs;
|
|
47
41
|
const iterateTick = (fingerprintCache) => runIterate({
|
|
48
42
|
...iterateOpts,
|
|
@@ -75,14 +69,12 @@ async function runPollCore(opts) {
|
|
|
75
69
|
};
|
|
76
70
|
lastResult = await runTick(allowCache);
|
|
77
71
|
prNumber ??= lastResult.pr;
|
|
78
|
-
|
|
79
|
-
pendingQuotaWarning = lastResult.quotaWarning;
|
|
72
|
+
pendingQuotaWarning = carryQuotaWarning(pendingQuotaWarning, lastResult.quotaWarning);
|
|
80
73
|
const refreshIfReturning = async () => {
|
|
81
74
|
if (lastResult?.fingerprintReused !== true)
|
|
82
75
|
return;
|
|
83
76
|
lastResult = await runTick(false);
|
|
84
|
-
|
|
85
|
-
pendingQuotaWarning = lastResult.quotaWarning;
|
|
77
|
+
pendingQuotaWarning = carryQuotaWarning(pendingQuotaWarning, lastResult.quotaWarning);
|
|
86
78
|
};
|
|
87
79
|
if (untilTerminal &&
|
|
88
80
|
pendingQuotaWarning !== undefined &&
|
|
@@ -92,7 +84,7 @@ async function runPollCore(opts) {
|
|
|
92
84
|
if (lastResult.action === "fix_code" && debounceSeconds > 0 && !pastDebounce) {
|
|
93
85
|
debounceUntil ??= Date.now() + debounceMs;
|
|
94
86
|
const remainingMs = Math.max(debounceUntil - Date.now(), 0);
|
|
95
|
-
|
|
87
|
+
writeRuleAutoResolveProgress(lastResult);
|
|
96
88
|
writeDebounceProgress(tick, Date.now() - start, remainingMs);
|
|
97
89
|
await sleep(Math.min(intervalMs, remainingMs));
|
|
98
90
|
continue;
|
|
@@ -110,7 +102,7 @@ async function runPollCore(opts) {
|
|
|
110
102
|
if (pendingQuotaWarning === undefined)
|
|
111
103
|
debounceUntil = null;
|
|
112
104
|
const elapsedMs = Date.now() - start;
|
|
113
|
-
const sleepMs = quotaPollIntervalMs(quotaBands, lastResult.apiUsage, intervalMs, MAX_TIMER_MS);
|
|
105
|
+
const sleepMs = quotaPollIntervalMs(quotaBands, lastResult.apiUsage, intervalMs, MAX_TIMER_MS, getGithubTransport());
|
|
114
106
|
if (!untilTerminal) {
|
|
115
107
|
const remainingMs = timeoutMs - elapsedMs;
|
|
116
108
|
if (remainingMs <= 0 || remainingMs + TIMER_DRIFT_TOLERANCE_MS < sleepMs) {
|
|
@@ -127,7 +119,7 @@ async function runPollCore(opts) {
|
|
|
127
119
|
verbose,
|
|
128
120
|
lastWaitSignature,
|
|
129
121
|
});
|
|
130
|
-
|
|
122
|
+
writeRuleAutoResolveProgress(lastResult);
|
|
131
123
|
await sleep(sleepMs);
|
|
132
124
|
continue;
|
|
133
125
|
}
|
|
@@ -136,7 +128,7 @@ async function runPollCore(opts) {
|
|
|
136
128
|
!pastDebounce) {
|
|
137
129
|
debounceUntil = null;
|
|
138
130
|
const elapsedMs = Date.now() - start;
|
|
139
|
-
const sleepMs = quotaPollIntervalMs(quotaBands, lastResult.apiUsage, intervalMs, MAX_TIMER_MS);
|
|
131
|
+
const sleepMs = quotaPollIntervalMs(quotaBands, lastResult.apiUsage, intervalMs, MAX_TIMER_MS, getGithubTransport());
|
|
140
132
|
if (!untilTerminal) {
|
|
141
133
|
const remainingMs = timeoutMs - elapsedMs;
|
|
142
134
|
if (remainingMs <= 0 || remainingMs + TIMER_DRIFT_TOLERANCE_MS < sleepMs) {
|
|
@@ -144,12 +136,12 @@ async function runPollCore(opts) {
|
|
|
144
136
|
break;
|
|
145
137
|
}
|
|
146
138
|
}
|
|
147
|
-
|
|
139
|
+
writeRuleAutoResolveProgress(lastResult);
|
|
148
140
|
await sleep(sleepMs);
|
|
149
141
|
continue;
|
|
150
142
|
}
|
|
151
143
|
if (lastResult.action === "fix_code" && debounceSeconds > 0 && !pastDebounce) {
|
|
152
|
-
|
|
144
|
+
writeRuleAutoResolveProgress(lastResult);
|
|
153
145
|
debounceUntil ??= Date.now() + debounceMs;
|
|
154
146
|
const remainingMs = debounceUntil - Date.now();
|
|
155
147
|
if (remainingMs > 0) {
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import type { GraphqlQuotaWarningBand } from "../config/load.mts";
|
|
2
2
|
import type { ApiUsage, GraphqlQuotaWarning } from "../types.mts";
|
|
3
|
+
import type { GithubTransport } from "../github/transport.mts";
|
|
3
4
|
/** Claim GraphQL and REST core warnings separately, then present one result. */
|
|
4
5
|
export declare function selectQuotaWarning(key: {
|
|
5
6
|
owner: string;
|
|
6
7
|
repo: string;
|
|
7
|
-
}, bands: GraphqlQuotaWarningBand[], usage: ApiUsage, persist: boolean): Promise<GraphqlQuotaWarning | undefined>;
|
|
8
|
+
}, bands: GraphqlQuotaWarningBand[], usage: ApiUsage, persist: boolean, transport?: Exclude<GithubTransport, "auto">): Promise<GraphqlQuotaWarning | undefined>;
|
|
@@ -1,19 +1,24 @@
|
|
|
1
|
-
import { withGraphqlCredentialFingerprint } from "../github/api-telemetry.mjs";
|
|
1
|
+
import { withGraphqlCredentialFingerprint, withRestCoreCredentialFingerprint, } from "../github/api-telemetry.mjs";
|
|
2
2
|
import { composeQuotaWarning } from "../quota-budgets.mjs";
|
|
3
3
|
import { evaluateWorktreeGraphqlQuotaWarning } from "../state/graphql-quota-warnings.mjs";
|
|
4
4
|
/** Claim GraphQL and REST core warnings separately, then present one result. */
|
|
5
|
-
export async function selectQuotaWarning(key, bands, usage, persist) {
|
|
5
|
+
export async function selectQuotaWarning(key, bands, usage, persist, transport) {
|
|
6
6
|
const core = usage.rest?.find((item) => item.resource === "core");
|
|
7
|
-
const
|
|
8
|
-
|
|
7
|
+
const graphql = transport === "rest" ? undefined : usage.graphql;
|
|
8
|
+
// Capture provenance together with this usage snapshot before either async
|
|
9
|
+
// state evaluation can yield while newer requests update telemetry.
|
|
10
|
+
const graphqlSample = graphql ? withGraphqlCredentialFingerprint(graphql) : undefined;
|
|
11
|
+
const coreSample = core ? withRestCoreCredentialFingerprint(core) : undefined;
|
|
12
|
+
const graphqlWarning = graphqlSample
|
|
13
|
+
? await evaluateWorktreeGraphqlQuotaWarning(key, bands, graphqlSample, persist)
|
|
9
14
|
: undefined;
|
|
10
|
-
const coreWarning =
|
|
11
|
-
? await evaluateWorktreeGraphqlQuotaWarning(key, bands,
|
|
15
|
+
const coreWarning = coreSample
|
|
16
|
+
? await evaluateWorktreeGraphqlQuotaWarning(key, bands, coreSample, persist)
|
|
12
17
|
: undefined;
|
|
13
18
|
return composeQuotaWarning({
|
|
14
19
|
graphqlWarning,
|
|
15
20
|
coreWarning,
|
|
16
|
-
graphql
|
|
21
|
+
graphql,
|
|
17
22
|
core,
|
|
18
23
|
bands,
|
|
19
24
|
});
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { getRepoInfo, getCurrentPrNumber } from "../github/client.mjs";
|
|
2
2
|
import { applyResolveOptions } from "../comments/resolve.mjs";
|
|
3
3
|
import { fetchReplyThreadTranscripts } from "../github/reply-thread-transcripts.mjs";
|
|
4
|
+
import { readApplyReviewPreflight, } from "../github/apply-review-preflight.mjs";
|
|
4
5
|
import { markReplySeen } from "../state/seen-comments.mjs";
|
|
5
6
|
import { threadTranscriptBodies } from "../threads/transcript.mjs";
|
|
6
7
|
import { addPrShepherdMarker } from "../comments/marker.mjs";
|
|
8
|
+
import { adoptedReplyThreads } from "../comments/uncertain-replies.mjs";
|
|
7
9
|
import { EXIT, ShepherdError } from "../exit-codes.mjs";
|
|
8
10
|
/** @deprecated Hidden implementation for `resolve`; use `apply review`. */
|
|
9
11
|
export async function runResolveMutate(opts) {
|
|
@@ -15,9 +17,20 @@ export async function runResolveMutate(opts) {
|
|
|
15
17
|
// Fetch only to retain the pre-reply transcript for successful-reply seen
|
|
16
18
|
// markers. It never determines which user-supplied IDs are sent to GitHub.
|
|
17
19
|
let transcriptById;
|
|
20
|
+
let preflight = null;
|
|
18
21
|
if (opts.replyThreadIds?.length) {
|
|
19
22
|
try {
|
|
20
|
-
|
|
23
|
+
preflight = await readApplyReviewPreflight(prNumber, repo, opts.replyThreadIds);
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
// The standalone reads below and in applyResolveOptions cover everything it would have.
|
|
27
|
+
}
|
|
28
|
+
transcriptById = new Map(preflight?.transcripts);
|
|
29
|
+
const missing = [...new Set(opts.replyThreadIds)].filter((id) => !transcriptById.has(id));
|
|
30
|
+
try {
|
|
31
|
+
if (missing.length)
|
|
32
|
+
for (const [id, body] of await fetchReplyThreadTranscripts(prNumber, repo, missing))
|
|
33
|
+
transcriptById.set(id, body);
|
|
21
34
|
}
|
|
22
35
|
catch {
|
|
23
36
|
// Seen-marker bookkeeping is best-effort. A failed read must not block
|
|
@@ -27,6 +40,7 @@ export async function runResolveMutate(opts) {
|
|
|
27
40
|
// Iterate capability-checks and routes its generated commands. Direct apply
|
|
28
41
|
// requests are user-directed: forward every supplied ID unchanged and let
|
|
29
42
|
// GitHub report whether each requested mutation is permitted or applicable.
|
|
43
|
+
// Only generated durable-state commands carry `--adopt-existing-replies`.
|
|
30
44
|
const result = await applyResolveOptions(prNumber, repo, {
|
|
31
45
|
resolveThreadIds: opts.resolveThreadIds,
|
|
32
46
|
replyThreadIds: opts.replyThreadIds,
|
|
@@ -34,14 +48,28 @@ export async function runResolveMutate(opts) {
|
|
|
34
48
|
dismissReviewIds: opts.dismissReviewIds,
|
|
35
49
|
dismissMessage: opts.dismissMessage,
|
|
36
50
|
requireSha: opts.requireSha,
|
|
37
|
-
|
|
38
|
-
|
|
51
|
+
...(opts.adoptExistingReplies && { adoptExistingReplies: true }),
|
|
52
|
+
}, ...(preflight ? [preflight] : []));
|
|
53
|
+
const adopted = new Set(adoptedReplyThreads(result));
|
|
54
|
+
let adoptedTranscripts;
|
|
55
|
+
if (adopted.size) {
|
|
56
|
+
try {
|
|
57
|
+
adoptedTranscripts = await fetchReplyThreadTranscripts(prNumber, repo, [...adopted]);
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
/* Never synthesize a transcript for an already-delivered reply. */
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
if (opts.dismissMessage && (transcriptById || adoptedTranscripts)) {
|
|
39
64
|
const markedMessage = addPrShepherdMarker(opts.dismissMessage);
|
|
40
65
|
await Promise.all(result.repliedThreads.map((id) => {
|
|
41
|
-
const previousBody = transcriptById
|
|
66
|
+
const previousBody = transcriptById?.get(id);
|
|
67
|
+
const currentBody = adopted.has(id) ? adoptedTranscripts?.get(id) : undefined;
|
|
68
|
+
if (adopted.has(id) && currentBody === undefined)
|
|
69
|
+
return Promise.resolve();
|
|
42
70
|
if (previousBody === undefined)
|
|
43
71
|
return Promise.resolve();
|
|
44
|
-
return markReplySeen({ owner: repo.owner, repo: repo.name, pr: prNumber }, id, previousBody, threadTranscriptBodies([previousBody, markedMessage]), markedMessage);
|
|
72
|
+
return markReplySeen({ owner: repo.owner, repo: repo.name, pr: prNumber }, id, previousBody, currentBody ?? threadTranscriptBodies([previousBody, markedMessage]), markedMessage);
|
|
45
73
|
}));
|
|
46
74
|
}
|
|
47
75
|
return result;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { RepoInfo } from "../github/client.mts";
|
|
2
|
+
import { type RestMergeStackGuard } from "../github/rest-merge-stack-guard.mts";
|
|
3
|
+
/** Validate the exact current native prefix before requesting a stack merge. */
|
|
4
|
+
export declare function validateRestStackMergeReadiness(pr: number, repo: RepoInfo, sha: string, expectedStack?: RestMergeStackGuard): Promise<void>;
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { EXIT, ShepherdError } from "../exit-codes.mjs";
|
|
2
|
+
import { readRestStackMembership, readRestStackTopology } from "../github/rest-stack-read.mjs";
|
|
3
|
+
import { fetchRawSummaryPr } from "../github/poll-summary.mjs";
|
|
4
|
+
import { summarizePollSummaryPr } from "../github/poll-summary-projector.mjs";
|
|
5
|
+
import { stackAncestryGaps } from "../github/stack-read.mjs";
|
|
6
|
+
import { mapPool } from "../util/pool.mjs";
|
|
7
|
+
import { restMergeStackGuardKey, } from "../github/rest-merge-stack-guard.mjs";
|
|
8
|
+
/** Validate the exact current native prefix before requesting a stack merge. */
|
|
9
|
+
export async function validateRestStackMergeReadiness(pr, repo, sha, expectedStack) {
|
|
10
|
+
const initialMembership = await readRestStackMembership(pr, repo);
|
|
11
|
+
if (!initialMembership) {
|
|
12
|
+
if (expectedStack)
|
|
13
|
+
fail("Expected native stack is no longer present");
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
if (expectedStack &&
|
|
17
|
+
(initialMembership.number !== expectedStack.number ||
|
|
18
|
+
initialMembership.base.ref !== expectedStack.baseRefName))
|
|
19
|
+
fail("Expected native stack identity or trunk changed");
|
|
20
|
+
const topology = await readRestStackTopology(pr, repo);
|
|
21
|
+
const index = topology.ordered.findIndex((member) => member.number === pr);
|
|
22
|
+
if (index < 0 || topology.ordered[index]?.headRefOid !== sha)
|
|
23
|
+
fail("Stack head changed before merge");
|
|
24
|
+
const prefix = topology.ordered.slice(0, index + 1);
|
|
25
|
+
if (expectedStack &&
|
|
26
|
+
restMergeStackGuardKey(expectedStack) !==
|
|
27
|
+
restMergeStackGuardKey({
|
|
28
|
+
number: topology.stackNumber,
|
|
29
|
+
baseRefName: initialMembership.base.ref,
|
|
30
|
+
prefix: prefix.map(guardMember),
|
|
31
|
+
}))
|
|
32
|
+
fail("Expected native stack prefix or parent boundaries changed");
|
|
33
|
+
if (prefix.some((member) => !["OPEN", "MERGED"].includes(member.state)))
|
|
34
|
+
fail("Stack prefix has a closed or unverified dependency");
|
|
35
|
+
const open = prefix.filter((member) => member.state === "OPEN");
|
|
36
|
+
const membership = await readRestStackMembership(pr, repo);
|
|
37
|
+
if (membership &&
|
|
38
|
+
(membership.number !== initialMembership.number ||
|
|
39
|
+
membership.base.ref !== initialMembership.base.ref))
|
|
40
|
+
fail("Native stack identity or trunk changed while validating merge readiness");
|
|
41
|
+
if (!membership || open[0]?.baseRefName !== membership.base.ref)
|
|
42
|
+
fail("Bottom open stack layer does not target the trunk");
|
|
43
|
+
if (stackAncestryGaps(prefix).length > 0)
|
|
44
|
+
fail("Stack prefix has stale parent boundaries");
|
|
45
|
+
await mapPool(open, 4, async (member) => {
|
|
46
|
+
const raw = await fetchRawSummaryPr(member.number, repo);
|
|
47
|
+
const summary = await summarizePollSummaryPr(raw, repo, { stackPrNumber: pr });
|
|
48
|
+
if (raw.headRefOid !== member.headRefOid ||
|
|
49
|
+
raw.baseRefOid !== member.baseRefOid ||
|
|
50
|
+
summary.readyReceipt !== true)
|
|
51
|
+
fail(`PR #${member.number} has no current Shepherd READY receipt`);
|
|
52
|
+
});
|
|
53
|
+
const latest = await readRestStackTopology(pr, repo);
|
|
54
|
+
const finalMembership = await readRestStackMembership(pr, repo);
|
|
55
|
+
if (!finalMembership ||
|
|
56
|
+
finalMembership.number !== initialMembership.number ||
|
|
57
|
+
finalMembership.base.ref !== initialMembership.base.ref ||
|
|
58
|
+
JSON.stringify(finalMembership.pull_requests.map((member) => member.number)) !==
|
|
59
|
+
JSON.stringify(latest.ordered.map((member) => member.number)) ||
|
|
60
|
+
latest.stackNumber !== topology.stackNumber ||
|
|
61
|
+
JSON.stringify(latest.ordered) !== JSON.stringify(topology.ordered))
|
|
62
|
+
fail("Native stack changed while validating merge readiness");
|
|
63
|
+
}
|
|
64
|
+
function guardMember(member) {
|
|
65
|
+
return {
|
|
66
|
+
pr: member.number,
|
|
67
|
+
headRefName: member.headRefName,
|
|
68
|
+
headRefOid: member.headRefOid,
|
|
69
|
+
baseRefName: member.baseRefName,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
function fail(message) {
|
|
73
|
+
throw new ShepherdError(`${message}; rerun the --stack --merge selector before applying this request`, EXIT.UNAVAILABLE);
|
|
74
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { autoMinimizeComments, autoResolveThreads } from "../comments/resolve.mjs";
|
|
2
2
|
import { runJournal } from "./journal/index.mjs";
|
|
3
|
+
import { canGenerateGithubMutation } from "../github/mutation-policy.mjs";
|
|
3
4
|
import { decorateAutoResolveError, formatRuleAutoResolveJournalItem, minimizedItem, reasonClause, reasonsForError, resolvedThread, ruleAutoResolveBody, uniqueReasons, } from "./rule-auto-resolve-format.mjs";
|
|
4
5
|
const EMPTY = {
|
|
5
6
|
threadIds: [],
|
|
@@ -28,9 +29,14 @@ export async function applySuppressedRuleAutoResolve(input) {
|
|
|
28
29
|
reviewSummaryIds: input.partition.ruleAutoResolveReviewSummaryIds,
|
|
29
30
|
};
|
|
30
31
|
}
|
|
31
|
-
const
|
|
32
|
-
const
|
|
33
|
-
const
|
|
32
|
+
const canMinimize = (items, id) => canGenerateGithubMutation(items.find((item) => item.id === id)?.viewerCanMinimize, "minimize");
|
|
33
|
+
const threadFor = (id) => input.batch.reviewThreads.find((thread) => thread.id === id);
|
|
34
|
+
const commentIds = input.partition.ruleAutoResolveCommentIds.filter((id) => input.partition.suppressedCommentIds.has(id) && canMinimize(input.batch.comments, id));
|
|
35
|
+
const reviewSummaryIds = input.partition.ruleAutoResolveReviewSummaryIds.filter((id) => input.partition.suppressedReviewSummaryIds.has(id) &&
|
|
36
|
+
canMinimize(input.batch.reviewSummaries, id));
|
|
37
|
+
const threadIds = input.partition.ruleAutoResolveThreadIds.filter((id) => input.partition.suppressedThreadIds.has(id) &&
|
|
38
|
+
threadFor(id)?.isResolved === false &&
|
|
39
|
+
canGenerateGithubMutation(threadFor(id)?.viewerCanResolve, "resolve"));
|
|
34
40
|
const minimizeIds = [...commentIds, ...reviewSummaryIds];
|
|
35
41
|
const [minimized, resolved] = await Promise.all([
|
|
36
42
|
minimizeIds.length > 0
|
|
@@ -4,11 +4,12 @@ export declare const SHEPHERD_JOURNAL_DETAILS_OPEN = "<details>";
|
|
|
4
4
|
export declare const SHEPHERD_JOURNAL_DETAILS_SUMMARY = "<summary>Shepherd Journal</summary>";
|
|
5
5
|
export declare const SHEPHERD_JOURNAL_DETAILS_CLOSE = "</details>";
|
|
6
6
|
export declare const SHEPHERD_JOURNAL_APPEND_HINT = "If Shepherd Journal details already exist, append entries inside them instead of creating another container.";
|
|
7
|
-
export declare const SHEPHERD_JOURNAL_FIRST_LOOK_GUIDANCE
|
|
7
|
+
export declare const SHEPHERD_JOURNAL_FIRST_LOOK_GUIDANCE = "Read each body under `## Review summaries (first look)` and journal any warranted note before review mutations.";
|
|
8
|
+
/** The concrete `apply journal` command. The placeholder is single-quoted so a substituted decision stays literal in the shell. */
|
|
9
|
+
export declare function buildShepherdJournalCommand(prReference: string | number): string;
|
|
8
10
|
/**
|
|
9
11
|
* Build the Shepherd Journal instruction step. The reference-citation convention (link
|
|
10
|
-
* threads/comments
|
|
11
|
-
*
|
|
12
|
-
* of being re-emitted every tick (see AGENTS.md "Keep skills and loop prompts minimal").
|
|
12
|
+
* threads/comments by heading URL, cite reviews by ID) is a short clause, so it stays inline:
|
|
13
|
+
* a separate playbook would cost the agent an extra read turn that outweighs the clause.
|
|
13
14
|
*/
|
|
14
15
|
export declare function buildShepherdJournalInstruction(prReference: string | number): string;
|
|
@@ -1,20 +1,21 @@
|
|
|
1
1
|
import { buildPrShepherdCommand } from "../cli/runner.mjs";
|
|
2
|
-
import { playbookPointer } from "./playbook-pointer.mjs";
|
|
3
2
|
export const SHEPHERD_JOURNAL_SECTION = "Shepherd Journal";
|
|
4
3
|
export const SHEPHERD_JOURNAL_SECTION_PATTERN = /^##\s+Shepherd\s+Journal$/;
|
|
5
4
|
export const SHEPHERD_JOURNAL_DETAILS_OPEN = "<details>";
|
|
6
5
|
export const SHEPHERD_JOURNAL_DETAILS_SUMMARY = "<summary>Shepherd Journal</summary>";
|
|
7
6
|
export const SHEPHERD_JOURNAL_DETAILS_CLOSE = "</details>";
|
|
8
7
|
export const SHEPHERD_JOURNAL_APPEND_HINT = "If Shepherd Journal details already exist, append entries inside them instead of creating another container.";
|
|
9
|
-
export const SHEPHERD_JOURNAL_FIRST_LOOK_GUIDANCE = `Read each body under \`## Review summaries (first look)\` and journal any warranted note before review mutations
|
|
8
|
+
export const SHEPHERD_JOURNAL_FIRST_LOOK_GUIDANCE = `Read each body under \`## Review summaries (first look)\` and journal any warranted note before review mutations.`;
|
|
9
|
+
/** The concrete `apply journal` command. The placeholder is single-quoted so a substituted decision stays literal in the shell. */
|
|
10
|
+
export function buildShepherdJournalCommand(prReference) {
|
|
11
|
+
return `${buildPrShepherdCommand(["apply", "journal", String(prReference)]).text} '- <decision>'`;
|
|
12
|
+
}
|
|
10
13
|
/**
|
|
11
14
|
* Build the Shepherd Journal instruction step. The reference-citation convention (link
|
|
12
|
-
* threads/comments
|
|
13
|
-
*
|
|
14
|
-
* of being re-emitted every tick (see AGENTS.md "Keep skills and loop prompts minimal").
|
|
15
|
+
* threads/comments by heading URL, cite reviews by ID) is a short clause, so it stays inline:
|
|
16
|
+
* a separate playbook would cost the agent an extra read turn that outweighs the clause.
|
|
15
17
|
*/
|
|
16
18
|
export function buildShepherdJournalInstruction(prReference) {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
return `For any substantial decision or rejection, append \`- <decision>\` to Shepherd Journal with \`${command}\`. ${playbookPointer("Shepherd Journal")}`;
|
|
19
|
+
const command = buildShepherdJournalCommand(prReference);
|
|
20
|
+
return `Journal key decisions or rejections with URLs or IDs: \`${command}\``;
|
|
20
21
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
export { findHumanHandoffs, appendHumanHandoffInstructions } from "./stack-handoffs.mts";
|
|
1
2
|
import type { PollSummaryItem, PollSummaryResult, StackNextAction } from "../types.mts";
|
|
2
3
|
export interface StackPlan {
|
|
3
4
|
action: StackNextAction;
|
|
@@ -17,14 +18,5 @@ export declare function retargetWaitPlan(first: PollSummaryItem): StackPlan;
|
|
|
17
18
|
export declare function idleWaitPlan(idle: PollSummaryItem[]): StackPlan;
|
|
18
19
|
export declare function describeIdleLayers(idle: PollSummaryItem[]): string;
|
|
19
20
|
export declare function appendAutonomousInstructions(instructions: string[], candidates: PollSummaryItem[]): void;
|
|
20
|
-
/** Layers only a human can resolve: a closed dependency, an unverified state, or an escalation. */
|
|
21
|
-
export interface HumanHandoffs {
|
|
22
|
-
closedDependency?: PollSummaryItem;
|
|
23
|
-
unverified?: PollSummaryItem;
|
|
24
|
-
escalated: PollSummaryItem[];
|
|
25
|
-
}
|
|
26
|
-
export declare function findHumanHandoffs(result: PollSummaryResult): HumanHandoffs | undefined;
|
|
27
|
-
/** Name every human handoff; `stop` when no autonomous work precedes it. */
|
|
28
|
-
export declare function appendHumanHandoffInstructions(instructions: string[], { closedDependency, unverified, escalated }: HumanHandoffs, stop: boolean): void;
|
|
29
21
|
export declare function isStackLayerReady(item: PollSummaryItem): boolean;
|
|
30
22
|
export declare function stackPosition(item: PollSummaryItem): number;
|
|
@@ -1,7 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { findHumanHandoffs, appendHumanHandoffInstructions } from "./stack-handoffs.mjs";
|
|
2
|
+
export { findHumanHandoffs, appendHumanHandoffInstructions } from "./stack-handoffs.mjs";
|
|
2
3
|
import { stackMergeFlag } from "./stack-merge-flag.mjs";
|
|
3
4
|
import { stackLayerBlockReason } from "./stack-layer-readiness.mjs";
|
|
4
5
|
import { appendMarkReadyInstructions, splitStackWork } from "./stack-work.mjs";
|
|
6
|
+
import { getGithubTransport } from "../github/transport.mjs";
|
|
7
|
+
import { buildMergeCommandPlan, renderMergeCommand } from "./iterate/merge.mjs";
|
|
5
8
|
function readyPrefixTop(result) {
|
|
6
9
|
const layers = [...result.prs].sort((left, right) => stackPosition(left) - stackPosition(right));
|
|
7
10
|
if (layers.some((item) => item.state === "OPEN" && item.isInMergeQueue))
|
|
@@ -40,17 +43,51 @@ export function planPrefixDrain(result, mergeRequested) {
|
|
|
40
43
|
item.action !== "escalate" &&
|
|
41
44
|
(!isStackLayerReady(item) || staleChildren.has(item.pr))), staleChildren);
|
|
42
45
|
const span = open[0]?.pr === top.pr ? "that layer alone" : `PR #${top.pr} and every unmerged layer below it`;
|
|
43
|
-
const
|
|
44
|
-
if ("
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
46
|
+
const instructions = [];
|
|
47
|
+
if (getGithubTransport() === "rest" || top.transport === "rest") {
|
|
48
|
+
// Upper layers target their parent; the prefix merges into the stack trunk.
|
|
49
|
+
const trunk = result.prs.find((item) => item.baseRefName === top.stack.baseRefName);
|
|
50
|
+
const plan = buildMergeCommandPlan({
|
|
51
|
+
transport: "rest",
|
|
52
|
+
pr: top.pr,
|
|
53
|
+
repo: result.repo,
|
|
54
|
+
nodeId: "",
|
|
55
|
+
headSha: top.headRefOid,
|
|
56
|
+
queue: trunk?.requiresMergeQueue === true,
|
|
57
|
+
queueKnown: trunk?.requiresMergeQueue !== undefined,
|
|
58
|
+
allowedMergeMethods: result.allowedMergeMethods,
|
|
59
|
+
expectedStack: {
|
|
60
|
+
number: top.stack.number,
|
|
61
|
+
baseRefName: top.stack.baseRefName,
|
|
62
|
+
prefix: [...result.prs]
|
|
63
|
+
.sort((left, right) => stackPosition(left) - stackPosition(right))
|
|
64
|
+
.filter((item) => stackPosition(item) <= stackPosition(top))
|
|
65
|
+
.map((item) => ({
|
|
66
|
+
pr: item.pr,
|
|
67
|
+
headRefName: item.headRefName,
|
|
68
|
+
headRefOid: item.headRefOid,
|
|
69
|
+
baseRefName: item.baseRefName,
|
|
70
|
+
})),
|
|
71
|
+
},
|
|
72
|
+
});
|
|
73
|
+
if ("unavailable" in plan)
|
|
74
|
+
return {
|
|
75
|
+
action: "escalate",
|
|
76
|
+
stackMergeable: false,
|
|
77
|
+
instructions: [`1. ${plan.unavailable}`],
|
|
78
|
+
};
|
|
79
|
+
instructions[0] = `1. PR #${top.pr} is the highest ready layer of native stack #${top.stack.number}. Run \`${renderMergeCommand(plan.command)}\` to request merging ${span}. If status is \`pending\`, rerun that command at the configured cadence to resume its UUID. \`enqueued\` is not merged. Shepherd revalidates every open lower layer's READY receipt before submission.`;
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
const method = stackMergeFlag(result.allowedMergeMethods);
|
|
83
|
+
if ("unavailable" in method)
|
|
84
|
+
return {
|
|
85
|
+
action: "escalate",
|
|
86
|
+
stackMergeable: false,
|
|
87
|
+
instructions: [`1. ${method.unavailable}`],
|
|
88
|
+
};
|
|
89
|
+
instructions[0] = `1. PR #${top.pr} is the highest open layer of stack #${top.stack.number} in \`${result.repo}\` whose open lower layers are all ready. Run \`GH_REPO=${result.repo} gh stack merge ${top.pr} --yes ${method.flag}\` to merge ${span}. If \`gh stack\` is an unknown command, run \`gh extension install github/gh-stack\`, then rerun that merge command. Do not rebase, push, or run \`gh stack push\`.`;
|
|
50
90
|
}
|
|
51
|
-
const instructions = [
|
|
52
|
-
`1. PR #${top.pr} is the highest open layer of stack #${top.stack.number} in \`${result.repo}\` whose open lower layers are all ready. Run \`GH_REPO=${result.repo} gh stack merge ${top.pr} --yes ${method.flag}\` to merge ${span}. ${playbookPointer("Stack merge")}`,
|
|
53
|
-
];
|
|
54
91
|
appendAutonomousInstructions(instructions, above.sessions);
|
|
55
92
|
appendMarkReadyInstructions(instructions, above.markReady);
|
|
56
93
|
const handoffs = findHumanHandoffs(result);
|
|
@@ -101,7 +138,7 @@ function sessionInstruction(item) {
|
|
|
101
138
|
const queueNote = item.queueRemoval
|
|
102
139
|
? " That session fixes failing queue CI, or escalates when the removal has no concrete fix."
|
|
103
140
|
: "";
|
|
104
|
-
return `${removal} Run \`${item.pollCommand}
|
|
141
|
+
return `${removal} Run \`${item.pollCommand}\`.${queueNote}`;
|
|
105
142
|
}
|
|
106
143
|
export function describeIdleLayers(idle) {
|
|
107
144
|
return idle.map((item) => `PR #${item.pr} (${item.reasons.join(", ")})`).join("; ");
|
|
@@ -109,35 +146,11 @@ export function describeIdleLayers(idle) {
|
|
|
109
146
|
export function appendAutonomousInstructions(instructions, candidates) {
|
|
110
147
|
if (candidates.length === 0)
|
|
111
148
|
return;
|
|
112
|
-
instructions.push(`${instructions.length + 1}. Start or delegate one-PR sessions only for
|
|
149
|
+
instructions.push(`${instructions.length + 1}. Start or delegate concurrent one-PR sessions only for \`owned\` rows. Leave other layers untouched.`);
|
|
113
150
|
for (const item of candidates) {
|
|
114
151
|
instructions.push(`${instructions.length + 1}.${sessionInstruction(item)}`);
|
|
115
152
|
}
|
|
116
153
|
}
|
|
117
|
-
export function findHumanHandoffs(result) {
|
|
118
|
-
const lastOpen = result.prs.filter((item) => item.state === "OPEN").at(-1);
|
|
119
|
-
const closedDependency = result.prs.find((item) => item.state === "CLOSED" && lastOpen && stackPosition(item) < stackPosition(lastOpen));
|
|
120
|
-
const unverified = result.prs.find((item) => item.state !== "OPEN" && item.state !== "MERGED");
|
|
121
|
-
const escalated = result.prs.filter((item) => item.action === "escalate");
|
|
122
|
-
return closedDependency || unverified || escalated.length > 0
|
|
123
|
-
? { closedDependency, unverified, escalated }
|
|
124
|
-
: undefined;
|
|
125
|
-
}
|
|
126
|
-
/** Name every human handoff; `stop` when no autonomous work precedes it. */
|
|
127
|
-
export function appendHumanHandoffInstructions(instructions, { closedDependency, unverified, escalated }, stop) {
|
|
128
|
-
const ask = stop ? "Stop and ask" : "After autonomous shepherding, ask";
|
|
129
|
-
if (closedDependency) {
|
|
130
|
-
instructions.push(`${instructions.length + 1}. PR #${closedDependency.pr} was closed without merging below an open layer. ${ask} the stack owner whether to restore that dependency or rebuild the upper branches.`);
|
|
131
|
-
}
|
|
132
|
-
if (unverified && unverified.pr !== closedDependency?.pr) {
|
|
133
|
-
instructions.push(`${instructions.length + 1}. PR #${unverified.pr} has state \`${unverified.state}\` rather than open or merged. ${ask} the stack owner to reconcile this layer before declaring the stack complete.`);
|
|
134
|
-
}
|
|
135
|
-
for (const item of escalated) {
|
|
136
|
-
if (item.pr === closedDependency?.pr || item.pr === unverified?.pr)
|
|
137
|
-
continue;
|
|
138
|
-
instructions.push(`${instructions.length + 1}. PR #${item.pr} requires human action (${item.reasons.join(", ")}). ${stop ? "Stop for that decision." : "Keep shepherding other PRs before the handoff."}`);
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
154
|
export function isStackLayerReady(item) {
|
|
142
155
|
return item.stack !== undefined && stackLayerBlockReason(item) === undefined;
|
|
143
156
|
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { PollSummaryItem, PollSummaryResult } from "../types.mts";
|
|
2
|
+
/** Layers only a human can resolve: a closed dependency, an unverified state, or an escalation. */
|
|
3
|
+
export interface HumanHandoffs {
|
|
4
|
+
closedDependency?: PollSummaryItem;
|
|
5
|
+
unverified?: PollSummaryItem;
|
|
6
|
+
escalated: PollSummaryItem[];
|
|
7
|
+
}
|
|
8
|
+
export declare function findHumanHandoffs(result: PollSummaryResult): HumanHandoffs | undefined;
|
|
9
|
+
/** Name every human handoff; `stop` when no autonomous work precedes it. */
|
|
10
|
+
export declare function appendHumanHandoffInstructions(instructions: string[], { closedDependency, unverified, escalated }: HumanHandoffs, stop: boolean): void;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { stackPosition } from "./stack-drain.mjs";
|
|
2
|
+
export function findHumanHandoffs(result) {
|
|
3
|
+
const lastOpen = result.prs.filter((item) => item.state === "OPEN").at(-1);
|
|
4
|
+
const closedDependency = result.prs.find((item) => item.state === "CLOSED" && lastOpen && stackPosition(item) < stackPosition(lastOpen));
|
|
5
|
+
const unverified = result.prs.find((item) => item.state !== "OPEN" && item.state !== "MERGED");
|
|
6
|
+
const escalated = result.prs.filter((item) => item.action === "escalate");
|
|
7
|
+
return closedDependency || unverified || escalated.length > 0
|
|
8
|
+
? { closedDependency, unverified, escalated }
|
|
9
|
+
: undefined;
|
|
10
|
+
}
|
|
11
|
+
/** Name every human handoff; `stop` when no autonomous work precedes it. */
|
|
12
|
+
export function appendHumanHandoffInstructions(instructions, { closedDependency, unverified, escalated }, stop) {
|
|
13
|
+
const ask = stop ? "Stop and ask" : "After autonomous shepherding, ask";
|
|
14
|
+
if (closedDependency) {
|
|
15
|
+
instructions.push(`${instructions.length + 1}. PR #${closedDependency.pr} was closed without merging below an open layer. ${ask} the stack owner whether to restore that dependency or rebuild the upper branches.`);
|
|
16
|
+
}
|
|
17
|
+
if (unverified && unverified.pr !== closedDependency?.pr) {
|
|
18
|
+
instructions.push(`${instructions.length + 1}. PR #${unverified.pr} has state \`${unverified.state}\` rather than open or merged. ${ask} the stack owner to reconcile this layer before declaring the stack complete.`);
|
|
19
|
+
}
|
|
20
|
+
for (const item of escalated) {
|
|
21
|
+
if (item.pr === closedDependency?.pr || item.pr === unverified?.pr)
|
|
22
|
+
continue;
|
|
23
|
+
instructions.push(`${instructions.length + 1}. PR #${item.pr} requires human action (${item.reasons.join(", ")}). ${stop ? "Stop for that decision." : "Keep shepherding other PRs before the handoff."}`);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -12,3 +12,8 @@ export declare function applyStackStallGuard(planned: {
|
|
|
12
12
|
owner: string;
|
|
13
13
|
name: string;
|
|
14
14
|
}, stallTimeoutSeconds: number): Promise<PollSummaryResult>;
|
|
15
|
+
/**
|
|
16
|
+
* Unix seconds when an unchanged idle stack plan trips `stall-timeout`, or undefined when no
|
|
17
|
+
* stack timer is running. Event mode schedules its next tick no later than this.
|
|
18
|
+
*/
|
|
19
|
+
export declare function readStackStallDeadline(result: PollSummaryResult, stallTimeoutSeconds: number): Promise<number | undefined>;
|
|
@@ -42,6 +42,17 @@ export async function applyStackStallGuard(planned, repo, stallTimeoutSeconds) {
|
|
|
42
42
|
],
|
|
43
43
|
};
|
|
44
44
|
}
|
|
45
|
+
/**
|
|
46
|
+
* Unix seconds when an unchanged idle stack plan trips `stall-timeout`, or undefined when no
|
|
47
|
+
* stack timer is running. Event mode schedules its next tick no later than this.
|
|
48
|
+
*/
|
|
49
|
+
export async function readStackStallDeadline(result, stallTimeoutSeconds) {
|
|
50
|
+
const [owner, repo] = result.repo.split("/");
|
|
51
|
+
if (result.selection.kind !== "stack" || stallTimeoutSeconds <= 0 || !owner || !repo)
|
|
52
|
+
return undefined;
|
|
53
|
+
const read = await readStackStallState({ owner, repo, stack: result.selection.stackNumber });
|
|
54
|
+
return read.ok && read.state ? read.state.firstSeenAt + stallTimeoutSeconds : undefined;
|
|
55
|
+
}
|
|
45
56
|
function stackStateUnavailable(result, reason) {
|
|
46
57
|
return {
|
|
47
58
|
...result,
|
|
@@ -29,4 +29,9 @@ export declare function splitStackWork(candidates: PollSummaryItem[], staleChild
|
|
|
29
29
|
* first because only the one-PR session reads the full review context.
|
|
30
30
|
*/
|
|
31
31
|
export declare function appendMarkReadyInstructions(instructions: string[], layers: ProbedLayer[]): void;
|
|
32
|
+
/**
|
|
33
|
+
* The closing step after routed sessions: rerun the selector, or stop when nothing is owned.
|
|
34
|
+
* Returns the plan action: a stop is a handoff, so no rerun, quota cadence, or wake-up follows it.
|
|
35
|
+
*/
|
|
36
|
+
export declare function appendStackRerunInstruction(instructions: string[], layers: PollSummaryItem[], rerun: string): "shepherd" | "escalate";
|
|
32
37
|
export {};
|