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/bin/cli/poll-targets.mjs
CHANGED
|
@@ -2,18 +2,20 @@ import { parseArgs } from "node:util";
|
|
|
2
2
|
import { EXIT, ShepherdError } from "../exit-codes.mjs";
|
|
3
3
|
import { getRepoInfo } from "../github/client.mjs";
|
|
4
4
|
import { parseCliPrReference, normalizeRepositoryIdentity, resolveParsedPrTarget, } from "../pr-reference.mjs";
|
|
5
|
+
import { rejectRemovedFlags } from "./removed-flags.mjs";
|
|
5
6
|
const VALUE_FLAGS = new Set([
|
|
6
7
|
"--format",
|
|
7
8
|
"--ready-delay",
|
|
8
9
|
"--stall-timeout",
|
|
9
10
|
"--instructions",
|
|
10
|
-
"--poll-mode",
|
|
11
11
|
"--interval",
|
|
12
12
|
"--timeout",
|
|
13
13
|
"--debounce",
|
|
14
|
-
"--stack",
|
|
15
14
|
]);
|
|
15
|
+
/** Splits PR references from flags. Returns null after printing a usage error. */
|
|
16
16
|
export function parsePollTargets(args) {
|
|
17
|
+
if (rejectRemovedFlags(args))
|
|
18
|
+
return null;
|
|
17
19
|
const { values } = parseArgs({
|
|
18
20
|
args,
|
|
19
21
|
strict: false,
|
|
@@ -22,39 +24,22 @@ export function parsePollTargets(args) {
|
|
|
22
24
|
});
|
|
23
25
|
const consumed = new Set();
|
|
24
26
|
const refs = [];
|
|
25
|
-
let stack;
|
|
26
27
|
for (let index = 0; index < args.length; index += 1) {
|
|
27
28
|
const arg = args[index];
|
|
28
29
|
if (VALUE_FLAGS.has(arg)) {
|
|
29
|
-
if (arg === "--format"
|
|
30
|
+
if (arg === "--format") {
|
|
30
31
|
consumed.add(index);
|
|
31
32
|
if (index + 1 < args.length)
|
|
32
33
|
consumed.add(index + 1);
|
|
33
34
|
}
|
|
34
|
-
if (arg === "--stack") {
|
|
35
|
-
const parsed = parseCliPrReference(args[index + 1] ?? "");
|
|
36
|
-
if (!parsed)
|
|
37
|
-
return usage(`invalid --stack PR reference: ${args[index + 1] ?? "(missing)"}`);
|
|
38
|
-
if (stack)
|
|
39
|
-
return usage("--stack may only be specified once");
|
|
40
|
-
stack = parsed;
|
|
41
|
-
}
|
|
42
35
|
index += 1;
|
|
43
36
|
continue;
|
|
44
37
|
}
|
|
45
38
|
const equals = arg.indexOf("=");
|
|
46
39
|
const name = equals < 0 ? arg : arg.slice(0, equals);
|
|
47
40
|
if (VALUE_FLAGS.has(name)) {
|
|
48
|
-
if (name === "--format"
|
|
41
|
+
if (name === "--format")
|
|
49
42
|
consumed.add(index);
|
|
50
|
-
if (name === "--stack") {
|
|
51
|
-
const parsed = parseCliPrReference(arg.slice(equals + 1));
|
|
52
|
-
if (!parsed)
|
|
53
|
-
return usage(`invalid --stack PR reference: ${arg.slice(equals + 1)}`);
|
|
54
|
-
if (stack)
|
|
55
|
-
return usage("--stack may only be specified once");
|
|
56
|
-
stack = parsed;
|
|
57
|
-
}
|
|
58
43
|
continue;
|
|
59
44
|
}
|
|
60
45
|
if (arg === "--verbose") {
|
|
@@ -64,23 +49,25 @@ export function parsePollTargets(args) {
|
|
|
64
49
|
if (arg.startsWith("--"))
|
|
65
50
|
continue;
|
|
66
51
|
const parsed = parseCliPrReference(arg);
|
|
67
|
-
if (!parsed)
|
|
68
|
-
|
|
52
|
+
if (!parsed) {
|
|
53
|
+
// A typo must not silently drop a PR from an exact multi-PR selection.
|
|
54
|
+
process.stderr.write(`pr-shepherd: invalid PR reference "${arg}".\n`);
|
|
55
|
+
process.exitCode = EXIT.USAGE;
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
69
58
|
refs.push(parsed);
|
|
70
59
|
consumed.add(index);
|
|
71
60
|
}
|
|
72
|
-
if (stack && refs.length > 0)
|
|
73
|
-
return usage("--stack cannot be combined with explicit PRs");
|
|
74
61
|
const format = (values.format ?? "text");
|
|
75
62
|
return {
|
|
76
63
|
refs,
|
|
77
|
-
stack,
|
|
78
64
|
global: { format, verbose: values.verbose === true },
|
|
79
65
|
extra: args.filter((_, index) => !consumed.has(index)),
|
|
80
66
|
};
|
|
81
67
|
}
|
|
68
|
+
/** Resolves PR references that must all name one repository. */
|
|
82
69
|
export async function resolvePollTargets(parsed) {
|
|
83
|
-
const all = parsed.
|
|
70
|
+
const all = parsed.refs;
|
|
84
71
|
if (all.length === 0)
|
|
85
72
|
return { prNumbers: [] };
|
|
86
73
|
const checkoutRepo = all.some((ref) => ref.repository === undefined)
|
|
@@ -102,14 +89,7 @@ export async function resolvePollTargets(parsed) {
|
|
|
102
89
|
if (!prNumbers.includes(target.prNumber))
|
|
103
90
|
prNumbers.push(target.prNumber);
|
|
104
91
|
}
|
|
105
|
-
return
|
|
106
|
-
? { prNumbers: [], stackPrNumber: prNumbers[0], targetRepository: selectedRepo }
|
|
107
|
-
: { prNumbers, targetRepository: selectedRepo };
|
|
108
|
-
}
|
|
109
|
-
function usage(message) {
|
|
110
|
-
process.stderr.write(`pr-shepherd: ${message}\n`);
|
|
111
|
-
process.exitCode = EXIT.USAGE;
|
|
112
|
-
return null;
|
|
92
|
+
return { prNumbers, targetRepository: selectedRepo };
|
|
113
93
|
}
|
|
114
94
|
function usageThrow(message) {
|
|
115
95
|
throw new ShepherdError(message, EXIT.USAGE);
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { EXIT } from "../exit-codes.mjs";
|
|
2
|
+
/** Flags removed in v1, with the replacement each usage error names. */
|
|
3
|
+
const REMOVED_FLAGS = new Map([
|
|
4
|
+
["--stack", "`--stack` was removed; use `pr-shepherd stack <PR>`."],
|
|
5
|
+
[
|
|
6
|
+
"--poll-mode",
|
|
7
|
+
"`--poll-mode` was removed; `pr-shepherd iterate` runs one tick, and looping commands run one tick when CLAUDE_CODE_REMOTE=true.",
|
|
8
|
+
],
|
|
9
|
+
]);
|
|
10
|
+
export function isRemovedFlag(arg) {
|
|
11
|
+
return REMOVED_FLAGS.has(arg.split("=", 1)[0]);
|
|
12
|
+
}
|
|
13
|
+
/** Prints a usage error and returns true when `args` contains a removed flag. */
|
|
14
|
+
export function rejectRemovedFlags(args) {
|
|
15
|
+
for (const arg of args) {
|
|
16
|
+
const message = REMOVED_FLAGS.get(arg.split("=", 1)[0]);
|
|
17
|
+
if (message === undefined)
|
|
18
|
+
continue;
|
|
19
|
+
process.stderr.write(`pr-shepherd: ${message}\n`);
|
|
20
|
+
process.exitCode = EXIT.USAGE;
|
|
21
|
+
return true;
|
|
22
|
+
}
|
|
23
|
+
return false;
|
|
24
|
+
}
|
package/bin/cli/runner.d.mts
CHANGED
|
@@ -2,7 +2,7 @@ interface PrShepherdCommand {
|
|
|
2
2
|
argv: string[];
|
|
3
3
|
text: string;
|
|
4
4
|
}
|
|
5
|
-
/** Every emitted pr-shepherd command starts with the configured `
|
|
5
|
+
/** Every emitted pr-shepherd command starts with the configured `cli-command` launcher. */
|
|
6
6
|
export declare function buildPrShepherdCommand(args: string[]): PrShepherdCommand;
|
|
7
7
|
export declare function renderShellCommand(argv: string[]): string;
|
|
8
8
|
export {};
|
package/bin/cli/runner.mjs
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { loadConfig } from "../config/load.mjs";
|
|
2
2
|
import { getGithubTransport } from "../github/transport.mjs";
|
|
3
|
-
/** Every emitted pr-shepherd command starts with the configured `
|
|
3
|
+
/** Every emitted pr-shepherd command starts with the configured `cli-command` launcher. */
|
|
4
4
|
export function buildPrShepherdCommand(args) {
|
|
5
5
|
const transport = getGithubTransport() === "rest" &&
|
|
6
6
|
!args.some((arg) => arg === "--transport" || arg.startsWith("--transport="))
|
|
7
7
|
? ["--transport", "rest"]
|
|
8
8
|
: [];
|
|
9
|
-
const argv = [...loadConfig()
|
|
9
|
+
const argv = [...loadConfig()["cli-command"], ...args, ...transport];
|
|
10
10
|
return { argv, text: renderShellCommand(argv) };
|
|
11
11
|
}
|
|
12
12
|
export function renderShellCommand(argv) {
|
|
@@ -26,7 +26,6 @@ export function projectStackOverview(result) {
|
|
|
26
26
|
...(result.instructions?.length && { instructions: result.instructions }),
|
|
27
27
|
...(result.apiUsage && { apiUsage: result.apiUsage }),
|
|
28
28
|
...(result.quotaWarning && { quotaWarning: result.quotaWarning }),
|
|
29
|
-
...(result.pollMode && { pollMode: result.pollMode }),
|
|
30
29
|
...(result.nextCheck && { nextCheck: result.nextCheck }),
|
|
31
30
|
};
|
|
32
31
|
}
|
|
@@ -94,7 +93,7 @@ export function formatStackOverview(overview) {
|
|
|
94
93
|
const lines = [
|
|
95
94
|
`# ${overview.repo} stack #${stack.stackNumber}${stackTerminalTag(overview.nextAction)} — ${overview.reason}`,
|
|
96
95
|
"",
|
|
97
|
-
`anchor PR #${stack.anchor} · ${stack.stackSize} layers · mode \`${overview.mode}
|
|
96
|
+
`anchor PR #${stack.anchor} · ${stack.stackSize} layers · mode \`${overview.mode}\``,
|
|
98
97
|
...(overview.stackMergeable ? ["stackMergeable: true"] : []),
|
|
99
98
|
...(overview.nextAction ? [`nextAction: ${overview.nextAction}`] : []),
|
|
100
99
|
...formatNextCheckLines(overview.nextCheck),
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import type { CheckAnnotation
|
|
1
|
+
import type { CheckAnnotation } from "../types.mts";
|
|
2
2
|
/** Returns null when the annotation adds nothing beyond the check's own conclusion tag. */
|
|
3
3
|
export declare function renderCheckAnnotation(a: CheckAnnotation, logExcerpt?: string): string | null;
|
|
4
|
-
export declare function renderProtectedRun(run: IterateResultFixCode["fix"]["protectedRuns"][number]): string;
|
|
@@ -25,12 +25,6 @@ export function renderCheckAnnotation(a, logExcerpt) {
|
|
|
25
25
|
function duplicatesLog(text, logExcerpt) {
|
|
26
26
|
return logExcerpt !== undefined && logExcerpt.includes(text.trim());
|
|
27
27
|
}
|
|
28
|
-
export function renderProtectedRun(run) {
|
|
29
|
-
const label = run.workflowName
|
|
30
|
-
? `${run.workflowName} (${run.checkNames.join(", ")})`
|
|
31
|
-
: run.checkNames.join(", ");
|
|
32
|
-
return `- \`${run.runId}\` — \`${label}\` [matched: \`${run.matchedPattern}\`]`;
|
|
33
|
-
}
|
|
34
28
|
function renderAnnotationRange(a) {
|
|
35
29
|
if (a.startLine === null && a.endLine === null)
|
|
36
30
|
return "?";
|
|
@@ -4,17 +4,17 @@ import { renderSuggestionBlock, renderLineRange } from "./suggestion-renderer.mj
|
|
|
4
4
|
import { renderThreadBullet, renderReviewBullet, renderThreadResolutionStatusTag, renderAuthor, buildFirstLookBullets, renderThreadConversation, blockquote, } from "./list-formatters.mjs";
|
|
5
5
|
import { BODY_TRUNCATE_MAX_CHARS } from "./body-truncate.mjs";
|
|
6
6
|
import { numberInstructions } from "./iterate-instructions.mjs";
|
|
7
|
-
import { renderCheckAnnotation
|
|
7
|
+
import { renderCheckAnnotation } from "./triage-formatter-extra.mjs";
|
|
8
8
|
import { renderRelatedJobLines } from "./related-jobs-format.mjs";
|
|
9
9
|
import { isFailingAgentCheck } from "../checks/conclusions.mjs";
|
|
10
10
|
import { renderMergeCommand } from "../commands/iterate/merge.mjs";
|
|
11
11
|
import { partitionFixThreads } from "../commands/iterate/fix-instruction-threads.mjs";
|
|
12
|
-
export function
|
|
12
|
+
export function formatTriageResult(header, result, opts = {}) {
|
|
13
13
|
const verbose = opts.verbose ?? false;
|
|
14
14
|
const topCap = verbose ? undefined : BODY_TRUNCATE_MAX_CHARS;
|
|
15
15
|
const sections = [header];
|
|
16
|
-
if (result.
|
|
17
|
-
const { shown, total } = result.
|
|
16
|
+
if (result.triage.reviewItems) {
|
|
17
|
+
const { shown, total } = result.triage.reviewItems;
|
|
18
18
|
sections.push(`**showing** ${shown} of ${total} review items`);
|
|
19
19
|
}
|
|
20
20
|
if (result.mergedBasePullRequests?.length) {
|
|
@@ -41,25 +41,25 @@ export function formatFixCodeResult(header, result, opts = {}) {
|
|
|
41
41
|
}
|
|
42
42
|
}
|
|
43
43
|
};
|
|
44
|
-
const { locatedThreads, unlocatedMutatedThreads, unlocatedThreads } = partitionFixThreads(result.
|
|
44
|
+
const { locatedThreads, unlocatedMutatedThreads, unlocatedThreads } = partitionFixThreads(result.triage.threads, result.triage.resolveCommand, result.triage.resolveOnlyCommand);
|
|
45
45
|
renderThreads("## Review threads", [...locatedThreads, ...unlocatedMutatedThreads]);
|
|
46
46
|
renderThreads("## Unlocated review threads (logged once — no mutation)", unlocatedThreads);
|
|
47
|
-
if (result.
|
|
47
|
+
if (result.triage.resolutionOnlyThreads.length > 0) {
|
|
48
48
|
sections.push("## Review threads to resolve");
|
|
49
|
-
sections.push(result.
|
|
49
|
+
sections.push(result.triage.resolutionOnlyThreads
|
|
50
50
|
.map((t) => renderThreadBullet(t, { statusTag: renderThreadResolutionStatusTag(t), verbose }))
|
|
51
51
|
.join("\n"));
|
|
52
52
|
}
|
|
53
|
-
if (result.
|
|
53
|
+
if (result.triage.actionableComments.length > 0) {
|
|
54
54
|
sections.push("## Actionable comments");
|
|
55
|
-
for (const c of result.
|
|
55
|
+
for (const c of result.triage.actionableComments) {
|
|
56
56
|
const heading = c.url ? `[commentId=${c.id}](${c.url})` : `\`commentId=${c.id}\``;
|
|
57
57
|
const authorizationMarker = c.viewerCanMinimize === false ? " [viewer cannot minimize]" : "";
|
|
58
58
|
sections.push(`### ${heading} (${renderAuthor(c.author, c.authorType, c.authorAssociation)})${authorizationMarker}`);
|
|
59
59
|
sections.push(blockquote(c.body, topCap, c.url));
|
|
60
60
|
}
|
|
61
61
|
}
|
|
62
|
-
const failingChecks = result.
|
|
62
|
+
const failingChecks = result.triage.checks.filter((ch) => isFailingAgentCheck(ch));
|
|
63
63
|
if (failingChecks.length > 0) {
|
|
64
64
|
sections.push("## Failing checks");
|
|
65
65
|
// Multiple failing CheckRuns (matrix jobs, etc.) can share one runId; the rerun command is
|
|
@@ -99,7 +99,7 @@ export function formatFixCodeResult(header, result, opts = {}) {
|
|
|
99
99
|
});
|
|
100
100
|
sections.push(bullets.join("\n\n"));
|
|
101
101
|
}
|
|
102
|
-
const annotatedChecks = result.
|
|
102
|
+
const annotatedChecks = result.triage.checks
|
|
103
103
|
.map((ch) => ({
|
|
104
104
|
ch,
|
|
105
105
|
rendered: (ch.annotations ?? [])
|
|
@@ -121,9 +121,9 @@ export function formatFixCodeResult(header, result, opts = {}) {
|
|
|
121
121
|
sections.push(rendered.join("\n\n"));
|
|
122
122
|
}
|
|
123
123
|
}
|
|
124
|
-
if (result.
|
|
124
|
+
if (result.triage.changesRequestedReviews.length > 0) {
|
|
125
125
|
sections.push("## Changes-requested reviews");
|
|
126
|
-
for (const r of result.
|
|
126
|
+
for (const r of result.triage.changesRequestedReviews) {
|
|
127
127
|
// A stale bot CR that already had its full body surfaced on a prior tick stays a terse
|
|
128
128
|
// one-line reminder (renderReviewBullet's staleBotCr branch) — repeating the full body
|
|
129
129
|
// every tick would be noise, not new content. Every other review (a bot CR's first
|
|
@@ -141,65 +141,54 @@ export function formatFixCodeResult(header, result, opts = {}) {
|
|
|
141
141
|
sections.push(r.body.trim() === "" ? "(no review body)" : blockquote(r.body, topCap));
|
|
142
142
|
}
|
|
143
143
|
}
|
|
144
|
-
if (result.
|
|
144
|
+
if (result.triage.firstLookSummaries.length > 0) {
|
|
145
145
|
sections.push("## Review summaries (first look)");
|
|
146
|
-
for (const r of result.
|
|
146
|
+
for (const r of result.triage.firstLookSummaries) {
|
|
147
147
|
sections.push(`### \`reviewId=${r.id}\` (${renderAuthor(r.author, r.authorType, r.authorAssociation)})${r.viewerCanMinimize === false ? " [viewer cannot minimize]" : ""}`);
|
|
148
148
|
sections.push(r.body.trim() === "" ? "(no review body)" : blockquote(r.body, topCap));
|
|
149
149
|
}
|
|
150
150
|
}
|
|
151
|
-
if (result.
|
|
151
|
+
if (result.triage.editedSummaries.length > 0) {
|
|
152
152
|
sections.push("## Review summaries (edited since first look — already minimized; do not re-minimize)");
|
|
153
|
-
for (const r of result.
|
|
153
|
+
for (const r of result.triage.editedSummaries) {
|
|
154
154
|
sections.push(`### \`reviewId=${r.id}\` (${renderAuthor(r.author, r.authorType, r.authorAssociation)})${r.viewerCanMinimize === false ? " [viewer cannot minimize]" : ""}`);
|
|
155
155
|
sections.push(r.body.trim() === "" ? "(no review body)" : blockquote(r.body, topCap));
|
|
156
156
|
}
|
|
157
157
|
}
|
|
158
|
-
const firstLookSummaryIds = new Set(result.
|
|
159
|
-
const seenSummaryIds = result.
|
|
158
|
+
const firstLookSummaryIds = new Set(result.triage.firstLookSummaries.map((r) => r.id));
|
|
159
|
+
const seenSummaryIds = result.triage.reviewSummaryIds.filter((id) => !firstLookSummaryIds.has(id));
|
|
160
160
|
if (seenSummaryIds.length > 0) {
|
|
161
161
|
sections.push("## Review IDs to minimize queue");
|
|
162
162
|
sections.push(seenSummaryIds.map((id) => `- \`${id}\``).join("\n"));
|
|
163
163
|
}
|
|
164
|
-
if (result.
|
|
164
|
+
if (result.triage.surfacedApprovals.length > 0) {
|
|
165
165
|
sections.push("## Approvals (surfaced — not minimized)");
|
|
166
|
-
for (const r of result.
|
|
166
|
+
for (const r of result.triage.surfacedApprovals) {
|
|
167
167
|
sections.push(`### \`reviewId=${r.id}\` (${renderAuthor(r.author, r.authorType, r.authorAssociation)})${r.viewerCanMinimize === false ? " [viewer cannot minimize]" : ""}`);
|
|
168
168
|
sections.push(r.body.trim() === "" ? "(no review body)" : blockquote(r.body, topCap));
|
|
169
169
|
}
|
|
170
170
|
}
|
|
171
|
-
const firstLookTotal = result.
|
|
171
|
+
const firstLookTotal = result.triage.firstLookThreads.length + result.triage.firstLookComments.length;
|
|
172
172
|
if (firstLookTotal > 0) {
|
|
173
173
|
sections.push(`## First-look items (${firstLookTotal}) — acknowledge status before acting`);
|
|
174
|
-
const resolutionOnlyIds = new Set(result.
|
|
175
|
-
sections.push(buildFirstLookBullets(result.
|
|
176
|
-
}
|
|
177
|
-
if (result.fix.inProgressRunIds.length > 0) {
|
|
178
|
-
sections.push("## In-progress runs");
|
|
179
|
-
sections.push(result.fix.inProgressRunIds.map((id) => `- \`${id}\``).join("\n"));
|
|
180
|
-
}
|
|
181
|
-
if (result.fix.protectedRuns.length > 0) {
|
|
182
|
-
sections.push("## Protected runs", result.fix.protectedRuns.map(renderProtectedRun).join("\n"));
|
|
183
|
-
}
|
|
184
|
-
if (result.cancelled.length > 0) {
|
|
185
|
-
sections.push("## Cancelled runs");
|
|
186
|
-
sections.push(result.cancelled.map((id) => `- \`${id}\``).join("\n"));
|
|
174
|
+
const resolutionOnlyIds = new Set(result.triage.resolutionOnlyThreads.map((t) => t.id));
|
|
175
|
+
sections.push(buildFirstLookBullets(result.triage.firstLookThreads, resolutionOnlyIds, result.triage.firstLookComments, verbose).join("\n"));
|
|
187
176
|
}
|
|
188
177
|
// The review mutation commands render inline in their `## Instructions` steps.
|
|
189
178
|
const postFixLines = verbose ? [`- base: \`${result.baseBranch}\``] : [];
|
|
190
|
-
if (result.
|
|
191
|
-
postFixLines.push(`- requeue: ${inlineCode(renderMergeCommand(result.
|
|
192
|
-
if (result.
|
|
193
|
-
postFixLines.push(`- requeue API fallback: ${inlineCode(renderMergeCommand(result.
|
|
179
|
+
if (result.triage.requeue) {
|
|
180
|
+
postFixLines.push(`- requeue: ${inlineCode(renderMergeCommand(result.triage.requeue.command))}`);
|
|
181
|
+
if (result.triage.requeue.queueApiFallbackCommand) {
|
|
182
|
+
postFixLines.push(`- requeue API fallback: ${inlineCode(renderMergeCommand(result.triage.requeue.queueApiFallbackCommand))}`);
|
|
194
183
|
}
|
|
195
184
|
}
|
|
196
|
-
if (result.
|
|
197
|
-
postFixLines.push(`- acknowledge queue removal: ${inlineCode(renderMergeCommand(result.
|
|
185
|
+
if (result.triage.queueRemovalAcknowledgment) {
|
|
186
|
+
postFixLines.push(`- acknowledge queue removal: ${inlineCode(renderMergeCommand(result.triage.queueRemovalAcknowledgment))}`);
|
|
198
187
|
}
|
|
199
188
|
if (postFixLines.length > 0)
|
|
200
189
|
sections.push("## Post-fix actions", postFixLines.join("\n"));
|
|
201
190
|
sections.push("## Instructions");
|
|
202
|
-
sections.push(numberInstructions(result.
|
|
191
|
+
sections.push(numberInstructions(result.triage.instructions));
|
|
203
192
|
return joinSections(sections);
|
|
204
193
|
}
|
|
205
194
|
function indentBlockquote(body, indent) {
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reject flags a subcommand does not accept before its PR target is resolved. Without this, an
|
|
3
|
+
* unknown or removed flag is treated as value-taking and swallows the PR number that follows it,
|
|
4
|
+
* so the command silently targets the branch-inferred PR instead.
|
|
5
|
+
*/
|
|
6
|
+
export declare function rejectUnknownFlags(args: string[], command: string, knownFlags: readonly string[]): boolean;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { EXIT } from "../exit-codes.mjs";
|
|
2
|
+
import { FLAGS_WITH_VALUES } from "./arg-flags.mjs";
|
|
3
|
+
const GLOBAL_FLAGS = ["--format", "--transport", "--verbose", "--help", "-h"];
|
|
4
|
+
/**
|
|
5
|
+
* Reject flags a subcommand does not accept before its PR target is resolved. Without this, an
|
|
6
|
+
* unknown or removed flag is treated as value-taking and swallows the PR number that follows it,
|
|
7
|
+
* so the command silently targets the branch-inferred PR instead.
|
|
8
|
+
*/
|
|
9
|
+
export function rejectUnknownFlags(args, command, knownFlags) {
|
|
10
|
+
const known = new Set([...GLOBAL_FLAGS, ...knownFlags]);
|
|
11
|
+
let unknown;
|
|
12
|
+
for (let i = 0; i < args.length; i += 1) {
|
|
13
|
+
const arg = args[i];
|
|
14
|
+
if (!arg.startsWith("-"))
|
|
15
|
+
continue;
|
|
16
|
+
if (!known.has(arg.split("=", 1)[0])) {
|
|
17
|
+
unknown = arg;
|
|
18
|
+
break;
|
|
19
|
+
}
|
|
20
|
+
// A separate value (`--message -1`) is the flag's argument, not another flag.
|
|
21
|
+
if (FLAGS_WITH_VALUES.has(arg))
|
|
22
|
+
i += 1;
|
|
23
|
+
}
|
|
24
|
+
if (unknown === undefined)
|
|
25
|
+
return false;
|
|
26
|
+
process.stderr.write(`pr-shepherd: ${command}: unknown flag "${unknown}".\n`);
|
|
27
|
+
process.exitCode = EXIT.USAGE;
|
|
28
|
+
return true;
|
|
29
|
+
}
|
package/bin/cli-parser.mjs
CHANGED
|
@@ -1,24 +1,25 @@
|
|
|
1
1
|
/* eslint-disable max-lines */
|
|
2
2
|
/** CLI argument parsing and subcommand dispatch for pr-shepherd. See --help for usage. */
|
|
3
3
|
import { readFileSync } from "node:fs";
|
|
4
|
-
import { EXIT, applyReviewResultToExitCode, errorToExitCode } from "./exit-codes.mjs";
|
|
4
|
+
import { EXIT, ShepherdError, applyReviewResultToExitCode, errorToExitCode, } from "./exit-codes.mjs";
|
|
5
|
+
import { loadConfig } from "./config/load.mjs";
|
|
5
6
|
import { runResolveMutate } from "./commands/resolve.mjs";
|
|
6
7
|
import { runLogFile } from "./commands/log-file.mjs";
|
|
7
8
|
import { handleClean } from "./cli/clean-handler.mjs";
|
|
8
9
|
import { parseCommonArgs, getFlag, hasFlag, parseList } from "./cli/args.mjs";
|
|
10
|
+
import { rejectUnknownFlags } from "./cli/unknown-flags.mjs";
|
|
9
11
|
import { isDefaultPollInvocation, validateDefaultPollArgs } from "./cli/default-poll.mjs";
|
|
10
12
|
import { USAGE, helpKeyForArgs, maybePrintHelp } from "./cli/help.mjs";
|
|
11
13
|
import { formatMutateResult } from "./cli/formatters.mjs";
|
|
12
|
-
import {
|
|
14
|
+
import { handleSuggest, handleIterate, handleMarkFilesAsViewed } from "./cli/handlers.mjs";
|
|
13
15
|
import { handleJournal } from "./cli/journal-handler.mjs";
|
|
14
16
|
import { handleJournalExtract } from "./cli/journal-extract-handler.mjs";
|
|
15
17
|
import { handlePlaybook } from "./cli/playbook-handler.mjs";
|
|
16
|
-
import { handlePoll } from "./cli/poll-handler.mjs";
|
|
18
|
+
import { handlePoll, handleStack } from "./cli/poll-handler.mjs";
|
|
17
19
|
import { warnPrrcThreadIds, validateRequireSha, rejectPrrcMinimizeIds, } from "./cli/resolve-validators.mjs";
|
|
18
20
|
import { handleCheckBlocker } from "./cli/check-blocker-handler.mjs";
|
|
19
21
|
import { handleQueueRemoval } from "./cli/queue-removal-handler.mjs";
|
|
20
22
|
import { setupLog } from "./log/setup.mjs";
|
|
21
|
-
import { rejectInvalidPollModeFlag, runInEventStateScope, runInPollModeScope, } from "./cli/event-state-scope.mjs";
|
|
22
23
|
import { handleApplyMerge } from "./cli/apply-merge-handler.mjs";
|
|
23
24
|
import { getLocalHeadSha } from "./commands/suggestion-patch-git.mjs";
|
|
24
25
|
import { extractTransportArgs } from "./cli/transport-args.mjs";
|
|
@@ -34,7 +35,6 @@ export async function main(argv) {
|
|
|
34
35
|
if (extracted.args.some((arg) => arg === "--help" || arg === "-h") ||
|
|
35
36
|
extracted.args[0] === "--version" ||
|
|
36
37
|
extracted.args[0] === "-v" ||
|
|
37
|
-
extracted.args[0] === "log-file" ||
|
|
38
38
|
extracted.args[0] === "playbook" ||
|
|
39
39
|
(extracted.args[0] === "admin" && extracted.args[1] === "log-file") ||
|
|
40
40
|
(extracted.args[0] === "journal" && extracted.args[1] === "extract")) {
|
|
@@ -50,6 +50,17 @@ export async function main(argv) {
|
|
|
50
50
|
process.exitCode = EXIT.USAGE;
|
|
51
51
|
return;
|
|
52
52
|
}
|
|
53
|
+
// Validate config before any GitHub work, so a bad or pre-v1 config file exits 78 up front.
|
|
54
|
+
try {
|
|
55
|
+
loadConfig();
|
|
56
|
+
}
|
|
57
|
+
catch (error) {
|
|
58
|
+
if (!(error instanceof ShepherdError))
|
|
59
|
+
throw error;
|
|
60
|
+
process.stderr.write(`pr-shepherd: ${error.message}\n`);
|
|
61
|
+
process.exitCode = error.exitCode;
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
53
64
|
return runWithGithubTransport(mode, () => dispatch(dispatched), {
|
|
54
65
|
verbose: extracted.args.includes("--verbose"),
|
|
55
66
|
});
|
|
@@ -65,12 +76,7 @@ async function dispatch(argv) {
|
|
|
65
76
|
process.stdout.write(`${USAGE.top}\n`);
|
|
66
77
|
return;
|
|
67
78
|
}
|
|
68
|
-
//
|
|
69
|
-
if (subcommand === "log-file") {
|
|
70
|
-
await handleLogFile(args.slice(1));
|
|
71
|
-
return;
|
|
72
|
-
}
|
|
73
|
-
// Extraction deliberately precedes legacy warnings and logging: it is a local,
|
|
79
|
+
// Extraction deliberately precedes logging: it is a local,
|
|
74
80
|
// GitHub/config/log-free read path for automation that already has a PR body.
|
|
75
81
|
if (subcommand === "journal" && args[1] === "extract") {
|
|
76
82
|
await handleJournalExtract(args.slice(2));
|
|
@@ -80,7 +86,7 @@ async function dispatch(argv) {
|
|
|
80
86
|
// command namespace. Keep this before setupLog because log-file reads the
|
|
81
87
|
// log path and must not initialize/tee the log it is reporting.
|
|
82
88
|
if (subcommand === "admin" && args[1] === "log-file") {
|
|
83
|
-
await handleLogFile(args.slice(2)
|
|
89
|
+
await handleLogFile(args.slice(2));
|
|
84
90
|
return;
|
|
85
91
|
}
|
|
86
92
|
// Short-circuit all --help/-h before any I/O or logging.
|
|
@@ -93,24 +99,12 @@ async function dispatch(argv) {
|
|
|
93
99
|
}
|
|
94
100
|
return;
|
|
95
101
|
}
|
|
96
|
-
const legacyReplacement = {
|
|
97
|
-
poll: "pr-shepherd [PR] (the default PR polling command)",
|
|
98
|
-
resolve: "apply review",
|
|
99
|
-
"mark-files-as-viewed": "apply files",
|
|
100
|
-
journal: "apply journal",
|
|
101
|
-
"build-suggestion-patch": "build-suggestion-patches",
|
|
102
|
-
"commit-suggestion": "build-suggestion-patches",
|
|
103
|
-
};
|
|
104
|
-
if (subcommand !== undefined && legacyReplacement[subcommand] !== undefined) {
|
|
105
|
-
warnLegacyAlias(subcommand, legacyReplacement[subcommand]);
|
|
106
|
-
}
|
|
107
102
|
// A local read of shipped files: no GitHub, git, or log I/O.
|
|
108
103
|
if (subcommand === "playbook") {
|
|
109
104
|
handlePlaybook(args.slice(1));
|
|
110
105
|
return;
|
|
111
106
|
}
|
|
112
|
-
|
|
113
|
-
return runInEventStateScope(args, () => dispatchLogged(argv));
|
|
107
|
+
return dispatchLogged(argv);
|
|
114
108
|
}
|
|
115
109
|
async function dispatchLogged(argv) {
|
|
116
110
|
const args = argv.slice(2);
|
|
@@ -127,36 +121,18 @@ async function dispatchLogged(argv) {
|
|
|
127
121
|
case "apply":
|
|
128
122
|
await handleApply(args.slice(1));
|
|
129
123
|
break;
|
|
130
|
-
case "
|
|
131
|
-
await
|
|
124
|
+
case "suggest":
|
|
125
|
+
await handleSuggest(args.slice(1));
|
|
132
126
|
break;
|
|
133
|
-
case "
|
|
134
|
-
await
|
|
127
|
+
case "stack":
|
|
128
|
+
await handleStack(args.slice(1));
|
|
135
129
|
break;
|
|
136
130
|
case "admin":
|
|
137
131
|
await handleAdmin(args.slice(1));
|
|
138
132
|
break;
|
|
139
|
-
case "resolve":
|
|
140
|
-
await handleResolve(args.slice(1), "resolve");
|
|
141
|
-
break;
|
|
142
|
-
case "commit-suggestion":
|
|
143
|
-
await handleCommitSuggestion(args.slice(1), "commit-suggestion");
|
|
144
|
-
break;
|
|
145
|
-
case "mark-files-as-viewed":
|
|
146
|
-
await handleMarkFilesAsViewed(args.slice(1), "mark-files-as-viewed");
|
|
147
|
-
break;
|
|
148
133
|
case "iterate":
|
|
149
134
|
await handleIterate(args.slice(1));
|
|
150
135
|
break;
|
|
151
|
-
case "poll":
|
|
152
|
-
await handlePoll(args.slice(1));
|
|
153
|
-
break;
|
|
154
|
-
case "clean":
|
|
155
|
-
await handleClean(args.slice(1), "clean");
|
|
156
|
-
break;
|
|
157
|
-
case "journal":
|
|
158
|
-
await handleJournal(args.slice(1), "journal");
|
|
159
|
-
break;
|
|
160
136
|
default:
|
|
161
137
|
process.stderr.write(`Unknown subcommand: ${subcommand ?? "(none)"}\n`);
|
|
162
138
|
process.stderr.write(`${USAGE.top}\n`);
|
|
@@ -164,9 +140,6 @@ async function dispatchLogged(argv) {
|
|
|
164
140
|
return;
|
|
165
141
|
}
|
|
166
142
|
}
|
|
167
|
-
function warnLegacyAlias(alias, replacement) {
|
|
168
|
-
process.stderr.write(`pr-shepherd: ${alias} is deprecated; use ${replacement.startsWith("pr-shepherd") ? replacement : `pr-shepherd ${replacement}`} instead.\n`);
|
|
169
|
-
}
|
|
170
143
|
async function handleApply(args) {
|
|
171
144
|
const action = args[0];
|
|
172
145
|
switch (action) {
|
|
@@ -213,10 +186,10 @@ function readVersion() {
|
|
|
213
186
|
// ---------------------------------------------------------------------------
|
|
214
187
|
// Subcommand handlers
|
|
215
188
|
// ---------------------------------------------------------------------------
|
|
216
|
-
async function handleLogFile(args
|
|
217
|
-
if (maybePrintHelp(args,
|
|
189
|
+
async function handleLogFile(args) {
|
|
190
|
+
if (maybePrintHelp(args, "admin log-file"))
|
|
218
191
|
return;
|
|
219
|
-
if (
|
|
192
|
+
if (rejectUnknownFlags(args, "admin log-file", []))
|
|
220
193
|
return;
|
|
221
194
|
const jsonOut = args.some((a) => a === "--format=json") ||
|
|
222
195
|
(() => {
|
|
@@ -224,16 +197,27 @@ async function handleLogFile(args, usageKey = "log-file") {
|
|
|
224
197
|
return idx !== -1 && args[idx + 1] === "json";
|
|
225
198
|
})();
|
|
226
199
|
try {
|
|
227
|
-
|
|
228
|
-
const result = await runInPollModeScope(args, () => runLogFile());
|
|
200
|
+
const result = await runLogFile();
|
|
229
201
|
process.stdout.write(jsonOut ? `${JSON.stringify(result, null, 2)}\n` : `${result.path}\n`);
|
|
230
202
|
}
|
|
231
203
|
catch (e) {
|
|
232
|
-
process.stderr.write(`pr-shepherd: log-file: ${String(e)}\n`);
|
|
204
|
+
process.stderr.write(`pr-shepherd: admin log-file: ${String(e)}\n`);
|
|
233
205
|
process.exitCode = errorToExitCode(e);
|
|
234
206
|
}
|
|
235
207
|
}
|
|
236
|
-
|
|
208
|
+
const APPLY_REVIEW_FLAGS = [
|
|
209
|
+
"--resolve-thread-ids",
|
|
210
|
+
"--reply-thread-ids",
|
|
211
|
+
"--minimize-comment-ids",
|
|
212
|
+
"--dismiss-review-ids",
|
|
213
|
+
"--message",
|
|
214
|
+
"--require-sha",
|
|
215
|
+
"--adopt-existing-replies",
|
|
216
|
+
];
|
|
217
|
+
async function handleResolve(args) {
|
|
218
|
+
const command = "apply review";
|
|
219
|
+
if (rejectUnknownFlags(args, command, APPLY_REVIEW_FLAGS))
|
|
220
|
+
return;
|
|
237
221
|
const { prNumber, global: globalOpts, extra } = parseCommonArgs(args);
|
|
238
222
|
const resolveThreadIds = parseList(getFlag(extra, "--resolve-thread-ids"));
|
|
239
223
|
const replyThreadIds = parseList(getFlag(extra, "--reply-thread-ids"));
|
|
@@ -247,11 +231,6 @@ async function handleResolve(args, command = "apply review") {
|
|
|
247
231
|
return;
|
|
248
232
|
if (rejectPrrcMinimizeIds(minimizeCommentIds).length > 0)
|
|
249
233
|
return;
|
|
250
|
-
if (hasFlag(extra, "--fetch")) {
|
|
251
|
-
process.stderr.write(`pr-shepherd: ${command}: --fetch has been removed; run pr-shepherd iterate to fetch the next action.\n`);
|
|
252
|
-
process.exitCode = EXIT.USAGE;
|
|
253
|
-
return;
|
|
254
|
-
}
|
|
255
234
|
const hasAction = resolveThreadIds.length > 0 ||
|
|
256
235
|
replyThreadIds.length > 0 ||
|
|
257
236
|
minimizeCommentIds.length > 0 ||
|
|
@@ -6,7 +6,7 @@ export declare function checksWithActionableAnnotations(report: ShepherdReport):
|
|
|
6
6
|
* check, an unseen check-run annotation, or a hard merge conflict) — the categories that
|
|
7
7
|
* `commands/iterate/index.mts` never defers while a PR is queued. Shared with `check.mts` so
|
|
8
8
|
* the seen-marker suppression gate there can't drift from the actual iterate dispatch
|
|
9
|
-
* decision (a queued PR with a failing check still renders review items via `
|
|
9
|
+
* decision (a queued PR with a failing check still renders review items via `triage`; their
|
|
10
10
|
* seen markers must not be suppressed just because the PR happens to be queued).
|
|
11
11
|
*/
|
|
12
12
|
export declare function hasCheckDrivenActionableWork(checks: {
|
|
@@ -20,7 +20,7 @@ export function checksWithActionableAnnotations(report) {
|
|
|
20
20
|
* check, an unseen check-run annotation, or a hard merge conflict) — the categories that
|
|
21
21
|
* `commands/iterate/index.mts` never defers while a PR is queued. Shared with `check.mts` so
|
|
22
22
|
* the seen-marker suppression gate there can't drift from the actual iterate dispatch
|
|
23
|
-
* decision (a queued PR with a failing check still renders review items via `
|
|
23
|
+
* decision (a queued PR with a failing check still renders review items via `triage`; their
|
|
24
24
|
* seen markers must not be suppressed just because the PR happens to be queued).
|
|
25
25
|
*/
|
|
26
26
|
export function hasCheckDrivenActionableWork(checks, mergeStatusValue) {
|