pr-shepherd 0.56.6 → 0.57.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/plugin.json +1 -1
- package/README.md +150 -280
- package/bin/api.d.mts +25 -3
- package/bin/api.mjs +51 -13
- package/bin/checks/classify.d.mts +1 -0
- package/bin/checks/classify.mjs +1 -1
- package/bin/checks/conclusions.d.mts +5 -1
- package/bin/checks/conclusions.mjs +8 -2
- package/bin/checks/superseded.d.mts +8 -2
- package/bin/checks/superseded.mjs +24 -7
- package/bin/classify/loader.d.mts +2 -0
- package/bin/classify/loader.mjs +15 -0
- package/bin/classify/standard/author.d.mts +3 -0
- package/bin/classify/standard/author.mjs +10 -0
- package/bin/classify/standard/codecov-report.d.mts +4 -0
- package/bin/classify/standard/codecov-report.mjs +10 -0
- package/bin/classify/standard/coderabbit-notices.d.mts +8 -0
- package/bin/classify/standard/coderabbit-notices.mjs +38 -0
- package/bin/classify/standard/codex-notices.d.mts +8 -0
- package/bin/classify/standard/codex-notices.mjs +34 -0
- package/bin/classify/standard/dependabot-notices.d.mts +4 -0
- package/bin/classify/standard/dependabot-notices.mjs +15 -0
- package/bin/classify/standard/gemini-notices.d.mts +4 -0
- package/bin/classify/standard/gemini-notices.mjs +13 -0
- package/bin/classify/standard/index.d.mts +7 -0
- package/bin/classify/standard/index.mjs +21 -0
- package/bin/classify/standard/kilo-no-issues.d.mts +4 -0
- package/bin/classify/standard/kilo-no-issues.mjs +17 -0
- package/bin/classify/standard/sourcery-notices.d.mts +8 -0
- package/bin/classify/standard/sourcery-notices.mjs +20 -0
- package/bin/cli/api-usage-formatter.mjs +6 -1
- package/bin/cli/apply-merge-handler.d.mts +3 -0
- package/bin/cli/apply-merge-handler.mjs +73 -0
- package/bin/cli/arg-flags.d.mts +2 -0
- package/bin/cli/arg-flags.mjs +47 -0
- package/bin/cli/args.mjs +10 -41
- package/bin/cli/clean-handler.d.mts +1 -0
- package/bin/cli/clean-handler.mjs +71 -0
- package/bin/cli/default-poll.mjs +3 -0
- package/bin/cli/event-state-scope.d.mts +19 -0
- package/bin/cli/event-state-scope.mjs +60 -0
- package/bin/cli/fix-formatter.mjs +5 -11
- package/bin/cli/handlers.d.mts +0 -1
- package/bin/cli/handlers.mjs +8 -64
- package/bin/cli/help-command-pages.d.mts +62 -18
- package/bin/cli/help-command-pages.mjs +59 -15
- package/bin/cli/help-iterate-poll-pages.d.mts +2 -2
- package/bin/cli/help-iterate-poll-pages.mjs +6 -0
- package/bin/cli/help-log-file-page.d.mts +1 -1
- package/bin/cli/help-log-file-page.mjs +4 -1
- package/bin/cli/help-top-page.d.mts +1 -1
- package/bin/cli/help-top-page.mjs +5 -0
- package/bin/cli/help.d.mts +63 -19
- package/bin/cli/help.mjs +2 -0
- package/bin/cli/iterate-branch-segment.d.mts +2 -0
- package/bin/cli/iterate-branch-segment.mjs +12 -7
- package/bin/cli/iterate-flags.d.mts +7 -1
- package/bin/cli/iterate-flags.mjs +38 -0
- package/bin/cli/iterate-formatter.d.mts +6 -6
- package/bin/cli/iterate-formatter.mjs +56 -22
- package/bin/cli/iterate-instructions.mjs +45 -15
- package/bin/cli/iterate-lean.mjs +39 -14
- package/bin/cli/iterate-merge-formatter.d.mts +6 -0
- package/bin/cli/iterate-merge-formatter.mjs +24 -14
- package/bin/cli/iterate-verbose.mjs +3 -6
- package/bin/cli/list-formatters.mjs +3 -1
- package/bin/cli/mutate-formatter.mjs +10 -5
- package/bin/cli/next-check-format.d.mts +7 -0
- package/bin/cli/next-check-format.mjs +10 -0
- package/bin/cli/playbook-handler.d.mts +5 -0
- package/bin/cli/playbook-handler.mjs +40 -0
- package/bin/cli/poll-handler.mjs +7 -6
- package/bin/cli/poll-summary-formatter.mjs +11 -2
- package/bin/cli/poll-targets.mjs +2 -0
- package/bin/cli/resolve-validators.mjs +2 -2
- package/bin/cli/runner.mjs +6 -1
- package/bin/cli/stack-layer-view.d.mts +33 -0
- package/bin/cli/stack-layer-view.mjs +1 -0
- package/bin/cli/stack-overview.d.mts +10 -28
- package/bin/cli/stack-overview.mjs +39 -14
- package/bin/cli/transport-args.d.mts +5 -0
- package/bin/cli/transport-args.mjs +23 -0
- package/bin/cli/transport-formatter.d.mts +9 -0
- package/bin/cli/transport-formatter.mjs +13 -0
- package/bin/cli-parser.mjs +62 -7
- package/bin/commands/apply-merge-options.d.mts +4 -0
- package/bin/commands/apply-merge-options.mjs +34 -0
- package/bin/commands/apply-merge-output.d.mts +7 -0
- package/bin/commands/apply-merge-output.mjs +20 -0
- package/bin/commands/apply-merge-pull.d.mts +20 -0
- package/bin/commands/apply-merge-pull.mjs +15 -0
- package/bin/commands/apply-merge.d.mts +18 -0
- package/bin/commands/apply-merge.mjs +126 -0
- package/bin/commands/apply-queue-removal.mjs +7 -0
- package/bin/commands/check-annotations.mjs +28 -18
- package/bin/commands/check-execution-context.d.mts +5 -0
- package/bin/commands/check-execution-context.mjs +16 -1
- package/bin/commands/check-fingerprint.d.mts +26 -2
- package/bin/commands/check-fingerprint.mjs +64 -28
- package/bin/commands/check-terminal-report.mjs +11 -1
- package/bin/commands/check-unreported.d.mts +6 -2
- package/bin/commands/check-unreported.mjs +32 -12
- package/bin/commands/check-wait-detectors.d.mts +35 -0
- package/bin/commands/check-wait-detectors.mjs +107 -0
- package/bin/commands/check.d.mts +4 -2
- package/bin/commands/check.mjs +130 -40
- package/bin/commands/event-instructions.d.mts +11 -0
- package/bin/commands/event-instructions.mjs +27 -0
- package/bin/commands/event-mode.d.mts +14 -0
- package/bin/commands/event-mode.mjs +138 -0
- package/bin/commands/iterate/api-usage.mjs +4 -2
- package/bin/commands/iterate/base.mjs +4 -0
- package/bin/commands/iterate/check-blocker-gate.mjs +14 -2
- package/bin/commands/iterate/check-instructions.d.mts +9 -10
- package/bin/commands/iterate/check-instructions.mjs +23 -22
- package/bin/commands/iterate/classify.mjs +19 -5
- package/bin/commands/iterate/escalate.mjs +13 -3
- package/bin/commands/iterate/fix-code.mjs +26 -9
- package/bin/commands/iterate/fix-instruction-threads.d.mts +0 -8
- package/bin/commands/iterate/fix-instruction-threads.mjs +0 -16
- package/bin/commands/iterate/fix-loop-instruction.d.mts +9 -0
- package/bin/commands/iterate/fix-loop-instruction.mjs +35 -0
- package/bin/commands/iterate/helpers.mjs +15 -2
- package/bin/commands/iterate/index.mjs +57 -16
- package/bin/commands/iterate/mark-ready.mjs +50 -10
- package/bin/commands/iterate/merge-plan.d.mts +19 -0
- package/bin/commands/iterate/merge-plan.mjs +88 -0
- package/bin/commands/iterate/merge-state.mjs +3 -0
- package/bin/commands/iterate/merge.d.mts +4 -15
- package/bin/commands/iterate/merge.mjs +18 -51
- package/bin/commands/iterate/merged-base-pull-requests.d.mts +2 -6
- package/bin/commands/iterate/merged-base-pull-requests.mjs +15 -11
- package/bin/commands/iterate/native-stack-rebase.mjs +11 -0
- package/bin/commands/iterate/render.d.mts +8 -2
- package/bin/commands/iterate/render.mjs +28 -42
- package/bin/commands/iterate/stack-trunk-conflict.mjs +17 -1
- package/bin/commands/iterate/stale-ancestry.mjs +4 -1
- package/bin/commands/iterate/stall.d.mts +5 -1
- package/bin/commands/iterate/stall.mjs +19 -7
- package/bin/commands/iterate/thread-mutation-routing.d.mts +1 -0
- package/bin/commands/iterate/thread-mutation-routing.mjs +4 -2
- package/bin/commands/iterate/unreported-required.mjs +5 -2
- package/bin/commands/mark-files-as-viewed.mjs +7 -0
- package/bin/commands/next-check.d.mts +31 -0
- package/bin/commands/next-check.mjs +46 -0
- package/bin/commands/playbook.d.mts +13 -0
- package/bin/commands/playbook.mjs +48 -0
- package/bin/commands/poll-mode.d.mts +8 -0
- package/bin/commands/poll-mode.mjs +14 -0
- package/bin/commands/poll-progress.d.mts +1 -0
- package/bin/commands/poll-progress.mjs +6 -3
- package/bin/commands/poll-quota.d.mts +3 -2
- package/bin/commands/poll-quota.mjs +7 -3
- package/bin/commands/poll-summary-explicit-instructions.d.mts +2 -0
- package/bin/commands/poll-summary-explicit-instructions.mjs +10 -1
- package/bin/commands/poll-summary-instructions.mjs +16 -17
- package/bin/commands/poll-summary.mjs +42 -17
- package/bin/commands/poll.d.mts +0 -1
- package/bin/commands/poll.mjs +11 -19
- package/bin/commands/quota-selection.d.mts +2 -1
- package/bin/commands/quota-selection.mjs +12 -7
- package/bin/commands/resolve-mutate.mjs +33 -5
- package/bin/commands/rest-stack-merge-readiness.d.mts +4 -0
- package/bin/commands/rest-stack-merge-readiness.mjs +74 -0
- package/bin/commands/rule-auto-resolve.mjs +9 -3
- package/bin/commands/shepherd-journal.d.mts +5 -4
- package/bin/commands/shepherd-journal.mjs +9 -8
- package/bin/commands/stack-drain.d.mts +1 -9
- package/bin/commands/stack-drain.mjs +50 -37
- package/bin/commands/stack-handoffs.d.mts +10 -0
- package/bin/commands/stack-handoffs.mjs +25 -0
- package/bin/commands/stack-stall.d.mts +5 -0
- package/bin/commands/stack-stall.mjs +11 -0
- package/bin/commands/stack-work.d.mts +5 -0
- package/bin/commands/stack-work.mjs +32 -0
- package/bin/comments/existing-reply-scan.d.mts +17 -0
- package/bin/comments/existing-reply-scan.mjs +41 -0
- package/bin/comments/rate-limit.mjs +2 -2
- package/bin/comments/resolve.d.mts +7 -1
- package/bin/comments/resolve.mjs +108 -18
- package/bin/comments/rest-reply.d.mts +9 -0
- package/bin/comments/rest-reply.mjs +95 -0
- package/bin/comments/rest-review-mutations.d.mts +22 -0
- package/bin/comments/rest-review-mutations.mjs +125 -0
- package/bin/comments/review-visibility.d.mts +1 -1
- package/bin/comments/review-visibility.mjs +3 -2
- package/bin/comments/sha-poll.mjs +7 -3
- package/bin/comments/thread-visibility.mjs +10 -5
- package/bin/comments/uncertain-replies.d.mts +11 -0
- package/bin/comments/uncertain-replies.mjs +121 -0
- package/bin/comments/uncertain-reply-guards.d.mts +10 -0
- package/bin/comments/uncertain-reply-guards.mjs +94 -0
- package/bin/comments/visible-comments.d.mts +1 -1
- package/bin/comments/visible-comments.mjs +4 -2
- package/bin/config/load.d.mts +37 -1
- package/bin/config/load.mjs +73 -1
- package/bin/config.json +6 -2
- package/bin/exit-codes.d.mts +3 -0
- package/bin/exit-codes.mjs +8 -0
- package/bin/github/api-telemetry-aggregate.d.mts +15 -4
- package/bin/github/api-telemetry-aggregate.mjs +57 -18
- package/bin/github/api-telemetry.d.mts +4 -0
- package/bin/github/api-telemetry.mjs +22 -8
- package/bin/github/apply-review-preflight.d.mts +20 -0
- package/bin/github/apply-review-preflight.mjs +61 -0
- package/bin/github/base-behind-cache.d.mts +15 -0
- package/bin/github/base-behind-cache.mjs +18 -0
- package/bin/github/batch-parse-suites.d.mts +4 -2
- package/bin/github/batch-parse-suites.mjs +6 -1
- package/bin/github/batch-parser-helpers.mjs +40 -2
- package/bin/github/batch-parsers.mjs +1 -0
- package/bin/github/batch-raw-rules.d.mts +26 -0
- package/bin/github/batch-raw-types.d.mts +8 -6
- package/bin/github/batch-stack-evidence.d.mts +28 -0
- package/bin/github/batch-stack-evidence.mjs +62 -0
- package/bin/github/batch.d.mts +15 -2
- package/bin/github/batch.mjs +34 -17
- package/bin/github/captured-proxy-agent.d.mts +3 -0
- package/bin/github/captured-proxy-agent.mjs +8 -0
- package/bin/github/check-annotations-batch.d.mts +0 -5
- package/bin/github/check-annotations-batch.mjs +25 -4
- package/bin/github/check-annotations.mjs +3 -1
- package/bin/github/client.d.mts +8 -19
- package/bin/github/client.mjs +45 -13
- package/bin/github/fingerprint-fields.d.mts +8 -0
- package/bin/github/fingerprint-fields.mjs +6 -1
- package/bin/github/fingerprint.d.mts +4 -2
- package/bin/github/fingerprint.mjs +6 -38
- package/bin/github/github-fetch.d.mts +2 -0
- package/bin/github/github-fetch.mjs +32 -0
- package/bin/github/gql/base-behind.gql +3 -0
- package/bin/github/gql/batch-pr-page.gql +16 -0
- package/bin/github/gql/batch-pr.gql +57 -0
- package/bin/github/gql/commit-check-contexts.gql +17 -0
- package/bin/github/gql/get-pr-body.gql +1 -0
- package/bin/github/gql/poll-stack-summary.gql +1 -0
- package/bin/github/gql/poll-summary-check-contexts.gql +5 -0
- package/bin/github/gql/poll-summary-fragment.gql +65 -15
- package/bin/github/gql/stack-handoff-check-runs.gql +42 -0
- package/bin/github/graphql-http.mjs +9 -4
- package/bin/github/graphql-internal-retry.d.mts +2 -0
- package/bin/github/graphql-internal-retry.mjs +1 -1
- package/bin/github/graphql-quota-probe.d.mts +6 -0
- package/bin/github/graphql-quota-probe.mjs +56 -0
- package/bin/github/graphql-session-refusal.d.mts +8 -0
- package/bin/github/graphql-session-refusal.mjs +14 -0
- package/bin/github/http-request.d.mts +1 -1
- package/bin/github/http-request.mjs +22 -6
- package/bin/github/http-utils.mjs +6 -0
- package/bin/github/legacy-dispatcher.d.mts +6 -0
- package/bin/github/legacy-dispatcher.mjs +44 -0
- package/bin/github/merge-target-rules.d.mts +12 -3
- package/bin/github/merge-target-rules.mjs +71 -34
- package/bin/github/mutation-policy.d.mts +6 -0
- package/bin/github/mutation-policy.mjs +21 -0
- package/bin/github/poll-summary-annotation-probe.mjs +17 -10
- package/bin/github/poll-summary-check-blockers.d.mts +1 -1
- package/bin/github/poll-summary-check-blockers.mjs +2 -2
- package/bin/github/poll-summary-check-hydration.mjs +25 -10
- package/bin/github/poll-summary-checks.d.mts +2 -2
- package/bin/github/poll-summary-checks.mjs +9 -6
- package/bin/github/poll-summary-command.d.mts +2 -0
- package/bin/github/poll-summary-command.mjs +24 -0
- package/bin/github/poll-summary-fingerprint.d.mts +1 -1
- package/bin/github/poll-summary-fingerprint.mjs +4 -2
- package/bin/github/poll-summary-handoff-fields.d.mts +3 -0
- package/bin/github/poll-summary-handoff-fields.mjs +73 -0
- package/bin/github/poll-summary-projector.d.mts +1 -1
- package/bin/github/poll-summary-projector.mjs +17 -24
- package/bin/github/poll-summary-raw.d.mts +70 -10
- package/bin/github/poll-summary-readiness.d.mts +6 -1
- package/bin/github/poll-summary-readiness.mjs +13 -4
- package/bin/github/poll-summary-rest-queue.d.mts +3 -0
- package/bin/github/poll-summary-rest-queue.mjs +12 -0
- package/bin/github/poll-summary-review.d.mts +1 -1
- package/bin/github/poll-summary-review.mjs +35 -20
- package/bin/github/poll-summary-route.mjs +19 -3
- package/bin/github/poll-summary-stack-page.d.mts +11 -0
- package/bin/github/poll-summary-stack-page.mjs +27 -0
- package/bin/github/poll-summary-unreported.d.mts +3 -1
- package/bin/github/poll-summary-unreported.mjs +6 -3
- package/bin/github/poll-summary.d.mts +4 -1
- package/bin/github/poll-summary.mjs +47 -33
- package/bin/github/queries.d.mts +7 -3
- package/bin/github/queries.mjs +8 -4
- package/bin/github/rate-limit-sample.d.mts +7 -0
- package/bin/github/rate-limit-sample.mjs +12 -0
- package/bin/github/reply-recovery-read.d.mts +50 -0
- package/bin/github/reply-recovery-read.mjs +118 -0
- package/bin/github/reply-thread-transcripts.d.mts +0 -1
- package/bin/github/reply-thread-transcripts.mjs +24 -1
- package/bin/github/rest-annotation-read.d.mts +5 -0
- package/bin/github/rest-annotation-read.mjs +44 -0
- package/bin/github/rest-batch-read.d.mts +12 -0
- package/bin/github/rest-batch-read.mjs +57 -0
- package/bin/github/rest-batch-snapshot.d.mts +30 -0
- package/bin/github/rest-batch-snapshot.mjs +115 -0
- package/bin/github/rest-batch-unavailable.d.mts +5 -0
- package/bin/github/rest-batch-unavailable.mjs +16 -0
- package/bin/github/rest-check-read.d.mts +34 -0
- package/bin/github/rest-check-read.mjs +124 -0
- package/bin/github/rest-comment-authorship.d.mts +7 -0
- package/bin/github/rest-comment-authorship.mjs +11 -0
- package/bin/github/rest-conditional-scope.d.mts +20 -0
- package/bin/github/rest-conditional-scope.mjs +44 -0
- package/bin/github/rest-explicit-summary-read.d.mts +3 -0
- package/bin/github/rest-explicit-summary-read.mjs +8 -0
- package/bin/github/rest-feedback-read.d.mts +36 -0
- package/bin/github/rest-feedback-read.mjs +147 -0
- package/bin/github/rest-feedback-validation.d.mts +5 -0
- package/bin/github/rest-feedback-validation.mjs +28 -0
- package/bin/github/rest-http.d.mts +12 -0
- package/bin/github/rest-http.mjs +108 -23
- package/bin/github/rest-identities.d.mts +22 -0
- package/bin/github/rest-identities.mjs +134 -0
- package/bin/github/rest-merge-stack-guard.d.mts +14 -0
- package/bin/github/rest-merge-stack-guard.mjs +41 -0
- package/bin/github/rest-merge.d.mts +29 -0
- package/bin/github/rest-merge.mjs +56 -0
- package/bin/github/rest-merged-base-read.d.mts +9 -0
- package/bin/github/rest-merged-base-read.mjs +48 -0
- package/bin/github/rest-pr-core.d.mts +52 -0
- package/bin/github/rest-pr-core.mjs +60 -0
- package/bin/github/rest-reader-core.d.mts +16 -0
- package/bin/github/rest-reader-core.mjs +154 -0
- package/bin/github/rest-review-read.d.mts +11 -0
- package/bin/github/rest-review-read.mjs +47 -0
- package/bin/github/rest-rules-read.d.mts +9 -0
- package/bin/github/rest-rules-read.mjs +154 -0
- package/bin/github/rest-session-refusal.d.mts +5 -0
- package/bin/github/rest-session-refusal.mjs +21 -0
- package/bin/github/rest-snapshot-context.d.mts +10 -0
- package/bin/github/rest-snapshot-context.mjs +1 -0
- package/bin/github/rest-stack-read.d.mts +21 -0
- package/bin/github/rest-stack-read.mjs +47 -0
- package/bin/github/rest-stack-summary.d.mts +8 -0
- package/bin/github/rest-stack-summary.mjs +62 -0
- package/bin/github/rest-summary-read.d.mts +7 -0
- package/bin/github/rest-summary-read.mjs +112 -0
- package/bin/github/rest-terminal-batch.d.mts +14 -0
- package/bin/github/rest-terminal-batch.mjs +45 -0
- package/bin/github/rest-text.mjs +7 -3
- package/bin/github/rest-thread-read.d.mts +4 -0
- package/bin/github/rest-thread-read.mjs +35 -0
- package/bin/github/rest-viewer-read.d.mts +2 -0
- package/bin/github/rest-viewer-read.mjs +41 -0
- package/bin/github/stack-bottom.d.mts +3 -0
- package/bin/github/stack-bottom.mjs +14 -0
- package/bin/github/stack-handoff-context.d.mts +25 -0
- package/bin/github/stack-handoff-context.mjs +12 -0
- package/bin/github/stack-handoff-page.d.mts +17 -0
- package/bin/github/stack-handoff-page.mjs +306 -0
- package/bin/github/stack-handoff.d.mts +16 -0
- package/bin/github/stack-handoff.mjs +115 -0
- package/bin/github/stack-order.d.mts +6 -0
- package/bin/github/stack-order.mjs +13 -0
- package/bin/github/stack-read.d.mts +7 -5
- package/bin/github/stack-read.mjs +22 -24
- package/bin/github/stack-size-hint.d.mts +3 -0
- package/bin/github/stack-size-hint.mjs +14 -0
- package/bin/github/suggestion-thread.mjs +27 -1
- package/bin/github/thread-comments.mjs +9 -1
- package/bin/github/transport-evidence.d.mts +20 -0
- package/bin/github/transport-evidence.mjs +26 -0
- package/bin/github/transport-mode.d.mts +2 -0
- package/bin/github/transport-mode.mjs +5 -0
- package/bin/github/transport.d.mts +19 -0
- package/bin/github/transport.mjs +126 -0
- package/bin/github/unsupported-rest.d.mts +4 -0
- package/bin/github/unsupported-rest.mjs +7 -0
- package/bin/mcp/server.mjs +52 -3
- package/bin/merge-status/derive.d.mts +2 -0
- package/bin/merge-status/derive.mjs +17 -13
- package/bin/merge-status/required-check-requirements.d.mts +7 -0
- package/bin/merge-status/required-check-requirements.mjs +15 -0
- package/bin/merge-status/requirements-format.d.mts +5 -0
- package/bin/merge-status/requirements-format.mjs +41 -12
- package/bin/merge-status/requirements.mjs +18 -7
- package/bin/state/base.mjs +41 -0
- package/bin/state/durable-state.d.mts +6 -0
- package/bin/state/durable-state.mjs +41 -0
- package/bin/state/graphql-quota-policy.mjs +23 -16
- package/bin/state/merge-request.d.mts +25 -0
- package/bin/state/merge-request.mjs +145 -0
- package/bin/state/pr-fingerprint.d.mts +15 -0
- package/bin/state/pr-fingerprint.mjs +22 -7
- package/bin/state/rest-cache.d.mts +3 -0
- package/bin/state/rest-cache.mjs +1 -0
- package/bin/state/rest-snapshot-report.d.mts +21 -0
- package/bin/state/rest-snapshot-report.mjs +52 -0
- package/bin/state/seen-comments.d.mts +3 -0
- package/bin/state/seen-comments.mjs +18 -0
- package/bin/types/api-usage.d.mts +9 -1
- package/bin/types/escalate.d.mts +1 -1
- package/bin/types/github.d.mts +23 -9
- package/bin/types/iterate.d.mts +24 -2
- package/bin/types/merge-action.d.mts +1 -1
- package/bin/types/merge-requirements.d.mts +7 -7
- package/bin/types/next-check.d.mts +12 -0
- package/bin/types/next-check.mjs +1 -0
- package/bin/types/poll-summary.d.mts +21 -0
- package/bin/types/report.d.mts +13 -1
- package/bin/types/review-thread.d.mts +1 -1
- package/bin/types.d.mts +1 -0
- package/bin/types.mjs +1 -0
- package/package.json +4 -3
- package/plugins/pr-shepherd/.codex-plugin/plugin.json +1 -1
- package/plugins/pr-shepherd/.codex.mcp.json +1 -1
- package/plugins/pr-shepherd/.mcp.json +1 -1
- package/plugins/pr-shepherd/skills/mark-files-as-viewed/SKILL.md +1 -1
- package/plugins/pr-shepherd/skills/pr-shepherd/SKILL.md +14 -51
- package/plugins/pr-shepherd/skills/pr-shepherd/references/ci-failure-triage.md +12 -16
- package/plugins/pr-shepherd/skills/pr-shepherd/references/cloud-event-loop.md +14 -0
- package/plugins/pr-shepherd/skills/pr-shepherd/references/create-pr.md +10 -0
- package/plugins/pr-shepherd/skills/pr-shepherd/references/fix-code-loop.md +10 -0
- package/plugins/pr-shepherd/skills/pr-shepherd/references/mcp-fallback.md +9 -0
- package/plugins/pr-shepherd/skills/reduce-pr-noise/references/classifiers.md +3 -1
- package/bin/github/gql/pr-fingerprint.gql +0 -75
- package/plugins/pr-shepherd/skills/pr-shepherd/references/journal.md +0 -7
- package/plugins/pr-shepherd/skills/pr-shepherd/references/review-mutations.md +0 -9
- package/plugins/pr-shepherd/skills/pr-shepherd/references/stack-merge.md +0 -7
|
@@ -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 {};
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { buildPrShepherdCommand } from "../cli/runner.mjs";
|
|
2
|
+
import { formatPrUrl } from "../pr-reference.mjs";
|
|
1
3
|
/**
|
|
2
4
|
* The one-PR hold reason for a `READY` draft that only the disabled setting keeps in draft. The
|
|
3
5
|
* probe re-reads the draft, so this phrase, not a bare `[WAIT]`, proves it is still clean.
|
|
@@ -30,9 +32,39 @@ export function splitStackWork(candidates, staleChildren) {
|
|
|
30
32
|
*/
|
|
31
33
|
export function appendMarkReadyInstructions(instructions, layers) {
|
|
32
34
|
for (const item of layers) {
|
|
35
|
+
if (!item.owned) {
|
|
36
|
+
instructions.push(`${instructions.length + 1}. PR #${item.pr} is not owned. Leave its draft state unchanged.`);
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
if (item.transport === "rest") {
|
|
40
|
+
const command = buildPrShepherdCommand([
|
|
41
|
+
"iterate",
|
|
42
|
+
formatPrUrl(item.repo, item.pr),
|
|
43
|
+
"--transport",
|
|
44
|
+
"rest",
|
|
45
|
+
]).text;
|
|
46
|
+
instructions.push(`${instructions.length + 1}. Run \`${item.pollCommand}\` first for PR #${item.pr}. If it returns \`[WAIT]\` saying the draft is held only because automatic mark-ready is disabled, run \`${command}\` to authorize the CCR ready transition; otherwise follow the probe's instructions.`);
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
33
49
|
instructions.push(`${instructions.length + 1}. Automatic mark-ready is disabled, so marking PR #${item.pr} ready for review is your step. Run \`${item.pollCommand}\` first. If it returns \`[WAIT]\` saying PR #${item.pr} stays in draft because ${AUTO_MARK_READY_DISABLED_HOLD}, run \`gh pr ready ${item.pr} -R ${item.repo}\`; otherwise complete its instructions and leave PR #${item.pr} in draft this round.`);
|
|
34
50
|
}
|
|
35
51
|
}
|
|
36
52
|
function isProbed(item) {
|
|
37
53
|
return item.pollProbe === true && item.pollCommand !== undefined;
|
|
38
54
|
}
|
|
55
|
+
/**
|
|
56
|
+
* Work exists, but every routed layer belongs to another author: rerunning the stack selector
|
|
57
|
+
* cannot change anything, so the caller reports the overview and stops instead.
|
|
58
|
+
*/
|
|
59
|
+
function onlyUnownedWork(layers) {
|
|
60
|
+
return layers.length > 0 && layers.every((item) => !item.owned);
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* The closing step after routed sessions: rerun the selector, or stop when nothing is owned.
|
|
64
|
+
* Returns the plan action: a stop is a handoff, so no rerun, quota cadence, or wake-up follows it.
|
|
65
|
+
*/
|
|
66
|
+
export function appendStackRerunInstruction(instructions, layers, rerun) {
|
|
67
|
+
const stop = onlyUnownedWork(layers);
|
|
68
|
+
instructions.push(`${instructions.length + 1}. ${stop ? "No owned layer needs a session. Report this overview and stop." : rerun}`);
|
|
69
|
+
return stop ? "escalate" : "shepherd";
|
|
70
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { RepoInfo } from "../github/client.mts";
|
|
2
|
+
import { type ReplyEvidence } from "../github/reply-recovery-read.mts";
|
|
3
|
+
/**
|
|
4
|
+
* Threads whose last comment is already this exact Shepherd reply from the authenticated viewer.
|
|
5
|
+
*
|
|
6
|
+
* A cloud session can lose its state directory between ticks, taking the uncertain-reply
|
|
7
|
+
* records with it. With no local record to consult, GitHub is the only evidence of whether a
|
|
8
|
+
* reply already landed, so the `apply review` commands Shepherd generates in durable-state
|
|
9
|
+
* sessions opt in (`--adopt-existing-replies`) to checking it before posting. Direct apply
|
|
10
|
+
* requests never run this scan. A failed read never blocks the reply: it only means this
|
|
11
|
+
* safeguard had nothing to say. A batch fully covered by `preloaded` evidence (the
|
|
12
|
+
* apply-review preflight, read with no wait since) skips its read.
|
|
13
|
+
*/
|
|
14
|
+
export declare function findExistingReplies(context: {
|
|
15
|
+
repo: RepoInfo;
|
|
16
|
+
pr: number;
|
|
17
|
+
}, ids: readonly string[], message: string, preloaded?: Map<string, ReplyEvidence>): Promise<string[]>;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { readReplyRecoveryEvidence } from "../github/reply-recovery-read.mjs";
|
|
2
|
+
import { addPrShepherdMarker } from "./marker.mjs";
|
|
3
|
+
const BATCH = 10;
|
|
4
|
+
/**
|
|
5
|
+
* Threads whose last comment is already this exact Shepherd reply from the authenticated viewer.
|
|
6
|
+
*
|
|
7
|
+
* A cloud session can lose its state directory between ticks, taking the uncertain-reply
|
|
8
|
+
* records with it. With no local record to consult, GitHub is the only evidence of whether a
|
|
9
|
+
* reply already landed, so the `apply review` commands Shepherd generates in durable-state
|
|
10
|
+
* sessions opt in (`--adopt-existing-replies`) to checking it before posting. Direct apply
|
|
11
|
+
* requests never run this scan. A failed read never blocks the reply: it only means this
|
|
12
|
+
* safeguard had nothing to say. A batch fully covered by `preloaded` evidence (the
|
|
13
|
+
* apply-review preflight, read with no wait since) skips its read.
|
|
14
|
+
*/
|
|
15
|
+
export async function findExistingReplies(context, ids, message, preloaded) {
|
|
16
|
+
if (ids.length === 0)
|
|
17
|
+
return [];
|
|
18
|
+
const marked = addPrShepherdMarker(message);
|
|
19
|
+
const found = [];
|
|
20
|
+
for (let offset = 0; offset < ids.length; offset += BATCH) {
|
|
21
|
+
const batch = ids.slice(offset, offset + BATCH);
|
|
22
|
+
try {
|
|
23
|
+
const evidence = batch.every((id) => preloaded?.has(id))
|
|
24
|
+
? preloaded
|
|
25
|
+
: await readReplyRecoveryEvidence(context.repo, context.pr, batch);
|
|
26
|
+
for (const id of batch) {
|
|
27
|
+
const item = evidence.get(id);
|
|
28
|
+
const last = item?.comments.at(-1);
|
|
29
|
+
if (item &&
|
|
30
|
+
last?.body === marked &&
|
|
31
|
+
last.author?.toLowerCase() === item.viewer.toLowerCase()) {
|
|
32
|
+
found.push(id);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
/* Evidence is advisory here; the normal reply path still runs. */
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return found;
|
|
41
|
+
}
|
|
@@ -17,7 +17,7 @@ export function rateLimitFromGraphQlResult(messages, meta) {
|
|
|
17
17
|
if (message)
|
|
18
18
|
return buildRateLimitStop(message, meta);
|
|
19
19
|
if (meta.stopOnZeroRemaining === true && meta.rateLimit?.remaining === 0) {
|
|
20
|
-
return buildRateLimitStop(
|
|
20
|
+
return buildRateLimitStop(`GitHub ${meta.rateLimit?.resource === "core" ? "REST core" : "GraphQL"} rate limit remaining is 0`, meta);
|
|
21
21
|
}
|
|
22
22
|
return undefined;
|
|
23
23
|
}
|
|
@@ -47,5 +47,5 @@ function finiteNumber(value) {
|
|
|
47
47
|
return typeof value === "number" && Number.isFinite(value) ? value : undefined;
|
|
48
48
|
}
|
|
49
49
|
export function isRateLimitMessage(message) {
|
|
50
|
-
return /rate limit|rate-limit|secondary limit|secondary rate/i.test(message);
|
|
50
|
+
return /rate limit|rate-limit|secondary limit|secondary rate|abuse detection/i.test(message);
|
|
51
51
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { type RepoInfo } from "../github/client.mts";
|
|
2
2
|
import type { ResolveOptions } from "../types.mts";
|
|
3
3
|
import { type ResolveRateLimitStop } from "./rate-limit.mts";
|
|
4
|
+
import { type ReplyEvidence } from "../github/reply-recovery-read.mts";
|
|
4
5
|
export interface ResolveResult {
|
|
5
6
|
repliedThreads: string[];
|
|
6
7
|
resolvedThreads: string[];
|
|
@@ -26,12 +27,17 @@ export interface ResolveResult {
|
|
|
26
27
|
/** @deprecated Direct apply requests now rely on GitHub's mutation response. */
|
|
27
28
|
skippedUnauthorizedDismissals?: string[];
|
|
28
29
|
rateLimit?: ResolveRateLimitStop;
|
|
30
|
+
sessionRefusal?: string;
|
|
31
|
+
instructions?: string[];
|
|
29
32
|
unrepliedThreads?: string[];
|
|
30
33
|
unresolvedThreads?: string[];
|
|
31
34
|
unminimizedComments?: string[];
|
|
32
35
|
undismissedReviews?: string[];
|
|
33
36
|
}
|
|
34
|
-
export declare function applyResolveOptions(pr: number, repo: RepoInfo, opts: ResolveOptions
|
|
37
|
+
export declare function applyResolveOptions(pr: number, repo: RepoInfo, opts: ResolveOptions, preflight?: {
|
|
38
|
+
headSha?: string;
|
|
39
|
+
evidence: Map<string, ReplyEvidence>;
|
|
40
|
+
}): Promise<ResolveResult>;
|
|
35
41
|
/** @deprecated Compatibility alias; use `autoResolveThreads`. */
|
|
36
42
|
export declare function autoResolveOutdated(threadIds: string[]): Promise<{
|
|
37
43
|
resolved: string[];
|