pr-shepherd 0.19.0 → 0.21.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 +23 -56
- package/bin/checks/triage.test-support.mjs +1 -2
- package/bin/cli/default-poll.mjs +32 -0
- package/bin/cli/fix-formatter.mjs +3 -3
- package/bin/cli/formatters.mjs +5 -4
- package/bin/cli/handlers.mjs +0 -1
- package/bin/cli/help-command-pages.mjs +153 -0
- package/bin/cli/help-top-page.mjs +59 -0
- package/bin/cli/help.mjs +4 -30
- package/bin/cli/iterate-emitter.mjs +0 -1
- package/bin/cli/iterate-formatter.mjs +4 -6
- package/bin/cli/iterate-instructions.mjs +6 -8
- package/bin/cli/iterate-lean.mjs +4 -6
- package/bin/cli/iterate-lean.test-support.mjs +0 -2
- package/bin/cli/list-formatters.mjs +3 -0
- package/bin/cli/poll-handler.mjs +0 -1
- package/bin/cli/runner.mjs +2 -103
- package/bin/cli/validate-default-args.mjs +32 -0
- package/bin/cli-parser.clean.test-support.mjs +0 -1
- package/bin/cli-parser.commit-suggestion.test-support.mjs +2 -3
- package/bin/cli-parser.iterate-fix.test-support.mjs +1 -2
- package/bin/cli-parser.iterate-fixtures.mjs +1 -1
- package/bin/cli-parser.iterate.test-support.mjs +1 -2
- package/bin/cli-parser.mjs +7 -7
- package/bin/cli-parser.test-support.mjs +1 -2
- package/bin/commands/check.mjs +2 -1
- package/bin/commands/check.test-support.mjs +1 -2
- package/bin/commands/clean.test-support.mjs +0 -1
- package/bin/commands/commit-suggestion-instruction.mjs +2 -2
- package/bin/commands/commit-suggestion.apply.test-support.mjs +1 -2
- package/bin/commands/commit-suggestion.mjs +6 -2
- package/bin/commands/commit-suggestion.test-support.mjs +2 -3
- package/bin/commands/iterate/classify.mjs +2 -2
- package/bin/commands/iterate/fix-code.mjs +3 -3
- package/bin/commands/iterate/index.mjs +0 -1
- package/bin/commands/iterate/render.mjs +4 -3
- package/bin/commands/iterate-stall.test-support.mjs +0 -1
- package/bin/commands/iterate.fix-code-in-progress.test-support.mjs +2 -2
- package/bin/commands/poll.mjs +12 -3
- package/bin/commands/resolve-instructions.mjs +6 -7
- package/bin/commands/resolve.mjs +1 -1
- package/bin/commands/resolve.test-support.mjs +2 -2
- package/bin/commands/shepherd-journal.test-support.mjs +0 -2
- package/bin/comments/resolve.test-support.mjs +1 -2
- package/bin/comments/visible-comments.mjs +3 -2
- package/bin/config/load.mjs +0 -7
- package/bin/config.json +0 -3
- package/bin/github/batch-parsers.test-support.mjs +1 -2
- package/bin/github/batch.test-support.mjs +1 -2
- package/bin/github/http.test-support.mjs +1 -2
- package/bin/reporters/agent.mjs +1 -0
- package/bin/suggestions/patch.test-support.mjs +0 -2
- package/package.json +1 -1
- package/plugins/pr-shepherd/.codex-plugin/plugin.json +1 -1
- package/plugins/pr-shepherd/skills/pr-shepherd/SKILL.md +11 -27
- package/bin/cli/default-iterate.mjs +0 -50
|
@@ -13,8 +13,9 @@ export function classifyVisibleComments(comments, seenMap, minimizeComments) {
|
|
|
13
13
|
const cls = classifyItem(c.id, c.body, seenMap);
|
|
14
14
|
if (cls === "unchanged")
|
|
15
15
|
continue;
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
const comment = cls === "edited" ? { ...c, edited: true } : c;
|
|
17
|
+
actionable.push(comment);
|
|
18
|
+
toMarkSeen.push(comment);
|
|
18
19
|
}
|
|
19
20
|
return { actionable, minimizeIds, toMarkSeen };
|
|
20
21
|
}
|
package/bin/config/load.mjs
CHANGED
|
@@ -3,7 +3,6 @@ import { join, dirname } from "node:path";
|
|
|
3
3
|
import { homedir } from "node:os";
|
|
4
4
|
import { parse } from "yaml";
|
|
5
5
|
import builtins from "../config.json" with { type: "json" };
|
|
6
|
-
import { parseCliRunner } from "../cli/runner.mjs";
|
|
7
6
|
const MINIMIZE_COMMENTS_POLICIES = ["all", "bots", "users", "none"];
|
|
8
7
|
const RC_FILENAME = ".pr-shepherdrc.yml";
|
|
9
8
|
function findRcFile(startDir) {
|
|
@@ -61,12 +60,6 @@ export function loadConfig() {
|
|
|
61
60
|
const raw = readFileSync(rcPath, "utf8");
|
|
62
61
|
const parsed = (parse(raw) ?? {});
|
|
63
62
|
const config = deepMerge(defaults, parsed);
|
|
64
|
-
// Validate cli and watch at load time so misconfigurations are caught once
|
|
65
|
-
// with the rc file path in context, rather than during instruction rendering.
|
|
66
|
-
if (config.cli === null || Array.isArray(config.cli) || typeof config.cli !== "object") {
|
|
67
|
-
throw new Error(`Invalid config: cli must be a plain object, got ${JSON.stringify(config.cli)}`);
|
|
68
|
-
}
|
|
69
|
-
config.cli.runner = parseCliRunner(config.cli.runner);
|
|
70
63
|
config.iterate.minimizeComments = parseMinimizeCommentsPolicy(config.iterate.minimizeComments);
|
|
71
64
|
configCache.set(cwd, config);
|
|
72
65
|
return config;
|
package/bin/config.json
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
import { describe, it, expect, vi, beforeEach } from "vitest";
|
|
1
|
+
import { vi, beforeEach } from "vitest";
|
|
3
2
|
// ---------------------------------------------------------------------------
|
|
4
3
|
// Stub fetch and child_process globally before any imports.
|
|
5
4
|
// ---------------------------------------------------------------------------
|
package/bin/reporters/agent.mjs
CHANGED
package/package.json
CHANGED
|
@@ -8,7 +8,7 @@ allowed-tools: ["Bash", "Read", "Grep", "Edit", "Write", "Glob", "Skill"]
|
|
|
8
8
|
|
|
9
9
|
# pr-shepherd
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
Poll dispatcher for iterating a PR to completion.
|
|
12
12
|
|
|
13
13
|
## Arguments: $ARGUMENTS
|
|
14
14
|
|
|
@@ -20,40 +20,24 @@ One-tick dispatcher for iterating a PR to completion.
|
|
|
20
20
|
- Otherwise, infer: `gh pr view --json number --jq .number`
|
|
21
21
|
- If no PR found, report an error and stop.
|
|
22
22
|
|
|
23
|
-
2. **
|
|
23
|
+
2. **Run `pr-shepherd`:**
|
|
24
24
|
|
|
25
25
|
```bash
|
|
26
|
-
|
|
26
|
+
pr-shepherd <N> --interval 45s --timeout 4m
|
|
27
27
|
```
|
|
28
28
|
|
|
29
|
-
|
|
29
|
+
Do not pass `$ARGUMENTS` through as extra flags. If you need to inspect supported options, run `pr-shepherd --help`.
|
|
30
30
|
|
|
31
|
-
|
|
32
|
-
- Prefer `package.json` `packageManager`: `pnpm@...` → `pnpm exec`, `yarn@...` → `yarn run`, `bun@...` → `bunx`, `npm@...` → `npx`.
|
|
33
|
-
- If `packageManager` is absent, use lockfiles: `pnpm-lock.yaml` → `pnpm exec`, `yarn.lock` → `yarn run`, `bun.lock` / `bun.lockb` → `bunx`, `package-lock.json` or no signal → `npx`.
|
|
31
|
+
Print the full output. Follow the `## Instructions` section exactly for the current action.
|
|
34
32
|
|
|
35
|
-
|
|
33
|
+
3. **Persistence:** Continuously call `pr-shepherd <N> --interval 45s --timeout 4m` until the CLI returns `[CANCEL]` or `[ESCALATE]`, unless the human directs you to stop. Every other action is non-terminal:
|
|
34
|
+
- `[WAIT]`: call `pr-shepherd <N> --interval 45s --timeout 4m` again.
|
|
35
|
+
- `[MARK_READY]`: call `pr-shepherd <N> --interval 45s --timeout 4m` again.
|
|
36
|
+
- `[FIX_CODE]`: follow the output's `## Instructions`, then call `pr-shepherd <N> --interval 45s --timeout 4m` again.
|
|
36
37
|
|
|
37
|
-
|
|
38
|
+
Treat a nonzero poll exit code as PR state only when the output contains a matching `# PR #N [ACTION]` heading. Exit code `1` can also mean a command or validation failure; if there is no `[FIX_CODE]` heading, surface the error and stop instead of looping.
|
|
38
39
|
|
|
39
|
-
|
|
40
|
-
<runner> pr-shepherd <N>
|
|
41
|
-
```
|
|
42
|
-
|
|
43
|
-
Print the full output. Follow the `## Instructions` section exactly.
|
|
44
|
-
|
|
45
|
-
5. **Persistence:** Do not stop polling/iterating unless directed by the human or until the CLI returns a terminal state (`[CANCEL]` or `[ESCALATE]`). Every other action — `[WAIT]`, `[MARK_READY]`, `[FIX_CODE]` — is non-terminal and must be followed by another tick via one of the strategies below.
|
|
46
|
-
|
|
47
|
-
6. **Stop conditions (terminal states):**
|
|
40
|
+
4. **Stop conditions (terminal states):**
|
|
48
41
|
- Stop when the CLI emits `[CANCEL]` (ready-delay completed, or PR merged/closed).
|
|
49
42
|
- Stop when the CLI emits `[ESCALATE]`, including `stall-timeout` for repeated unchanged CI failures.
|
|
50
43
|
- **Do NOT merge the pull request** unless the human has explicitly requested or allowed it.
|
|
51
|
-
|
|
52
|
-
7. **Non-terminal actions** (`[WAIT]`, `[MARK_READY]`, `[FIX_CODE]`) — follow the `## Instructions` in the output. Pick one iteration strategy:
|
|
53
|
-
- **Blocking poll** — rerun as `<runner> pr-shepherd poll <N> [--interval <duration>] [--timeout <duration>]` (defaults: interval 30s, timeout 5m). Holds the agent turn until the action is non-WAIT or the timeout fires. Simplest when the agent cannot reliably schedule its own follow-up.
|
|
54
|
-
- **Scheduled wakeup + one tick** — schedule a single session-only follow-up task to rerun `<runner> pr-shepherd <N>` after a fresh 30s–4m delay, then end the turn.
|
|
55
|
-
- **Inline sleep + rerun** — sleep inline for a fresh 30s–4m delay, then rerun.
|
|
56
|
-
|
|
57
|
-
**Never write a custom polling loop** (shell `while`/`until` loops, script files that loop over pr-shepherd output, etc.). Custom loops poll only for terminal states and silently skip `[FIX_CODE]` handling — actionable review threads, failing checks, and resolve commands get missed. Use `pr-shepherd poll` for WAIT-state waiting; it exits on any non-WAIT action so the caller handles `[FIX_CODE]` and other actionable outputs normally.
|
|
58
|
-
|
|
59
|
-
Do not combine strategies (e.g., poll AND schedule a wakeup). Remember step 5 — every non-terminal output requires a follow-up tick.
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
import { parsePrNumber } from "./args.mjs";
|
|
2
|
-
import { USAGE } from "./help.mjs";
|
|
3
|
-
const DEFAULT_ITERATE_FLAGS_WITH_VALUES = new Set(["--format", "--ready-delay", "--stall-timeout"]);
|
|
4
|
-
const DEFAULT_ITERATE_BOOLEAN_FLAGS = new Set([
|
|
5
|
-
"--verbose",
|
|
6
|
-
"--no-auto-mark-ready",
|
|
7
|
-
"--no-auto-cancel-actionable",
|
|
8
|
-
]);
|
|
9
|
-
export function isDefaultIterateInvocation(subcommand) {
|
|
10
|
-
if (subcommand === "--help" || subcommand === "-h")
|
|
11
|
-
return false;
|
|
12
|
-
return (subcommand === undefined ||
|
|
13
|
-
parsePrNumber(subcommand) !== null ||
|
|
14
|
-
isDefaultIterateFlag(subcommand));
|
|
15
|
-
}
|
|
16
|
-
export function validateDefaultIterateArgs(args) {
|
|
17
|
-
let sawPr = false;
|
|
18
|
-
for (let i = 0; i < args.length; i += 1) {
|
|
19
|
-
const arg = args[i];
|
|
20
|
-
if (DEFAULT_ITERATE_FLAGS_WITH_VALUES.has(arg)) {
|
|
21
|
-
if (i + 1 >= args.length || args[i + 1].startsWith("--")) {
|
|
22
|
-
writeDefaultUsageError(arg);
|
|
23
|
-
return false;
|
|
24
|
-
}
|
|
25
|
-
i += 1;
|
|
26
|
-
continue;
|
|
27
|
-
}
|
|
28
|
-
const inlineFlag = arg.split("=", 1)[0];
|
|
29
|
-
if (DEFAULT_ITERATE_FLAGS_WITH_VALUES.has(inlineFlag))
|
|
30
|
-
continue;
|
|
31
|
-
if (DEFAULT_ITERATE_BOOLEAN_FLAGS.has(arg))
|
|
32
|
-
continue;
|
|
33
|
-
if (parsePrNumber(arg) !== null && !sawPr) {
|
|
34
|
-
sawPr = true;
|
|
35
|
-
continue;
|
|
36
|
-
}
|
|
37
|
-
writeDefaultUsageError(arg);
|
|
38
|
-
return false;
|
|
39
|
-
}
|
|
40
|
-
return true;
|
|
41
|
-
}
|
|
42
|
-
function isDefaultIterateFlag(arg) {
|
|
43
|
-
const name = arg.split("=", 1)[0];
|
|
44
|
-
return DEFAULT_ITERATE_FLAGS_WITH_VALUES.has(name) || DEFAULT_ITERATE_BOOLEAN_FLAGS.has(arg);
|
|
45
|
-
}
|
|
46
|
-
function writeDefaultUsageError(arg) {
|
|
47
|
-
process.stderr.write(`Unknown subcommand: ${arg}\n`);
|
|
48
|
-
process.stderr.write(`${USAGE.top}\n`);
|
|
49
|
-
process.exitCode = 1;
|
|
50
|
-
}
|