pr-shepherd 0.60.1 → 1.0.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 +7 -5
- package/bin/api.d.mts +35 -24
- package/bin/api.mjs +68 -48
- package/bin/checks/classify.d.mts +1 -1
- package/bin/checks/classify.mjs +4 -4
- package/bin/checks/log-excerpt.mjs +1 -1
- package/bin/cli/arg-flags.mjs +0 -3
- package/bin/cli/clean-handler.d.mts +1 -1
- package/bin/cli/clean-handler.mjs +5 -15
- package/bin/cli/default-poll.d.mts +2 -0
- package/bin/cli/default-poll.mjs +9 -6
- package/bin/cli/formatters.d.mts +2 -3
- package/bin/cli/formatters.mjs +0 -26
- package/bin/cli/handlers.d.mts +3 -3
- package/bin/cli/handlers.mjs +45 -35
- package/bin/cli/help-command-pages.d.mts +13 -158
- package/bin/cli/help-command-pages.mjs +12 -157
- package/bin/cli/help-iterate-poll-pages.d.mts +4 -3
- package/bin/cli/help-iterate-poll-pages.mjs +76 -36
- package/bin/cli/help-log-file-page.d.mts +1 -1
- package/bin/cli/help-log-file-page.mjs +3 -5
- package/bin/cli/help-top-page.d.mts +1 -1
- package/bin/cli/help-top-page.mjs +19 -20
- package/bin/cli/help.d.mts +14 -159
- package/bin/cli/iterate-checks-formatter.mjs +1 -1
- package/bin/cli/iterate-flags.d.mts +2 -4
- package/bin/cli/iterate-flags.mjs +4 -20
- package/bin/cli/iterate-formatter.d.mts +1 -1
- package/bin/cli/iterate-formatter.mjs +6 -6
- package/bin/cli/iterate-instructions.d.mts +1 -1
- package/bin/cli/iterate-instructions.mjs +5 -6
- package/bin/cli/iterate-lean.mjs +32 -40
- package/bin/cli/iterate-verbose.mjs +1 -1
- package/bin/cli/journal-formatter.mjs +0 -3
- package/bin/cli/journal-handler.d.mts +1 -1
- package/bin/cli/journal-handler.mjs +2 -1
- package/bin/cli/mutate-formatter.mjs +0 -9
- package/bin/cli/next-check-format.d.mts +0 -4
- package/bin/cli/next-check-format.mjs +0 -4
- package/bin/cli/poll-handler.d.mts +3 -0
- package/bin/cli/poll-handler.mjs +88 -47
- package/bin/cli/poll-summary-emitter.mjs +2 -2
- package/bin/cli/poll-summary-formatter.mjs +2 -2
- package/bin/cli/poll-targets.d.mts +2 -2
- package/bin/cli/poll-targets.mjs +15 -35
- package/bin/cli/removed-flags.d.mts +3 -0
- package/bin/cli/removed-flags.mjs +24 -0
- package/bin/cli/runner.d.mts +1 -1
- package/bin/cli/runner.mjs +2 -2
- package/bin/cli/stack-overview.d.mts +0 -1
- package/bin/cli/stack-overview.mjs +1 -2
- package/bin/cli/{fix-formatter-extra.d.mts → triage-formatter-extra.d.mts} +1 -2
- package/bin/cli/{fix-formatter-extra.mjs → triage-formatter-extra.mjs} +0 -6
- package/bin/cli/triage-formatter.d.mts +4 -0
- package/bin/cli/{fix-formatter.mjs → triage-formatter.mjs} +31 -42
- package/bin/cli/unknown-flags.d.mts +6 -0
- package/bin/cli/unknown-flags.mjs +29 -0
- package/bin/cli-parser.mjs +41 -62
- package/bin/commands/check-annotations.d.mts +1 -1
- package/bin/commands/check-annotations.mjs +1 -1
- package/bin/commands/check-review-budget.d.mts +1 -1
- package/bin/commands/check-review-budget.mjs +1 -1
- package/bin/commands/check-wait-detectors.d.mts +1 -1
- package/bin/commands/check-wait-detectors.mjs +1 -1
- package/bin/commands/check.d.mts +1 -1
- package/bin/commands/check.mjs +7 -7
- package/bin/commands/commit-suggestion-instruction.d.mts +2 -2
- package/bin/commands/commit-suggestion-instruction.mjs +3 -3
- package/bin/commands/iterate/api-usage.mjs +8 -8
- package/bin/commands/iterate/check-instructions.d.mts +4 -4
- package/bin/commands/iterate/check-instructions.mjs +8 -8
- package/bin/commands/iterate/classify.mjs +2 -2
- package/bin/commands/iterate/escalate.mjs +6 -6
- package/bin/commands/iterate/index.mjs +20 -23
- package/bin/commands/iterate/merge-plan.mjs +3 -3
- package/bin/commands/iterate/merge-state.mjs +4 -7
- package/bin/commands/iterate/native-stack-rebase.mjs +1 -1
- package/bin/commands/iterate/render.d.mts +1 -1
- package/bin/commands/iterate/render.mjs +2 -2
- package/bin/commands/iterate/stall.mjs +11 -9
- package/bin/commands/iterate/{fix-loop-instruction.mjs → triage-loop-instruction.mjs} +7 -3
- package/bin/commands/iterate/{fix-code.d.mts → triage.d.mts} +2 -2
- package/bin/commands/iterate/{fix-code.mjs → triage.mjs} +14 -23
- package/bin/commands/iterate/unreported-required.mjs +2 -5
- package/bin/commands/journal/index.d.mts +1 -3
- package/bin/commands/journal/index.mjs +1 -1
- package/bin/commands/mark-files-as-viewed.d.mts +1 -3
- package/bin/commands/mark-files-as-viewed.mjs +1 -1
- package/bin/commands/next-check.d.mts +2 -2
- package/bin/commands/next-check.mjs +4 -2
- package/bin/commands/poll-progress.mjs +1 -1
- package/bin/commands/poll-summary-explicit-instructions.mjs +1 -1
- package/bin/commands/poll-summary-instructions.mjs +7 -7
- package/bin/commands/poll-summary.mjs +4 -4
- package/bin/commands/poll.d.mts +1 -1
- package/bin/commands/poll.mjs +4 -4
- package/bin/commands/resolve-mutate.d.mts +1 -1
- package/bin/commands/resolve-mutate.mjs +1 -1
- package/bin/commands/rest-stack-merge-readiness.mjs +1 -1
- package/bin/commands/single-tick.d.mts +5 -0
- package/bin/commands/single-tick.mjs +7 -0
- package/bin/commands/stack-drain.mjs +1 -1
- package/bin/commands/stack-merge-flag.mjs +1 -1
- package/bin/commands/stack-stall.d.mts +2 -2
- package/bin/commands/stack-stall.mjs +2 -2
- package/bin/commands/stack-work.d.mts +2 -2
- package/bin/commands/stack-work.mjs +2 -2
- package/bin/commands/suggestion-patch-item.d.mts +0 -1
- package/bin/commands/suggestion-patch-item.mjs +0 -12
- package/bin/commands/suggestion-patches.d.mts +2 -2
- package/bin/commands/suggestion-patches.mjs +1 -1
- package/bin/commands/tick-instructions.d.mts +9 -0
- package/bin/commands/tick-instructions.mjs +23 -0
- package/bin/commands/tick.d.mts +15 -0
- package/bin/commands/{event-mode.mjs → tick.mjs} +39 -55
- package/bin/comments/minimize-policy.mjs +1 -3
- package/bin/comments/resolve.d.mts +0 -23
- package/bin/comments/resolve.mjs +0 -4
- package/bin/comments/review-output-budget.d.mts +1 -1
- package/bin/comments/review-output-budget.mjs +1 -1
- package/bin/comments/sha-poll.mjs +3 -1
- package/bin/config/default-bot-usernames.d.mts +2 -0
- package/bin/config/default-bot-usernames.mjs +15 -0
- package/bin/config/load.d.mts +4 -138
- package/bin/config/load.mjs +88 -443
- package/bin/config/merge-command-args.mjs +2 -2
- package/bin/config/merge-method.d.mts +1 -2
- package/bin/config/merge-method.mjs +1 -8
- package/bin/config/renames.d.mts +8 -0
- package/bin/config/renames.mjs +87 -0
- package/bin/config/resolve.d.mts +31 -0
- package/bin/config/resolve.mjs +89 -0
- package/bin/config/schema.d.mts +161 -0
- package/bin/config/schema.mjs +168 -0
- package/bin/exit-codes.d.mts +1 -1
- package/bin/exit-codes.mjs +3 -3
- package/bin/github/poll-summary-check-blockers.mjs +1 -1
- package/bin/github/poll-summary-command.mjs +8 -6
- package/bin/github/poll-summary-projector.mjs +2 -2
- package/bin/github/poll-summary-review.mjs +1 -1
- package/bin/github/poll-summary-route.mjs +9 -9
- package/bin/github/poll-summary-unreported.mjs +1 -1
- package/bin/github/poll-summary.mjs +1 -1
- package/bin/github/queries.d.mts +1 -1
- package/bin/github/queries.mjs +1 -1
- package/bin/mcp/server.mjs +48 -54
- package/bin/merge-status/derive.mjs +1 -1
- package/bin/state/durable-state.d.mts +1 -3
- package/bin/state/durable-state.mjs +2 -8
- package/bin/state/fix-attempts.d.mts +2 -2
- package/bin/state/fix-attempts.mjs +1 -1
- package/bin/state/merge-request.mjs +1 -1
- package/bin/state/pr-fingerprint.mjs +4 -11
- package/bin/state/seen-comments.d.mts +4 -5
- package/bin/state/seen-comments.mjs +8 -14
- package/bin/state/stack-stall.d.mts +1 -1
- package/bin/state/stack-stall.mjs +1 -1
- package/bin/state/stall-state-store.d.mts +1 -1
- package/bin/state/stall-state-store.mjs +1 -1
- package/bin/types/escalate.d.mts +2 -2
- package/bin/types/iterate.d.mts +12 -26
- package/bin/types/merge-queue.d.mts +2 -2
- package/bin/types/next-check.d.mts +1 -1
- package/bin/types/poll-summary.d.mts +3 -6
- package/bin/types/report.d.mts +2 -2
- package/bin/types/suggestion-patch.d.mts +1 -8
- package/package.json +2 -1
- package/plugins/pr-shepherd/.claude-plugin/plugin.json +1 -1
- 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/pr-shepherd/SKILL.md +6 -6
- package/plugins/pr-shepherd/skills/pr-shepherd/references/ci-failure-triage.md +1 -1
- package/plugins/pr-shepherd/skills/pr-shepherd/references/{cloud-event-loop.md → event-loop.md} +5 -5
- package/plugins/pr-shepherd/skills/pr-shepherd/references/mcp-fallback.md +3 -3
- package/plugins/pr-shepherd/skills/pr-shepherd/references/merge-queue-ejection.md +1 -1
- package/plugins/pr-shepherd/skills/pr-shepherd/references/suggestion-patches.md +1 -1
- package/plugins/pr-shepherd/skills/pr-shepherd/references/{fix-code-loop.md → triage-loop.md} +3 -3
- package/plugins/pr-shepherd/skills/reduce-pr-noise/SKILL.md +1 -1
- package/plugins/pr-shepherd/skills/reduce-pr-noise/references/classifiers.md +2 -2
- package/plugins/pr-shepherd/skills/reduce-pr-noise/references/settings.md +11 -11
- package/pr-shepherd.schema.json +361 -0
- package/bin/cli/event-state-scope.d.mts +0 -19
- package/bin/cli/event-state-scope.mjs +0 -60
- package/bin/cli/fix-formatter.d.mts +0 -4
- package/bin/commands/commit-suggestion.d.mts +0 -8
- package/bin/commands/commit-suggestion.mjs +0 -26
- package/bin/commands/event-instructions.d.mts +0 -11
- package/bin/commands/event-instructions.mjs +0 -27
- package/bin/commands/event-mode.d.mts +0 -14
- package/bin/commands/poll-mode.d.mts +0 -8
- package/bin/commands/poll-mode.mjs +0 -14
- package/bin/config.json +0 -68
- package/bin/types/protected-run.d.mts +0 -6
- package/bin/types/protected-run.mjs +0 -1
- /package/bin/commands/iterate/{fix-loop-instruction.d.mts → triage-loop-instruction.d.mts} +0 -0
package/README.md
CHANGED
|
@@ -13,7 +13,7 @@ Drive a pull request to merge-ready with a coding agent. It works with Claude Co
|
|
|
13
13
|
```text
|
|
14
14
|
$ pr-shepherd 123
|
|
15
15
|
|
|
16
|
-
# PR #123 [
|
|
16
|
+
# PR #123 [TRIAGE]
|
|
17
17
|
|
|
18
18
|
**status** `UNRESOLVED_COMMENTS` · **repo** `owner/repo`
|
|
19
19
|
**summary** 3 passing
|
|
@@ -96,7 +96,7 @@ These are offline estimates at 3.5 characters per token over recorded sessions,
|
|
|
96
96
|
|
|
97
97
|
### Clearer agent direction
|
|
98
98
|
|
|
99
|
-
For a single PR, each tick returns exactly one action: `WAIT`, `READY`, `MARK_READY`, `
|
|
99
|
+
For a single PR, each tick returns exactly one action: `WAIT`, `READY`, `MARK_READY`, `TRIAGE`, `MERGE`, `CANCEL`, or `ESCALATE`. A `stack` poll can also return `SHEPHERD`, which starts one-PR sessions for owned layers. Every action except `CANCEL` comes with numbered `## Instructions` and exact commands, so the agent does not invent policy. In the [behavior evals](evals/README.md), Sonnet 5.5 at low effort scores **0.94** with the plugin and **0.82** without it on the 36 GitHub-gotcha cases, so it misses about two-thirds fewer graded checks (0.18 → 0.06). On the eight gotchas listed under [Context and correctness](#context-and-correctness) it goes from 0.50 to 0.92. Weighted toward those gotchas, the mean Δ over all 52 cases is **+0.14**, and no case has a regression whose interval excludes 0. See [docs/actions.md](docs/actions.md) for the output contract.
|
|
100
100
|
|
|
101
101
|
### Lower GitHub API quota use
|
|
102
102
|
|
|
@@ -139,8 +139,8 @@ See [docs/graphql-usage.md](docs/graphql-usage.md) and [docs/rest-usage.md](docs
|
|
|
139
139
|
- The plugin ships [skills](docs/skills.md) for Claude Code, Codex, and Grok.
|
|
140
140
|
- Cursor and other stdio clients use the [MCP server](docs/mcp.md).
|
|
141
141
|
- Shell and CI use the [CLI](docs/cli-usage.md).
|
|
142
|
-
- In Claude Code cloud sessions, Shepherd switches to the [REST transport](docs/rest.md) and [
|
|
143
|
-
-
|
|
142
|
+
- In Claude Code cloud sessions, Shepherd switches to the [REST transport](docs/rest.md) and [single ticks](docs/cloud.md).
|
|
143
|
+
- `stack` reports every layer of a native GitHub stacked PR and shepherds the layers you own.
|
|
144
144
|
|
|
145
145
|
## Use cases
|
|
146
146
|
|
|
@@ -151,9 +151,10 @@ See [docs/graphql-usage.md](docs/graphql-usage.md) and [docs/rest-usage.md](docs
|
|
|
151
151
|
|
|
152
152
|
1. **Install the MCP server and the CLI.** See [Install](#install) below.
|
|
153
153
|
2. **Write your policy into a skill or agent instruction.** Examples: "skip non-blocking review comments", "reply instead of fixing nits", "never merge". Shepherd reports state and the next action. Your instructions decide how the agent treats each comment. The shipped `pr-shepherd` skill is a thin dispatcher you can wrap ([docs/skills.md](docs/skills.md)).
|
|
154
|
-
3. **Configure Shepherd.** In `.pr-shepherdrc.yml`, turn on the bundled classification rules. They drop known bot noise before it reaches the agent, which saves more tokens and tool calls. With the default `actions.
|
|
154
|
+
3. **Configure Shepherd.** In `.pr-shepherdrc.yml`, turn on the bundled classification rules. They drop known bot noise before it reaches the agent, which saves more tokens and tool calls. With the default `actions.auto-minimize-suppressed: true`, several rules also minimize matching comments on GitHub and surface the mutation result without editing the PR body. See [docs/configuration.md](docs/configuration.md#classifystandard--default-).
|
|
155
155
|
|
|
156
156
|
```yaml
|
|
157
|
+
version: 1
|
|
157
158
|
classify:
|
|
158
159
|
standard:
|
|
159
160
|
all: true
|
|
@@ -212,6 +213,7 @@ Leave out the PR number to use the current branch.
|
|
|
212
213
|
| Configuration and classification rules | [docs/configuration.md](docs/configuration.md), [examples/classification/](examples/classification/) |
|
|
213
214
|
| Journal, library API | [docs/api.md](docs/api.md) |
|
|
214
215
|
| Compared with Cursor, Copilot, CodeRabbit, … | [docs/comparison.md](docs/comparison.md) |
|
|
216
|
+
| Upgrading from 0.x | [docs/migrating-to-v1.md](docs/migrating-to-v1.md) |
|
|
215
217
|
|
|
216
218
|
## Harness ecosystem
|
|
217
219
|
|
package/bin/api.d.mts
CHANGED
|
@@ -4,11 +4,20 @@ import { type ApplyMergeResult } from "./commands/apply-merge.mts";
|
|
|
4
4
|
import type { RestMergeAction, RestMergeStackGuard } from "./github/rest-merge.mts";
|
|
5
5
|
export type { RestMergeStackGuard } from "./github/rest-merge.mts";
|
|
6
6
|
import type { MergeMethod } from "./config/merge-method.mts";
|
|
7
|
+
import { type CheckBlockerCommandResult } from "./commands/apply-check-blocker.mts";
|
|
7
8
|
import { type JournalResult } from "./commands/journal/index.mts";
|
|
8
9
|
import { type MarkFilesAsViewedResult } from "./commands/mark-files-as-viewed.mts";
|
|
9
10
|
import { type ApplyQueueRemovalResult } from "./commands/apply-queue-removal.mts";
|
|
10
11
|
import type { ResolveResult } from "./comments/resolve.mts";
|
|
11
|
-
import type {
|
|
12
|
+
import type { SuggestResult, IterateCommandOptions, IterateResult, PollSummaryResult } from "./types.mts";
|
|
13
|
+
export type { CancelReason, IterateResult, IterateResultTriage, IterateResultMerge, NextCheck, PollSummaryItem, PollSummaryResult, ShepherdAction, ShepherdMergeStatus, ShepherdStatus, StackNextAction, SuggestResult, SuggestionPatchResult, } from "./types.mts";
|
|
14
|
+
export type { ApplyMergeResult } from "./commands/apply-merge.mts";
|
|
15
|
+
export type { MarkFilesAsViewedResult } from "./commands/mark-files-as-viewed.mts";
|
|
16
|
+
export type { ApplyQueueRemovalResult } from "./commands/apply-queue-removal.mts";
|
|
17
|
+
export type { CheckBlockerCommandResult } from "./commands/apply-check-blocker.mts";
|
|
18
|
+
export type { JournalResult } from "./commands/journal/index.mts";
|
|
19
|
+
export type { ResolveResult } from "./comments/resolve.mts";
|
|
20
|
+
export type { ShepherdJournalExtraction } from "./journal/index.mts";
|
|
12
21
|
import { type ShepherdJournalExtraction } from "./journal/index.mts";
|
|
13
22
|
export interface CreatePrShepherdOptions {
|
|
14
23
|
/** GitHub transport retained for this client; individual calls may override it. */
|
|
@@ -22,18 +31,17 @@ type IterateOptions = Omit<IterateCommandOptions, "format" | "prNumber" | "targe
|
|
|
22
31
|
export type SingleIterateInput = IterateOptions & {
|
|
23
32
|
pr?: PrReference;
|
|
24
33
|
prs?: never;
|
|
25
|
-
stack?: never;
|
|
26
34
|
};
|
|
27
|
-
|
|
35
|
+
/** One aggregate tick over several PRs from one repository. */
|
|
36
|
+
export type MultiIterateInput = IterateOptions & {
|
|
28
37
|
prs: PrReference[];
|
|
29
38
|
pr?: never;
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
}
|
|
36
|
-
export type IterateInput = SingleIterateInput | AggregateIterateInput;
|
|
39
|
+
};
|
|
40
|
+
export type IterateInput = SingleIterateInput | MultiIterateInput;
|
|
41
|
+
/** One aggregate tick over the native stack containing `pr`. */
|
|
42
|
+
export type StackInput = IterateOptions & {
|
|
43
|
+
pr: PrReference;
|
|
44
|
+
};
|
|
37
45
|
export interface ReviewMutationsOperation {
|
|
38
46
|
type: "review_mutations";
|
|
39
47
|
resolveThreadIds?: string[];
|
|
@@ -63,6 +71,14 @@ export interface AcknowledgeQueueRemovalOperation {
|
|
|
63
71
|
queueCommitOid: string;
|
|
64
72
|
removedAtUnix: number;
|
|
65
73
|
}
|
|
74
|
+
export interface CheckBlockerOperation {
|
|
75
|
+
/** Record (`blockedBy`) or clear (`clear: true`) an external blocker for one failing check. */
|
|
76
|
+
type: "check_blocker";
|
|
77
|
+
check: string;
|
|
78
|
+
/** PR/issue URL, `owner/repo#N`, or `issue:owner/repo#N`. */
|
|
79
|
+
blockedBy?: string;
|
|
80
|
+
clear?: boolean;
|
|
81
|
+
}
|
|
66
82
|
export interface MergeOperation {
|
|
67
83
|
type: "merge";
|
|
68
84
|
requireSha: string;
|
|
@@ -71,7 +87,7 @@ export interface MergeOperation {
|
|
|
71
87
|
expectedStack?: RestMergeStackGuard;
|
|
72
88
|
}
|
|
73
89
|
/** Operations run in this exact list order after validation. */
|
|
74
|
-
export type ApplyOperation = MergeOperation | ReviewMutationsOperation | MarkFilesViewedOperation | AppendJournalOperation | AcknowledgeQueueRemovalOperation;
|
|
90
|
+
export type ApplyOperation = MergeOperation | ReviewMutationsOperation | MarkFilesViewedOperation | AppendJournalOperation | AcknowledgeQueueRemovalOperation | CheckBlockerOperation;
|
|
75
91
|
export interface ApplyInput {
|
|
76
92
|
transport?: GithubTransport;
|
|
77
93
|
/** PR shared by every operation in this ordered apply request. */
|
|
@@ -93,23 +109,19 @@ export type ApplyOperationResult = {
|
|
|
93
109
|
} | {
|
|
94
110
|
type: "acknowledge_queue_removal";
|
|
95
111
|
result: ApplyQueueRemovalResult;
|
|
112
|
+
} | {
|
|
113
|
+
type: "check_blocker";
|
|
114
|
+
result: CheckBlockerCommandResult;
|
|
96
115
|
};
|
|
97
116
|
export interface ApplyResult {
|
|
98
117
|
operations: ApplyOperationResult[];
|
|
99
118
|
}
|
|
100
|
-
export interface BuildSuggestionPatchInput {
|
|
101
|
-
transport?: GithubTransport;
|
|
102
|
-
pr?: PrReference;
|
|
103
|
-
threadId: string;
|
|
104
|
-
message: string;
|
|
105
|
-
description?: string;
|
|
106
|
-
}
|
|
107
119
|
export interface SuggestionPatchInput {
|
|
108
120
|
threadId: string;
|
|
109
121
|
message: string;
|
|
110
122
|
description?: string;
|
|
111
123
|
}
|
|
112
|
-
export interface
|
|
124
|
+
export interface SuggestInput {
|
|
113
125
|
transport?: GithubTransport;
|
|
114
126
|
pr?: PrReference;
|
|
115
127
|
suggestions: SuggestionPatchInput[];
|
|
@@ -120,13 +132,12 @@ export interface GetJournalInput {
|
|
|
120
132
|
}
|
|
121
133
|
export interface PrShepherd {
|
|
122
134
|
iterate(input?: SingleIterateInput): Promise<IterateResult>;
|
|
123
|
-
iterate(input:
|
|
135
|
+
iterate(input: MultiIterateInput): Promise<PollSummaryResult>;
|
|
124
136
|
iterate(input: IterateInput): Promise<IterateResult | PollSummaryResult>;
|
|
137
|
+
stack(input: StackInput): Promise<PollSummaryResult>;
|
|
125
138
|
apply(input: ApplyInput): Promise<ApplyResult>;
|
|
126
|
-
|
|
139
|
+
suggest(input: SuggestInput): Promise<SuggestResult>;
|
|
127
140
|
getJournal(input: GetJournalInput): Promise<ShepherdJournalExtraction>;
|
|
128
|
-
/** Compatibility adapter; prefer buildSuggestionPatches. */
|
|
129
|
-
buildSuggestionPatch(input: BuildSuggestionPatchInput): Promise<CommitSuggestionResult>;
|
|
130
141
|
}
|
|
131
142
|
/** Raised before any API mutation when an input cannot be validated. */
|
|
132
143
|
export declare class PrShepherdValidationError extends Error {
|
|
@@ -140,6 +151,6 @@ export declare class PartialApplyError extends Error {
|
|
|
140
151
|
}
|
|
141
152
|
/**
|
|
142
153
|
* Creates the programmatic API. The returned object intentionally exposes only
|
|
143
|
-
* read/plan, ordered apply, and suggestion-patch operations.
|
|
154
|
+
* read/plan (`iterate`, `stack`), ordered apply, and suggestion-patch (`suggest`) operations.
|
|
144
155
|
*/
|
|
145
156
|
export declare function createPrShepherd(options?: CreatePrShepherdOptions): PrShepherd;
|
package/bin/api.mjs
CHANGED
|
@@ -2,15 +2,17 @@
|
|
|
2
2
|
import { resolve } from "node:path";
|
|
3
3
|
import { createGithubTransportRunner } from "./github/transport.mjs";
|
|
4
4
|
import { runApplyMerge, validateApplyMergeOptions, } from "./commands/apply-merge.mjs";
|
|
5
|
-
import { runCommitSuggestion } from "./commands/commit-suggestion.mjs";
|
|
6
5
|
import { runSuggestionPatches } from "./commands/suggestion-patches.mjs";
|
|
7
|
-
import {
|
|
6
|
+
import { runIterateTick, runPollSummaryTick } from "./commands/tick.mjs";
|
|
7
|
+
import { applyCheckBlocker, } from "./commands/apply-check-blocker.mjs";
|
|
8
|
+
import { parseBlockedByRef } from "./commands/check-blocker-ref.mjs";
|
|
8
9
|
import { runJournal } from "./commands/journal/index.mjs";
|
|
9
10
|
import { validateJournalItem } from "./commands/journal/transform.mjs";
|
|
10
11
|
import { runMarkFilesAsViewed, } from "./commands/mark-files-as-viewed.mjs";
|
|
11
12
|
import { runResolveMutate } from "./commands/resolve-mutate.mjs";
|
|
12
13
|
import { applyQueueRemovalAck, } from "./commands/apply-queue-removal.mjs";
|
|
13
14
|
import { runWithExecutionCwd } from "./execution-context.mjs";
|
|
15
|
+
import { loadConfig } from "./config/load.mjs";
|
|
14
16
|
import { parsePrReference, normalizeRepositoryIdentity, resolveParsedPrTarget, } from "./pr-reference.mjs";
|
|
15
17
|
import { getPullRequestBody, getRepoInfo } from "./github/client.mjs";
|
|
16
18
|
import { getLocalHeadSha } from "./commands/suggestion-patch-git.mjs";
|
|
@@ -36,28 +38,49 @@ export class PartialApplyError extends Error {
|
|
|
36
38
|
}
|
|
37
39
|
/**
|
|
38
40
|
* Creates the programmatic API. The returned object intentionally exposes only
|
|
39
|
-
* read/plan, ordered apply, and suggestion-patch operations.
|
|
41
|
+
* read/plan (`iterate`, `stack`), ordered apply, and suggestion-patch (`suggest`) operations.
|
|
40
42
|
*/
|
|
41
43
|
export function createPrShepherd(options = {}) {
|
|
42
44
|
const cwd = options.cwd === undefined ? undefined : resolve(options.cwd);
|
|
43
45
|
const transportRunner = createGithubTransportRunner(options.transport);
|
|
44
46
|
function runInClient(input, work) {
|
|
45
|
-
|
|
47
|
+
// Validate config first, as the CLI does, so a bad or pre-v1 file rejects before GitHub I/O.
|
|
48
|
+
return runWithExecutionCwd(cwd, async () => {
|
|
49
|
+
loadConfig();
|
|
50
|
+
return transportRunner(work, input?.transport);
|
|
51
|
+
});
|
|
46
52
|
}
|
|
47
53
|
function iterate(input = {}) {
|
|
48
54
|
return runInClient(input, async () => {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
55
|
+
if ("pr" in input && "prs" in input) {
|
|
56
|
+
throw new PrShepherdValidationError("iterate pr and prs selectors are mutually exclusive");
|
|
57
|
+
}
|
|
58
|
+
if ("prs" in input) {
|
|
59
|
+
const { prs, pr: _pr, ...options } = input;
|
|
60
|
+
const { numbers, repository } = await resolveSameRepositoryRefs(prs, "iterate.prs");
|
|
61
|
+
return runPollSummaryTick({ ...options, prNumbers: numbers, targetRepository: repository });
|
|
53
62
|
}
|
|
54
|
-
const { pr: _pr, ...iterateOptions } = input;
|
|
63
|
+
const { pr: _pr, prs: _prs, ...iterateOptions } = input;
|
|
55
64
|
const target = resolvePrReference(input.pr);
|
|
56
|
-
return
|
|
65
|
+
return runIterateTick({ ...iterateOptions, ...target, format: "json" });
|
|
57
66
|
});
|
|
58
67
|
}
|
|
59
68
|
return Object.freeze({
|
|
60
69
|
iterate,
|
|
70
|
+
stack(input) {
|
|
71
|
+
return runInClient(input ?? {}, async () => {
|
|
72
|
+
if (!input || input.pr === undefined) {
|
|
73
|
+
throw new PrShepherdValidationError("stack requires a PR reference");
|
|
74
|
+
}
|
|
75
|
+
const { pr, ...options } = input;
|
|
76
|
+
const { numbers, repository } = await resolveSameRepositoryRefs([pr], "stack.pr");
|
|
77
|
+
return runPollSummaryTick({
|
|
78
|
+
...options,
|
|
79
|
+
stackPrNumber: numbers[0],
|
|
80
|
+
targetRepository: repository,
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
},
|
|
61
84
|
getJournal(input) {
|
|
62
85
|
return runInClient(input, async () => {
|
|
63
86
|
const { prNumber, targetRepository } = resolvePrReference(input.pr);
|
|
@@ -127,6 +150,18 @@ export function createPrShepherd(options = {}) {
|
|
|
127
150
|
results.push({ type: operation.type, result });
|
|
128
151
|
break;
|
|
129
152
|
}
|
|
153
|
+
case "check_blocker": {
|
|
154
|
+
const result = await applyCheckBlocker({
|
|
155
|
+
prNumber,
|
|
156
|
+
targetRepository,
|
|
157
|
+
checkName: operation.check,
|
|
158
|
+
...(operation.clear
|
|
159
|
+
? { clear: true }
|
|
160
|
+
: { blocker: parseBlockedByRef(operation.blockedBy) }),
|
|
161
|
+
});
|
|
162
|
+
results.push({ type: operation.type, result });
|
|
163
|
+
break;
|
|
164
|
+
}
|
|
130
165
|
case "acknowledge_queue_removal": {
|
|
131
166
|
const result = await applyQueueRemovalAck({
|
|
132
167
|
prNumber,
|
|
@@ -149,16 +184,8 @@ export function createPrShepherd(options = {}) {
|
|
|
149
184
|
return { operations: results };
|
|
150
185
|
});
|
|
151
186
|
},
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
const { pr: _pr, ...options } = input;
|
|
155
|
-
return runInClient(input, async () => {
|
|
156
|
-
const target = resolvePrReference(input.pr);
|
|
157
|
-
return runCommitSuggestion({ ...options, ...target, format: "json" });
|
|
158
|
-
});
|
|
159
|
-
},
|
|
160
|
-
buildSuggestionPatches(input) {
|
|
161
|
-
validateSuggestionPatchesInput(input);
|
|
187
|
+
suggest(input) {
|
|
188
|
+
validateSuggestInput(input);
|
|
162
189
|
const { pr: _pr, ...options } = input;
|
|
163
190
|
return runInClient(input, async () => {
|
|
164
191
|
const target = resolvePrReference(input.pr);
|
|
@@ -167,10 +194,9 @@ export function createPrShepherd(options = {}) {
|
|
|
167
194
|
},
|
|
168
195
|
});
|
|
169
196
|
}
|
|
170
|
-
async function
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
throw new PrShepherdValidationError("iterate.prs must contain at least one PR reference");
|
|
197
|
+
async function resolveSameRepositoryRefs(refs, label) {
|
|
198
|
+
if (!Array.isArray(refs) || refs.length === 0) {
|
|
199
|
+
throw new PrShepherdValidationError(`${label} must contain at least one PR reference`);
|
|
174
200
|
}
|
|
175
201
|
const parsedRefs = refs.map((ref) => {
|
|
176
202
|
const parsed = parsePrReference(ref);
|
|
@@ -197,16 +223,7 @@ async function resolveAggregateIterateInput(input) {
|
|
|
197
223
|
if (!numbers.includes(prNumber))
|
|
198
224
|
numbers.push(prNumber);
|
|
199
225
|
}
|
|
200
|
-
|
|
201
|
-
return "prs" in input
|
|
202
|
-
? { ...options, prNumbers: numbers, targetRepository: repository }
|
|
203
|
-
: { ...options, stackPrNumber: numbers[0], targetRepository: repository };
|
|
204
|
-
}
|
|
205
|
-
function validateIterateSelectors(input) {
|
|
206
|
-
const selectorCount = ["pr", "prs", "stack"].filter((key) => key in input).length;
|
|
207
|
-
if (selectorCount > 1) {
|
|
208
|
-
throw new PrShepherdValidationError("iterate pr, prs, and stack selectors are mutually exclusive");
|
|
209
|
-
}
|
|
226
|
+
return { numbers, repository: repository };
|
|
210
227
|
}
|
|
211
228
|
function validateApplyInput(input) {
|
|
212
229
|
if (!input || !Array.isArray(input.operations) || input.operations.length === 0) {
|
|
@@ -254,6 +271,21 @@ function validateOperation(operation) {
|
|
|
254
271
|
throw new PrShepherdValidationError(validation.error);
|
|
255
272
|
}
|
|
256
273
|
return;
|
|
274
|
+
case "check_blocker":
|
|
275
|
+
if (typeof operation.check !== "string" || operation.check === "") {
|
|
276
|
+
throw new PrShepherdValidationError("check_blocker.check must be the exact check name");
|
|
277
|
+
}
|
|
278
|
+
if (operation.clear !== undefined && typeof operation.clear !== "boolean") {
|
|
279
|
+
throw new PrShepherdValidationError("check_blocker.clear must be a boolean");
|
|
280
|
+
}
|
|
281
|
+
if (operation.clear === true && operation.blockedBy !== undefined) {
|
|
282
|
+
throw new PrShepherdValidationError("check_blocker takes either blockedBy or clear, not both");
|
|
283
|
+
}
|
|
284
|
+
if (operation.clear !== true &&
|
|
285
|
+
(typeof operation.blockedBy !== "string" || !parseBlockedByRef(operation.blockedBy))) {
|
|
286
|
+
throw new PrShepherdValidationError("check_blocker.blockedBy must be a PR/issue URL, owner/repo#N, or issue:owner/repo#N");
|
|
287
|
+
}
|
|
288
|
+
return;
|
|
257
289
|
case "acknowledge_queue_removal":
|
|
258
290
|
if (typeof operation.requireSha !== "string" ||
|
|
259
291
|
!/^[0-9a-f]{40}$/.test(operation.requireSha)) {
|
|
@@ -317,21 +349,9 @@ function validateMarkFilesViewed(operation) {
|
|
|
317
349
|
}
|
|
318
350
|
}
|
|
319
351
|
}
|
|
320
|
-
function
|
|
321
|
-
if (!input || typeof input.threadId !== "string" || input.threadId.trim() === "") {
|
|
322
|
-
throw new PrShepherdValidationError("buildSuggestionPatch.threadId is required");
|
|
323
|
-
}
|
|
324
|
-
if (typeof input.message !== "string" || input.message.trim() === "") {
|
|
325
|
-
throw new PrShepherdValidationError("buildSuggestionPatch.message is required and must be non-empty");
|
|
326
|
-
}
|
|
327
|
-
if (input.description !== undefined && typeof input.description !== "string") {
|
|
328
|
-
throw new PrShepherdValidationError("buildSuggestionPatch.description must be a string");
|
|
329
|
-
}
|
|
330
|
-
validatePrReference(input.pr);
|
|
331
|
-
}
|
|
332
|
-
function validateSuggestionPatchesInput(input) {
|
|
352
|
+
function validateSuggestInput(input) {
|
|
333
353
|
if (!input || !Array.isArray(input.suggestions) || input.suggestions.length === 0) {
|
|
334
|
-
throw new PrShepherdValidationError("
|
|
354
|
+
throw new PrShepherdValidationError("suggest.suggestions must be a non-empty array");
|
|
335
355
|
}
|
|
336
356
|
const seen = new Set();
|
|
337
357
|
for (const suggestion of input.suggestions) {
|
|
@@ -34,7 +34,7 @@ export interface CiVerdict {
|
|
|
34
34
|
anyFailing: boolean;
|
|
35
35
|
/** Names of checks that were filtered out (triggered by non-PR events). */
|
|
36
36
|
filteredNames: string[];
|
|
37
|
-
/** Names of checks suppressed by the user's
|
|
37
|
+
/** Names of checks suppressed by the user's checks.ignore config. */
|
|
38
38
|
ignoredNames: string[];
|
|
39
39
|
/** Names of CANCELLED checks covered by another run of the same workflow and event. */
|
|
40
40
|
supersededNames: string[];
|
package/bin/checks/classify.mjs
CHANGED
|
@@ -24,11 +24,11 @@ import picomatch from "picomatch";
|
|
|
24
24
|
export function classifyChecks(checks, opts = {}) {
|
|
25
25
|
const config = loadConfig();
|
|
26
26
|
const relevantEvents = new Set([
|
|
27
|
-
...config.checks
|
|
27
|
+
...config.checks["ci-trigger-events"],
|
|
28
28
|
...(opts.additionalRelevantEvents ?? []),
|
|
29
29
|
]);
|
|
30
|
-
const isIgnored = buildMatcher(config.
|
|
31
|
-
const isProtected = buildMatcher(config.
|
|
30
|
+
const isIgnored = buildMatcher(config.checks.ignore ?? []);
|
|
31
|
+
const isProtected = buildMatcher(config.checks["never-ignore"] ?? []);
|
|
32
32
|
const protectedRunIds = buildProtectedRunIds(checks, isProtected);
|
|
33
33
|
const supersededIndices = buildSupersededIndices(checks, opts.requiredContexts);
|
|
34
34
|
return checks.map((c, index) => {
|
|
@@ -69,7 +69,7 @@ function checkMatchesProtection(check, isProtected) {
|
|
|
69
69
|
}
|
|
70
70
|
function classify(check, relevantEvents) {
|
|
71
71
|
// Filter: runs from non-PR events don't count toward PR readiness.
|
|
72
|
-
// event === null means a commit StatusContext — these are always relevant regardless of
|
|
72
|
+
// event === null means a commit StatusContext — these are always relevant regardless of checks.ci-trigger-events.
|
|
73
73
|
if (check.event !== null && !relevantEvents.has(check.event)) {
|
|
74
74
|
return { ...check, category: "filtered" };
|
|
75
75
|
}
|
|
@@ -175,7 +175,7 @@ function truncateTail(text, keep) {
|
|
|
175
175
|
return from === -1 ? tail : truncateLogExcerpt(`${head}${text.slice(from)}`);
|
|
176
176
|
}
|
|
177
177
|
function compileIgnoreLogLinePatterns() {
|
|
178
|
-
return loadConfig().checks.
|
|
178
|
+
return loadConfig().checks["ignore-log-lines"].map((pattern) => new RegExp(pattern));
|
|
179
179
|
}
|
|
180
180
|
function isNoiseLine(line, patterns) {
|
|
181
181
|
return patterns.some((re) => re.test(line));
|
package/bin/cli/arg-flags.mjs
CHANGED
|
@@ -8,13 +8,11 @@ export const FLAGS_WITH_VALUES = new Set([
|
|
|
8
8
|
"--ready-delay",
|
|
9
9
|
"--stall-timeout",
|
|
10
10
|
"--instructions",
|
|
11
|
-
"--poll-mode",
|
|
12
11
|
"--require-sha",
|
|
13
12
|
"--message",
|
|
14
13
|
"--description",
|
|
15
14
|
"--body-file",
|
|
16
15
|
"--file",
|
|
17
|
-
"--stack",
|
|
18
16
|
"--thread-id",
|
|
19
17
|
"--resolve-thread-ids",
|
|
20
18
|
"--reply-thread-ids",
|
|
@@ -35,7 +33,6 @@ export const FLAGS_WITH_VALUES = new Set([
|
|
|
35
33
|
// numeric value to be misidentified as the PR number.
|
|
36
34
|
export const BOOLEAN_FLAGS = new Set([
|
|
37
35
|
"--no-auto-mark-ready",
|
|
38
|
-
"--no-auto-cancel-actionable",
|
|
39
36
|
"--quiet-status",
|
|
40
37
|
"--no-quiet-status",
|
|
41
38
|
"--until-terminal",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare function handleClean(args: string[]
|
|
1
|
+
export declare function handleClean(args: string[]): Promise<void>;
|
|
@@ -2,10 +2,10 @@ import { runClean } from "../commands/clean.mjs";
|
|
|
2
2
|
import { EXIT } from "../exit-codes.mjs";
|
|
3
3
|
import { USAGE } from "./help.mjs";
|
|
4
4
|
import { formatCleanResult } from "./formatters.mjs";
|
|
5
|
-
import { rejectInvalidPollModeFlag, runInPollModeScope } from "./event-state-scope.mjs";
|
|
6
5
|
const CLEAN_VARIANTS = new Set(["pr", "branch", "current", "repo", "all"]);
|
|
7
|
-
export async function handleClean(args
|
|
8
|
-
const
|
|
6
|
+
export async function handleClean(args) {
|
|
7
|
+
const command = "admin clean";
|
|
8
|
+
const usage = USAGE["admin clean"];
|
|
9
9
|
const variant = args[0];
|
|
10
10
|
if (!variant || !CLEAN_VARIANTS.has(variant)) {
|
|
11
11
|
process.stderr.write(`${usage}\n`);
|
|
@@ -18,8 +18,6 @@ export async function handleClean(args, command = "admin clean") {
|
|
|
18
18
|
continue;
|
|
19
19
|
if (a === "--dry-run" || a === "--format" || a.startsWith("--format="))
|
|
20
20
|
continue;
|
|
21
|
-
if (a === "--poll-mode" || a.startsWith("--poll-mode="))
|
|
22
|
-
continue;
|
|
23
21
|
process.stderr.write(`pr-shepherd: ${command}: unknown flag: "${a}"\n`);
|
|
24
22
|
process.exitCode = EXIT.USAGE;
|
|
25
23
|
return;
|
|
@@ -38,21 +36,14 @@ export async function handleClean(args, command = "admin clean") {
|
|
|
38
36
|
process.exitCode = EXIT.USAGE;
|
|
39
37
|
return;
|
|
40
38
|
}
|
|
41
|
-
if (rejectInvalidPollModeFlag(rest, command))
|
|
42
|
-
return;
|
|
43
39
|
const jsonOut = formatValue === "json";
|
|
44
40
|
const dryRun = rest.includes("--dry-run");
|
|
45
|
-
// Skip values consumed by --format <value>
|
|
41
|
+
// Skip values consumed by --format <value> so they aren't positionals.
|
|
46
42
|
const flagConsumedIndices = new Set();
|
|
47
43
|
if (fmtIdx !== -1 && fmtIdx + 1 < rest.length && !rest[fmtIdx + 1].startsWith("--")) {
|
|
48
44
|
flagConsumedIndices.add(fmtIdx);
|
|
49
45
|
flagConsumedIndices.add(fmtIdx + 1);
|
|
50
46
|
}
|
|
51
|
-
const pollModeIdx = rest.indexOf("--poll-mode");
|
|
52
|
-
if (pollModeIdx !== -1) {
|
|
53
|
-
flagConsumedIndices.add(pollModeIdx);
|
|
54
|
-
flagConsumedIndices.add(pollModeIdx + 1);
|
|
55
|
-
}
|
|
56
47
|
const positionals = rest.filter((a, i) => !flagConsumedIndices.has(i) && !a.startsWith("--"));
|
|
57
48
|
if (positionals.length > 1) {
|
|
58
49
|
process.stderr.write(`pr-shepherd: ${command}: too many positional arguments (expected at most 1, got ${positionals.length})\n`);
|
|
@@ -60,8 +51,7 @@ export async function handleClean(args, command = "admin clean") {
|
|
|
60
51
|
return;
|
|
61
52
|
}
|
|
62
53
|
const value = positionals[0];
|
|
63
|
-
|
|
64
|
-
const result = await runInPollModeScope(rest, () => runClean({ variant: variant, value, dryRun }));
|
|
54
|
+
const result = await runClean({ variant: variant, value, dryRun });
|
|
65
55
|
if (!result.ok) {
|
|
66
56
|
process.stderr.write(`pr-shepherd: ${command}: ${result.error}\n`);
|
|
67
57
|
process.exitCode = EXIT.SOFTWARE;
|
|
@@ -1,2 +1,4 @@
|
|
|
1
|
+
export declare const DEFAULT_POLL_FLAGS_WITH_VALUES: Set<string>;
|
|
2
|
+
export declare const DEFAULT_POLL_BOOLEAN_FLAGS: Set<string>;
|
|
1
3
|
export declare function isDefaultPollInvocation(subcommand: string | undefined): boolean;
|
|
2
4
|
export declare function validateDefaultPollArgs(args: string[]): boolean;
|
package/bin/cli/default-poll.mjs
CHANGED
|
@@ -2,22 +2,20 @@ import { EXIT } from "../exit-codes.mjs";
|
|
|
2
2
|
import { parsePrNumber } from "./args.mjs";
|
|
3
3
|
import { validateDefaultArgs } from "./validate-default-args.mjs";
|
|
4
4
|
import { USAGE } from "./help.mjs";
|
|
5
|
-
|
|
5
|
+
import { isRemovedFlag, rejectRemovedFlags } from "./removed-flags.mjs";
|
|
6
|
+
export const DEFAULT_POLL_FLAGS_WITH_VALUES = new Set([
|
|
6
7
|
"--transport",
|
|
7
8
|
"--format",
|
|
8
9
|
"--ready-delay",
|
|
9
10
|
"--stall-timeout",
|
|
10
11
|
"--instructions",
|
|
11
|
-
"--poll-mode",
|
|
12
12
|
"--interval",
|
|
13
13
|
"--timeout",
|
|
14
14
|
"--debounce",
|
|
15
|
-
"--stack",
|
|
16
15
|
]);
|
|
17
|
-
const DEFAULT_POLL_BOOLEAN_FLAGS = new Set([
|
|
16
|
+
export const DEFAULT_POLL_BOOLEAN_FLAGS = new Set([
|
|
18
17
|
"--verbose",
|
|
19
18
|
"--no-auto-mark-ready",
|
|
20
|
-
"--no-auto-cancel-actionable",
|
|
21
19
|
"--quiet-status",
|
|
22
20
|
"--no-quiet-status",
|
|
23
21
|
"--until-terminal",
|
|
@@ -29,11 +27,16 @@ export function isDefaultPollInvocation(subcommand) {
|
|
|
29
27
|
return (subcommand === undefined || parsePrNumber(subcommand) !== null || isDefaultPollFlag(subcommand));
|
|
30
28
|
}
|
|
31
29
|
export function validateDefaultPollArgs(args) {
|
|
30
|
+
if (rejectRemovedFlags(args))
|
|
31
|
+
return false;
|
|
32
32
|
return validateDefaultArgs(args, DEFAULT_POLL_FLAGS_WITH_VALUES, DEFAULT_POLL_BOOLEAN_FLAGS, writeDefaultUsageError);
|
|
33
33
|
}
|
|
34
34
|
function isDefaultPollFlag(arg) {
|
|
35
35
|
const name = arg.split("=", 1)[0];
|
|
36
|
-
|
|
36
|
+
// A removed flag routes here so its usage error names the replacement.
|
|
37
|
+
return (DEFAULT_POLL_FLAGS_WITH_VALUES.has(name) ||
|
|
38
|
+
DEFAULT_POLL_BOOLEAN_FLAGS.has(arg) ||
|
|
39
|
+
isRemovedFlag(arg));
|
|
37
40
|
}
|
|
38
41
|
function writeDefaultUsageError(arg) {
|
|
39
42
|
process.stderr.write(`Unknown subcommand: ${arg}\n`);
|
package/bin/cli/formatters.d.mts
CHANGED
|
@@ -3,6 +3,5 @@ export { projectIterateLean, projectIterateVerbose } from "./iterate-lean.mts";
|
|
|
3
3
|
export { formatCleanResult } from "./clean-formatter.mts";
|
|
4
4
|
export { formatMarkFilesAsViewedResult } from "./mark-files-as-viewed-formatter.mts";
|
|
5
5
|
export { formatMutateResult } from "./mutate-formatter.mts";
|
|
6
|
-
import type {
|
|
7
|
-
export declare function formatSuggestionPatchesResult(result:
|
|
8
|
-
export declare function formatCommitSuggestionResult(result: CommitSuggestionResult): string;
|
|
6
|
+
import type { SuggestResult } from "../types.mts";
|
|
7
|
+
export declare function formatSuggestionPatchesResult(result: SuggestResult): string;
|
package/bin/cli/formatters.mjs
CHANGED
|
@@ -12,32 +12,6 @@ export function formatSuggestionPatchesResult(result) {
|
|
|
12
12
|
appendInstructions(lines, result.postActionInstructions);
|
|
13
13
|
return lines.join("\n");
|
|
14
14
|
}
|
|
15
|
-
export function formatCommitSuggestionResult(result) {
|
|
16
|
-
const lines = [];
|
|
17
|
-
const range = result.startLine === result.endLine
|
|
18
|
-
? `line ${result.startLine}`
|
|
19
|
-
: `lines ${result.startLine}–${result.endLine}`;
|
|
20
|
-
lines.push(`Suggestion from @${result.author} for PR #${result.pr} — thread ${result.threadId}:`);
|
|
21
|
-
lines.push(` repo: ${result.repo}`);
|
|
22
|
-
lines.push(` ${result.path} (${range})`);
|
|
23
|
-
if (result.patch) {
|
|
24
|
-
const fence = safeFence(result.patch);
|
|
25
|
-
lines.push("");
|
|
26
|
-
lines.push(`${fence}diff`);
|
|
27
|
-
lines.push(result.patch.trimEnd());
|
|
28
|
-
lines.push(fence);
|
|
29
|
-
}
|
|
30
|
-
lines.push("", "## Suggested commit message", "", result.commitMessage, "", result.commitBody);
|
|
31
|
-
if (result.postActionInstructions.length > 0) {
|
|
32
|
-
lines.push("");
|
|
33
|
-
lines.push("## Instructions");
|
|
34
|
-
lines.push("");
|
|
35
|
-
result.postActionInstructions.forEach((inst, i) => {
|
|
36
|
-
lines.push(`${i + 1}. ${inst}`);
|
|
37
|
-
});
|
|
38
|
-
}
|
|
39
|
-
return lines.join("\n");
|
|
40
|
-
}
|
|
41
15
|
function formatPatch(patch, heading) {
|
|
42
16
|
const range = patch.startLine === patch.endLine
|
|
43
17
|
? `line ${patch.startLine}`
|
package/bin/cli/handlers.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export declare function
|
|
2
|
-
|
|
1
|
+
export declare function handleSuggest(args: string[]): Promise<void>;
|
|
2
|
+
/** `iterate [PR...]`: one tick for one PR, or one aggregate tick for several. */
|
|
3
3
|
export declare function handleIterate(args: string[]): Promise<void>;
|
|
4
|
-
export declare function handleMarkFilesAsViewed(args: string[]
|
|
4
|
+
export declare function handleMarkFilesAsViewed(args: string[]): Promise<void>;
|