pr-shepherd 0.59.1 → 0.59.2
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/bin/cli/help-command-pages.d.mts +2 -2
- package/bin/cli/help-iterate-poll-pages.d.mts +2 -2
- package/bin/cli/help-iterate-poll-pages.mjs +5 -5
- package/bin/cli/help-top-page.d.mts +1 -1
- package/bin/cli/help-top-page.mjs +2 -2
- package/bin/cli/help.d.mts +3 -3
- package/bin/cli/iterate-instructions.mjs +1 -31
- package/bin/cli/iterate-lean.mjs +0 -1
- package/bin/commands/event-mode.mjs +3 -7
- package/bin/commands/iterate/index.mjs +12 -3
- package/bin/commands/next-check.d.mts +0 -2
- package/bin/commands/next-check.mjs +1 -1
- package/bin/commands/poll-summary-explicit-instructions.d.mts +2 -0
- package/bin/commands/poll-summary-explicit-instructions.mjs +18 -2
- package/bin/commands/poll-summary-instructions.mjs +33 -11
- package/bin/commands/stack-drain.mjs +1 -2
- package/bin/commands/stack-work.d.mts +8 -21
- package/bin/commands/stack-work.mjs +14 -38
- package/bin/exit-codes.d.mts +1 -1
- package/bin/exit-codes.mjs +2 -1
- package/bin/github/poll-summary-projector.mjs +3 -1
- package/bin/github/poll-summary-route.mjs +6 -7
- package/bin/types/iterate.d.mts +2 -3
- package/bin/types/merge-requirements.d.mts +0 -7
- package/package.json +1 -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 +8 -6
- package/plugins/pr-shepherd/skills/pr-shepherd/references/cloud-event-loop.md +1 -1
- package/plugins/pr-shepherd/skills/pr-shepherd/references/draft-handoff.md +38 -0
- package/bin/commands/iterate/parent-first.d.mts +0 -8
- package/bin/commands/iterate/parent-first.mjs +0 -13
|
@@ -253,8 +253,8 @@ Flags:
|
|
|
253
253
|
|
|
254
254
|
PR may be a number or GitHub pull request URL. When omitted, the current branch PR is inferred.
|
|
255
255
|
Exit code: 0 on success; nonzero on failure (sysexits.h — see docs/exit-codes.md).`;
|
|
256
|
-
readonly iterate: "pr-shepherd iterate\n\nRun one iterate tick for a pull request. The no-subcommand form polls; use this subcommand for a single tick.\nThe output contains one action and an action-specific ## Instructions section.\n\nUsage:\n pr-shepherd iterate [PR] [iterate-flags]\n\nIterate flags:\n --ready-delay <duration> Settle window before a clean PR cancels. Bare number = minutes. Example: 15m.\n --stall-timeout <duration> Escalate repeated unchanged failures after this duration. Bare number = minutes. 0 disables.\n --no-auto-mark-ready
|
|
257
|
-
readonly poll: "pr-shepherd poll\n\nRun iterate repeatedly for one PR, or read compact summaries for an explicit PR set or native\nGitHub stack. Aggregate mode returns when any row needs work, every row is terminal, or timeout.\nPoll exits as soon as iterate returns READY, MARK_READY, CANCEL, or ESCALATE, or when timeout\nreturns the last WAIT result. FIX_CODE starts a --debounce settle window (default:\npoll.debounceSeconds; built-in 1m): poll keeps\niterating at --interval, then runs one more tick after the window and returns that result.\nWith --until-terminal or --merge, poll also continues through MARK_READY.\n\nUsage:\n pr-shepherd poll [PR ...] [poll-flags] [iterate-flags]\n pr-shepherd poll --stack PR [poll-flags] [iterate-flags]\n\nPoll flags:\n --stack PR Select all entries in PR's native GitHub stack, bottom to top.\n --interval <duration> Sleep between WAIT ticks. Bare number = seconds. Default: poll.intervalSeconds (built-in 60s). Stack and multi-PR polls multiply that by poll.stackIntervalFactor (built-in 2) unless this flag is set.\n --timeout <duration> Maximum wall-clock wait for WAIT ticks. Bare number = seconds. Default: poll.timeoutSeconds (built-in 4.5m).\n --debounce <duration> Settle window after first FIX_CODE or stack SHEPHERD before returning. Bare number = seconds. Default: poll.debounceSeconds (built-in 60s). 0 disables.\n --quiet-status Print only changed WAIT snapshots. Overrides poll.quietStatus.\n --no-quiet-status Print every WAIT snapshot. Overrides poll.quietStatus.\n --until-terminal Continue through WAIT/MARK_READY until READY/FIX_CODE/MERGE/CANCEL/ESCALATE or stack SHEPHERD.\n\nForwarded iterate flags:\n --ready-delay <duration> Settle window before a clean PR cancels. Bare number = minutes. Example: 15m.\n --stall-timeout <duration> Escalate repeated unchanged failures after this duration. Bare number = minutes. 0 disables.\n --no-auto-mark-ready
|
|
256
|
+
readonly iterate: "pr-shepherd iterate\n\nRun one iterate tick for a pull request. The no-subcommand form polls; use this subcommand for a single tick.\nThe output contains one action and an action-specific ## Instructions section.\n\nUsage:\n pr-shepherd iterate [PR] [iterate-flags]\n\nIterate flags:\n --ready-delay <duration> Settle window before a clean PR cancels. Bare number = minutes. Example: 15m.\n --stall-timeout <duration> Escalate repeated unchanged failures after this duration. Bare number = minutes. 0 disables.\n --no-auto-mark-ready Leave draft PRs in draft; stop when otherwise ready.\n --no-auto-cancel-actionable Legacy no-op; workflow runs are never cancelled.\n --merge Shepherd through readiness, then emit a merge or merge-queue command.\n --instructions playbook|inline Render fix_code steps inline every tick (default) or fold the invariant ones into a playbook pointer. Default: iterate.instructions (inline).\n --poll-mode auto|poll|event event runs one tick, never sleeps, and prints nextCheck; auto picks event when CLAUDE_CODE_REMOTE=true. Default: poll.mode (auto).\n --transport auto|graphql|rest Select GitHub transport. Default: github.transport (auto).\n --format text|json Output Markdown text or JSON. Default: text.\n --verbose Include verbose iterate fields.\n --help, -h Print this help and exit before GitHub, git, config, or log I/O.\n\nDurations accept s/m/h suffixes: 30s, 4.5m, 1h. A bare number is minutes; decimals are allowed only with an explicit unit (4.5m).\n\nActions:\n WAIT No immediate action; continue with the next poll.\n MARK_READY Draft PR was marked ready; continue with the next poll.\n READY Clean PR is inside the ready-delay. Schedule the rerun for when remainingSeconds elapses. Do not invent unrelated work. Already-owned later work may continue.\n FIX_CODE Agent action is required; follow the instructions, then continue polling.\n CANCEL Stop polling this pull request: merged/closed, ready-delay elapsed, or a clean draft left in draft because auto mark-ready is disabled. Continue remaining work from the original request.\n ESCALATE Stop polling until a human provides direction.\n MERGE Run the emitted merge/queue command, then continue monitoring.\n\nExit codes:\n 0 CANCEL (merged, ready-delay elapsed, or clean draft left in draft by disabled auto mark-ready)\n 10 WAIT or READY\n 11 MARK_READY\n 12 FIX_CODE\n 13 ESCALATE\n 14 CANCEL (closed without merging)\n 15 MERGE\n A command/validation/GitHub failure exits with a sysexits.h code instead (see docs/exit-codes.md).";
|
|
257
|
+
readonly poll: "pr-shepherd poll\n\nRun iterate repeatedly for one PR, or read compact summaries for an explicit PR set or native\nGitHub stack. Aggregate mode returns when any row needs work, every row is terminal, or timeout.\nPoll exits as soon as iterate returns READY, MARK_READY, CANCEL, or ESCALATE, or when timeout\nreturns the last WAIT result. FIX_CODE starts a --debounce settle window (default:\npoll.debounceSeconds; built-in 1m): poll keeps\niterating at --interval, then runs one more tick after the window and returns that result.\nWith --until-terminal or --merge, poll also continues through MARK_READY.\n\nUsage:\n pr-shepherd poll [PR ...] [poll-flags] [iterate-flags]\n pr-shepherd poll --stack PR [poll-flags] [iterate-flags]\n\nPoll flags:\n --stack PR Select all entries in PR's native GitHub stack, bottom to top.\n --interval <duration> Sleep between WAIT ticks. Bare number = seconds. Default: poll.intervalSeconds (built-in 60s). Stack and multi-PR polls multiply that by poll.stackIntervalFactor (built-in 2) unless this flag is set.\n --timeout <duration> Maximum wall-clock wait for WAIT ticks. Bare number = seconds. Default: poll.timeoutSeconds (built-in 4.5m).\n --debounce <duration> Settle window after first FIX_CODE or stack SHEPHERD before returning. Bare number = seconds. Default: poll.debounceSeconds (built-in 60s). 0 disables.\n --quiet-status Print only changed WAIT snapshots. Overrides poll.quietStatus.\n --no-quiet-status Print every WAIT snapshot. Overrides poll.quietStatus.\n --until-terminal Continue through WAIT/MARK_READY until READY/FIX_CODE/MERGE/CANCEL/ESCALATE or stack SHEPHERD.\n\nForwarded iterate flags:\n --ready-delay <duration> Settle window before a clean PR cancels. Bare number = minutes. Example: 15m.\n --stall-timeout <duration> Escalate repeated unchanged failures after this duration. Bare number = minutes. 0 disables.\n --no-auto-mark-ready Leave draft PRs in draft; stop when otherwise ready.\n --no-auto-cancel-actionable Legacy no-op; workflow runs are never cancelled.\n --merge Shepherd through readiness, then emit a merge or merge-queue command.\n --instructions playbook|inline Render fix_code steps inline every tick (default) or fold the invariant ones into a playbook pointer. Default: iterate.instructions (inline).\n --poll-mode auto|poll|event event runs one tick, never sleeps, and prints nextCheck; auto picks event when CLAUDE_CODE_REMOTE=true. Default: poll.mode (auto).\n --transport auto|graphql|rest Select GitHub transport. Default: github.transport (auto).\n --format text|json Output Markdown text or JSON. Default: text.\n --verbose Include verbose iterate fields and detailed per-tick lines.\n --help, -h Print this help and exit before GitHub, git, config, or log I/O.\n\nDurations accept s/m/h suffixes: 30s, 4.5m, 1h. A bare number uses each flag's default unit (seconds\nfor --interval/--timeout/--debounce, minutes for --ready-delay/--stall-timeout); decimals are allowed only with\nan explicit unit (4.5m).\nEach WAIT tick writes a stderr line naming what it is waiting on by default; poll.quietStatus can change that default, --quiet-status/--no-quiet-status override it, and --verbose emits detailed per-tick lines.\nFIX_CODE debounce writes a remaining-seconds line to stderr. --timeout does not cut an in-flight debounce short.\nWith --until-terminal, --timeout is ignored for WAIT ticks and polling continues until READY, FIX_CODE, MERGE, CANCEL, or ESCALATE. With --merge, --timeout still bounds WAIT ticks; it only continues through MARK_READY while polling remains within that timeout.\n\nExit codes: same as iterate (the final tick's action/reason decides the code).\n 0 CANCEL (merged, ready-delay elapsed, or clean draft left in draft by disabled auto mark-ready)\n 10 WAIT or READY (including a WAIT returned by --timeout)\n 11 MARK_READY\n 12 FIX_CODE\n 13 ESCALATE\n 14 CANCEL (closed without merging)\n 15 MERGE\n 16 SHEPHERD (--stack only: run the listed one-PR sessions, then rerun the selector)\n A command/validation/GitHub failure exits with a sysexits.h code instead (see docs/exit-codes.md).";
|
|
258
258
|
readonly clean: `pr-shepherd clean
|
|
259
259
|
|
|
260
260
|
Remove pr-shepherd state files from PR_SHEPHERD_STATE_DIR.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export declare const ITERATE_USAGE = "pr-shepherd iterate\n\nRun one iterate tick for a pull request. The no-subcommand form polls; use this subcommand for a single tick.\nThe output contains one action and an action-specific ## Instructions section.\n\nUsage:\n pr-shepherd iterate [PR] [iterate-flags]\n\nIterate flags:\n --ready-delay <duration> Settle window before a clean PR cancels. Bare number = minutes. Example: 15m.\n --stall-timeout <duration> Escalate repeated unchanged failures after this duration. Bare number = minutes. 0 disables.\n --no-auto-mark-ready
|
|
2
|
-
export declare const POLL_USAGE = "pr-shepherd poll\n\nRun iterate repeatedly for one PR, or read compact summaries for an explicit PR set or native\nGitHub stack. Aggregate mode returns when any row needs work, every row is terminal, or timeout.\nPoll exits as soon as iterate returns READY, MARK_READY, CANCEL, or ESCALATE, or when timeout\nreturns the last WAIT result. FIX_CODE starts a --debounce settle window (default:\npoll.debounceSeconds; built-in 1m): poll keeps\niterating at --interval, then runs one more tick after the window and returns that result.\nWith --until-terminal or --merge, poll also continues through MARK_READY.\n\nUsage:\n pr-shepherd poll [PR ...] [poll-flags] [iterate-flags]\n pr-shepherd poll --stack PR [poll-flags] [iterate-flags]\n\nPoll flags:\n --stack PR Select all entries in PR's native GitHub stack, bottom to top.\n --interval <duration> Sleep between WAIT ticks. Bare number = seconds. Default: poll.intervalSeconds (built-in 60s). Stack and multi-PR polls multiply that by poll.stackIntervalFactor (built-in 2) unless this flag is set.\n --timeout <duration> Maximum wall-clock wait for WAIT ticks. Bare number = seconds. Default: poll.timeoutSeconds (built-in 4.5m).\n --debounce <duration> Settle window after first FIX_CODE or stack SHEPHERD before returning. Bare number = seconds. Default: poll.debounceSeconds (built-in 60s). 0 disables.\n --quiet-status Print only changed WAIT snapshots. Overrides poll.quietStatus.\n --no-quiet-status Print every WAIT snapshot. Overrides poll.quietStatus.\n --until-terminal Continue through WAIT/MARK_READY until READY/FIX_CODE/MERGE/CANCEL/ESCALATE or stack SHEPHERD.\n\nForwarded iterate flags:\n --ready-delay <duration> Settle window before a clean PR cancels. Bare number = minutes. Example: 15m.\n --stall-timeout <duration> Escalate repeated unchanged failures after this duration. Bare number = minutes. 0 disables.\n --no-auto-mark-ready
|
|
1
|
+
export declare const ITERATE_USAGE = "pr-shepherd iterate\n\nRun one iterate tick for a pull request. The no-subcommand form polls; use this subcommand for a single tick.\nThe output contains one action and an action-specific ## Instructions section.\n\nUsage:\n pr-shepherd iterate [PR] [iterate-flags]\n\nIterate flags:\n --ready-delay <duration> Settle window before a clean PR cancels. Bare number = minutes. Example: 15m.\n --stall-timeout <duration> Escalate repeated unchanged failures after this duration. Bare number = minutes. 0 disables.\n --no-auto-mark-ready Leave draft PRs in draft; stop when otherwise ready.\n --no-auto-cancel-actionable Legacy no-op; workflow runs are never cancelled.\n --merge Shepherd through readiness, then emit a merge or merge-queue command.\n --instructions playbook|inline Render fix_code steps inline every tick (default) or fold the invariant ones into a playbook pointer. Default: iterate.instructions (inline).\n --poll-mode auto|poll|event event runs one tick, never sleeps, and prints nextCheck; auto picks event when CLAUDE_CODE_REMOTE=true. Default: poll.mode (auto).\n --transport auto|graphql|rest Select GitHub transport. Default: github.transport (auto).\n --format text|json Output Markdown text or JSON. Default: text.\n --verbose Include verbose iterate fields.\n --help, -h Print this help and exit before GitHub, git, config, or log I/O.\n\nDurations accept s/m/h suffixes: 30s, 4.5m, 1h. A bare number is minutes; decimals are allowed only with an explicit unit (4.5m).\n\nActions:\n WAIT No immediate action; continue with the next poll.\n MARK_READY Draft PR was marked ready; continue with the next poll.\n READY Clean PR is inside the ready-delay. Schedule the rerun for when remainingSeconds elapses. Do not invent unrelated work. Already-owned later work may continue.\n FIX_CODE Agent action is required; follow the instructions, then continue polling.\n CANCEL Stop polling this pull request: merged/closed, ready-delay elapsed, or a clean draft left in draft because auto mark-ready is disabled. Continue remaining work from the original request.\n ESCALATE Stop polling until a human provides direction.\n MERGE Run the emitted merge/queue command, then continue monitoring.\n\nExit codes:\n 0 CANCEL (merged, ready-delay elapsed, or clean draft left in draft by disabled auto mark-ready)\n 10 WAIT or READY\n 11 MARK_READY\n 12 FIX_CODE\n 13 ESCALATE\n 14 CANCEL (closed without merging)\n 15 MERGE\n A command/validation/GitHub failure exits with a sysexits.h code instead (see docs/exit-codes.md).";
|
|
2
|
+
export declare const POLL_USAGE = "pr-shepherd poll\n\nRun iterate repeatedly for one PR, or read compact summaries for an explicit PR set or native\nGitHub stack. Aggregate mode returns when any row needs work, every row is terminal, or timeout.\nPoll exits as soon as iterate returns READY, MARK_READY, CANCEL, or ESCALATE, or when timeout\nreturns the last WAIT result. FIX_CODE starts a --debounce settle window (default:\npoll.debounceSeconds; built-in 1m): poll keeps\niterating at --interval, then runs one more tick after the window and returns that result.\nWith --until-terminal or --merge, poll also continues through MARK_READY.\n\nUsage:\n pr-shepherd poll [PR ...] [poll-flags] [iterate-flags]\n pr-shepherd poll --stack PR [poll-flags] [iterate-flags]\n\nPoll flags:\n --stack PR Select all entries in PR's native GitHub stack, bottom to top.\n --interval <duration> Sleep between WAIT ticks. Bare number = seconds. Default: poll.intervalSeconds (built-in 60s). Stack and multi-PR polls multiply that by poll.stackIntervalFactor (built-in 2) unless this flag is set.\n --timeout <duration> Maximum wall-clock wait for WAIT ticks. Bare number = seconds. Default: poll.timeoutSeconds (built-in 4.5m).\n --debounce <duration> Settle window after first FIX_CODE or stack SHEPHERD before returning. Bare number = seconds. Default: poll.debounceSeconds (built-in 60s). 0 disables.\n --quiet-status Print only changed WAIT snapshots. Overrides poll.quietStatus.\n --no-quiet-status Print every WAIT snapshot. Overrides poll.quietStatus.\n --until-terminal Continue through WAIT/MARK_READY until READY/FIX_CODE/MERGE/CANCEL/ESCALATE or stack SHEPHERD.\n\nForwarded iterate flags:\n --ready-delay <duration> Settle window before a clean PR cancels. Bare number = minutes. Example: 15m.\n --stall-timeout <duration> Escalate repeated unchanged failures after this duration. Bare number = minutes. 0 disables.\n --no-auto-mark-ready Leave draft PRs in draft; stop when otherwise ready.\n --no-auto-cancel-actionable Legacy no-op; workflow runs are never cancelled.\n --merge Shepherd through readiness, then emit a merge or merge-queue command.\n --instructions playbook|inline Render fix_code steps inline every tick (default) or fold the invariant ones into a playbook pointer. Default: iterate.instructions (inline).\n --poll-mode auto|poll|event event runs one tick, never sleeps, and prints nextCheck; auto picks event when CLAUDE_CODE_REMOTE=true. Default: poll.mode (auto).\n --transport auto|graphql|rest Select GitHub transport. Default: github.transport (auto).\n --format text|json Output Markdown text or JSON. Default: text.\n --verbose Include verbose iterate fields and detailed per-tick lines.\n --help, -h Print this help and exit before GitHub, git, config, or log I/O.\n\nDurations accept s/m/h suffixes: 30s, 4.5m, 1h. A bare number uses each flag's default unit (seconds\nfor --interval/--timeout/--debounce, minutes for --ready-delay/--stall-timeout); decimals are allowed only with\nan explicit unit (4.5m).\nEach WAIT tick writes a stderr line naming what it is waiting on by default; poll.quietStatus can change that default, --quiet-status/--no-quiet-status override it, and --verbose emits detailed per-tick lines.\nFIX_CODE debounce writes a remaining-seconds line to stderr. --timeout does not cut an in-flight debounce short.\nWith --until-terminal, --timeout is ignored for WAIT ticks and polling continues until READY, FIX_CODE, MERGE, CANCEL, or ESCALATE. With --merge, --timeout still bounds WAIT ticks; it only continues through MARK_READY while polling remains within that timeout.\n\nExit codes: same as iterate (the final tick's action/reason decides the code).\n 0 CANCEL (merged, ready-delay elapsed, or clean draft left in draft by disabled auto mark-ready)\n 10 WAIT or READY (including a WAIT returned by --timeout)\n 11 MARK_READY\n 12 FIX_CODE\n 13 ESCALATE\n 14 CANCEL (closed without merging)\n 15 MERGE\n 16 SHEPHERD (--stack only: run the listed one-PR sessions, then rerun the selector)\n A command/validation/GitHub failure exits with a sysexits.h code instead (see docs/exit-codes.md).";
|
|
3
3
|
/** Public help page for the default PR polling invocation. */
|
|
4
4
|
export declare const DEFAULT_USAGE: string;
|
|
@@ -9,7 +9,7 @@ Usage:
|
|
|
9
9
|
Iterate flags:
|
|
10
10
|
--ready-delay <duration> Settle window before a clean PR cancels. Bare number = minutes. Example: 15m.
|
|
11
11
|
--stall-timeout <duration> Escalate repeated unchanged failures after this duration. Bare number = minutes. 0 disables.
|
|
12
|
-
--no-auto-mark-ready
|
|
12
|
+
--no-auto-mark-ready Leave draft PRs in draft; stop when otherwise ready.
|
|
13
13
|
--no-auto-cancel-actionable Legacy no-op; workflow runs are never cancelled.
|
|
14
14
|
--merge Shepherd through readiness, then emit a merge or merge-queue command.
|
|
15
15
|
--instructions playbook|inline Render fix_code steps inline every tick (default) or fold the invariant ones into a playbook pointer. Default: iterate.instructions (inline).
|
|
@@ -26,12 +26,12 @@ Actions:
|
|
|
26
26
|
MARK_READY Draft PR was marked ready; continue with the next poll.
|
|
27
27
|
READY Clean PR is inside the ready-delay. Schedule the rerun for when remainingSeconds elapses. Do not invent unrelated work. Already-owned later work may continue.
|
|
28
28
|
FIX_CODE Agent action is required; follow the instructions, then continue polling.
|
|
29
|
-
CANCEL Stop polling this pull request: merged/closed
|
|
29
|
+
CANCEL Stop polling this pull request: merged/closed, ready-delay elapsed, or a clean draft left in draft because auto mark-ready is disabled. Continue remaining work from the original request.
|
|
30
30
|
ESCALATE Stop polling until a human provides direction.
|
|
31
31
|
MERGE Run the emitted merge/queue command, then continue monitoring.
|
|
32
32
|
|
|
33
33
|
Exit codes:
|
|
34
|
-
0 CANCEL (merged
|
|
34
|
+
0 CANCEL (merged, ready-delay elapsed, or clean draft left in draft by disabled auto mark-ready)
|
|
35
35
|
10 WAIT or READY
|
|
36
36
|
11 MARK_READY
|
|
37
37
|
12 FIX_CODE
|
|
@@ -65,7 +65,7 @@ Poll flags:
|
|
|
65
65
|
Forwarded iterate flags:
|
|
66
66
|
--ready-delay <duration> Settle window before a clean PR cancels. Bare number = minutes. Example: 15m.
|
|
67
67
|
--stall-timeout <duration> Escalate repeated unchanged failures after this duration. Bare number = minutes. 0 disables.
|
|
68
|
-
--no-auto-mark-ready
|
|
68
|
+
--no-auto-mark-ready Leave draft PRs in draft; stop when otherwise ready.
|
|
69
69
|
--no-auto-cancel-actionable Legacy no-op; workflow runs are never cancelled.
|
|
70
70
|
--merge Shepherd through readiness, then emit a merge or merge-queue command.
|
|
71
71
|
--instructions playbook|inline Render fix_code steps inline every tick (default) or fold the invariant ones into a playbook pointer. Default: iterate.instructions (inline).
|
|
@@ -83,7 +83,7 @@ FIX_CODE debounce writes a remaining-seconds line to stderr. --timeout does not
|
|
|
83
83
|
With --until-terminal, --timeout is ignored for WAIT ticks and polling continues until READY, FIX_CODE, MERGE, CANCEL, or ESCALATE. With --merge, --timeout still bounds WAIT ticks; it only continues through MARK_READY while polling remains within that timeout.
|
|
84
84
|
|
|
85
85
|
Exit codes: same as iterate (the final tick's action/reason decides the code).
|
|
86
|
-
0 CANCEL (merged
|
|
86
|
+
0 CANCEL (merged, ready-delay elapsed, or clean draft left in draft by disabled auto mark-ready)
|
|
87
87
|
10 WAIT or READY (including a WAIT returned by --timeout)
|
|
88
88
|
11 MARK_READY
|
|
89
89
|
12 FIX_CODE
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const TOP_USAGE = "pr-shepherd\n\nAutonomous PR CI monitor and review-comment resolver for agentic coding tools.\n\nUsage:\n pr-shepherd --version | -v\n pr-shepherd --help | -h\n pr-shepherd [PR ...] [poll-flags] [iterate-flags]\n pr-shepherd --stack PR [poll-flags] [iterate-flags]\n pr-shepherd iterate [PR] [iterate-flags]\n pr-shepherd apply merge [PR] --require-sha SHA --merge-action ACTION --transport rest\n pr-shepherd apply review [PR] [review-flags]\n pr-shepherd apply files [PR] [files...] [--tests] [--match REGEX]\n pr-shepherd apply journal [PR] <item> [--dry-run] [--format text|json]\n pr-shepherd apply check-blocker [PR] --check <name> (--blocked-by <ref>|--clear)\n pr-shepherd apply queue-removal [PR] --require-sha <head> --queue-commit <commit> --removed-at <unix>\n pr-shepherd journal extract --body-file <path>\n pr-shepherd build-suggestion-patches [PR] --thread-id ID --message MSG [groups...]\n pr-shepherd admin clean <pr|branch|current|repo|all> [value] [flags]\n pr-shepherd admin log-file [--format text|json]\n\nCommands:\n [PR ...] Poll one PR, an explicit same-repository set, or a native stack.\n iterate Run one iterate tick (single-tick alias).\n apply merge Submit or resume a guarded asynchronous merge or enqueue request.\n apply review Apply review-state mutations after fixes.\n apply files Mark selected changed files as viewed.\n apply journal Append a list item to the Shepherd Journal details block of a PR body.\n apply check-blocker Record that a failing check is blocked on an external PR or issue.\n apply queue-removal Acknowledge one current CI-driven native-stack queue removal.\n journal extract Extract a validated Shepherd Journal from a local PR-body file as JSON.\n build-suggestion-patches\n Convert ordered GitHub suggestion threads into patches and commit instructions.\n playbook Print a playbook named by an instruction pointer.\n admin clean Remove pr-shepherd state files.\n admin log-file Print the per-worktree debug log path.\n\nPR argument:\n PR may be a number, owner/repo#number, or a GitHub pull request URL.\n Multiple PRs must name one repository. --stack PR selects every entry in PR's native stack.\n When omitted, pr-shepherd infers the current branch's pull request.\n\nCommon flags:\n --transport auto|graphql|rest Select GitHub transport. Default: github.transport (auto).\n --format text|json Output Markdown text or JSON. Default: text.\n --verbose Include verbose iterate fields and detailed poll-tick lines.\n --help, -h Print help and exit before any GitHub, git, config, or log I/O.\n\nIterate flags:\n --ready-delay <duration> Settle window before a clean PR cancels. Bare number = minutes. Example: 15m.\n --stall-timeout <duration> Escalate repeated unchanged failures after this duration. Bare number = minutes. 0 disables.\n --no-auto-mark-ready
|
|
1
|
+
export declare const TOP_USAGE = "pr-shepherd\n\nAutonomous PR CI monitor and review-comment resolver for agentic coding tools.\n\nUsage:\n pr-shepherd --version | -v\n pr-shepherd --help | -h\n pr-shepherd [PR ...] [poll-flags] [iterate-flags]\n pr-shepherd --stack PR [poll-flags] [iterate-flags]\n pr-shepherd iterate [PR] [iterate-flags]\n pr-shepherd apply merge [PR] --require-sha SHA --merge-action ACTION --transport rest\n pr-shepherd apply review [PR] [review-flags]\n pr-shepherd apply files [PR] [files...] [--tests] [--match REGEX]\n pr-shepherd apply journal [PR] <item> [--dry-run] [--format text|json]\n pr-shepherd apply check-blocker [PR] --check <name> (--blocked-by <ref>|--clear)\n pr-shepherd apply queue-removal [PR] --require-sha <head> --queue-commit <commit> --removed-at <unix>\n pr-shepherd journal extract --body-file <path>\n pr-shepherd build-suggestion-patches [PR] --thread-id ID --message MSG [groups...]\n pr-shepherd admin clean <pr|branch|current|repo|all> [value] [flags]\n pr-shepherd admin log-file [--format text|json]\n\nCommands:\n [PR ...] Poll one PR, an explicit same-repository set, or a native stack.\n iterate Run one iterate tick (single-tick alias).\n apply merge Submit or resume a guarded asynchronous merge or enqueue request.\n apply review Apply review-state mutations after fixes.\n apply files Mark selected changed files as viewed.\n apply journal Append a list item to the Shepherd Journal details block of a PR body.\n apply check-blocker Record that a failing check is blocked on an external PR or issue.\n apply queue-removal Acknowledge one current CI-driven native-stack queue removal.\n journal extract Extract a validated Shepherd Journal from a local PR-body file as JSON.\n build-suggestion-patches\n Convert ordered GitHub suggestion threads into patches and commit instructions.\n playbook Print a playbook named by an instruction pointer.\n admin clean Remove pr-shepherd state files.\n admin log-file Print the per-worktree debug log path.\n\nPR argument:\n PR may be a number, owner/repo#number, or a GitHub pull request URL.\n Multiple PRs must name one repository. --stack PR selects every entry in PR's native stack.\n When omitted, pr-shepherd infers the current branch's pull request.\n\nCommon flags:\n --transport auto|graphql|rest Select GitHub transport. Default: github.transport (auto).\n --format text|json Output Markdown text or JSON. Default: text.\n --verbose Include verbose iterate fields and detailed poll-tick lines.\n --help, -h Print help and exit before any GitHub, git, config, or log I/O.\n\nIterate flags:\n --ready-delay <duration> Settle window before a clean PR cancels. Bare number = minutes. Example: 15m.\n --stall-timeout <duration> Escalate repeated unchanged failures after this duration. Bare number = minutes. 0 disables.\n --no-auto-mark-ready Leave draft PRs in draft; stop when otherwise ready.\n --no-auto-cancel-actionable Legacy no-op; workflow runs are never cancelled.\n --merge Shepherd through readiness, then emit a merge or merge-queue command.\n --instructions playbook|inline Render fix_code steps inline every tick (default) or fold the invariant ones into a playbook pointer. Default: iterate.instructions (inline).\n\nPolling flags:\n --interval <duration> Delay between WAIT ticks. Bare number = seconds. Default: poll.intervalSeconds (built-in 60s). Stack and multi-PR polls multiply that by poll.stackIntervalFactor (built-in 2) unless this flag is set.\n --timeout <duration> Poll wall-clock cap for WAIT ticks. Bare number = seconds. Default: poll.timeoutSeconds (built-in 4.5m).\n --debounce <duration> Settle window after first FIX_CODE or stack SHEPHERD before returning. Bare number = seconds. Default: poll.debounceSeconds (built-in 60s). 0 disables.\n --quiet-status Print only changed WAIT snapshots. Overrides poll.quietStatus.\n --no-quiet-status Print every WAIT snapshot. Overrides poll.quietStatus.\n --until-terminal Continue through WAIT/MARK_READY until READY/FIX_CODE/MERGE/CANCEL/ESCALATE or stack SHEPHERD.\n\nClean variants:\n pr [number] Remove state for one PR. Defaults to current branch PR.\n branch [name] Remove state for a branch's PR. Defaults to current branch.\n current Alias for branch against the current branch.\n repo Remove all state for the current repository.\n all Remove all pr-shepherd state.\n\nExit codes: 0 done, 10-19 PR state, 64-78 shepherd failed (sysexits.h).\n 0 CANCEL (merged, ready-delay elapsed, or clean draft left in draft by disabled auto mark-ready)\n 10 WAIT or READY\n 11 MARK_READY\n 12 FIX_CODE\n 13 ESCALATE\n 14 CANCEL (closed without merging)\n 15 MERGE\n 16 SHEPHERD (--stack only: run the listed one-PR sessions, then rerun the selector)\nSee docs/exit-codes.md for the full sysexits.h error-code table.\n\nDuration examples: 30s, 4.5m, 1h. A bare number uses each flag's default unit (see above); decimals are allowed with an explicit unit (4.5m).\n\nRun 'pr-shepherd <command> --help' for command-specific details.";
|
|
@@ -49,7 +49,7 @@ Common flags:
|
|
|
49
49
|
Iterate flags:
|
|
50
50
|
--ready-delay <duration> Settle window before a clean PR cancels. Bare number = minutes. Example: 15m.
|
|
51
51
|
--stall-timeout <duration> Escalate repeated unchanged failures after this duration. Bare number = minutes. 0 disables.
|
|
52
|
-
--no-auto-mark-ready
|
|
52
|
+
--no-auto-mark-ready Leave draft PRs in draft; stop when otherwise ready.
|
|
53
53
|
--no-auto-cancel-actionable Legacy no-op; workflow runs are never cancelled.
|
|
54
54
|
--merge Shepherd through readiness, then emit a merge or merge-queue command.
|
|
55
55
|
--instructions playbook|inline Render fix_code steps inline every tick (default) or fold the invariant ones into a playbook pointer. Default: iterate.instructions (inline).
|
|
@@ -70,7 +70,7 @@ Clean variants:
|
|
|
70
70
|
all Remove all pr-shepherd state.
|
|
71
71
|
|
|
72
72
|
Exit codes: 0 done, 10-19 PR state, 64-78 shepherd failed (sysexits.h).
|
|
73
|
-
0 CANCEL (merged
|
|
73
|
+
0 CANCEL (merged, ready-delay elapsed, or clean draft left in draft by disabled auto mark-ready)
|
|
74
74
|
10 WAIT or READY
|
|
75
75
|
11 MARK_READY
|
|
76
76
|
12 FIX_CODE
|
package/bin/cli/help.d.mts
CHANGED
|
@@ -253,8 +253,8 @@ Flags:
|
|
|
253
253
|
|
|
254
254
|
PR may be a number or GitHub pull request URL. When omitted, the current branch PR is inferred.
|
|
255
255
|
Exit code: 0 on success; nonzero on failure (sysexits.h — see docs/exit-codes.md).`;
|
|
256
|
-
readonly iterate: "pr-shepherd iterate\n\nRun one iterate tick for a pull request. The no-subcommand form polls; use this subcommand for a single tick.\nThe output contains one action and an action-specific ## Instructions section.\n\nUsage:\n pr-shepherd iterate [PR] [iterate-flags]\n\nIterate flags:\n --ready-delay <duration> Settle window before a clean PR cancels. Bare number = minutes. Example: 15m.\n --stall-timeout <duration> Escalate repeated unchanged failures after this duration. Bare number = minutes. 0 disables.\n --no-auto-mark-ready
|
|
257
|
-
readonly poll: "pr-shepherd poll\n\nRun iterate repeatedly for one PR, or read compact summaries for an explicit PR set or native\nGitHub stack. Aggregate mode returns when any row needs work, every row is terminal, or timeout.\nPoll exits as soon as iterate returns READY, MARK_READY, CANCEL, or ESCALATE, or when timeout\nreturns the last WAIT result. FIX_CODE starts a --debounce settle window (default:\npoll.debounceSeconds; built-in 1m): poll keeps\niterating at --interval, then runs one more tick after the window and returns that result.\nWith --until-terminal or --merge, poll also continues through MARK_READY.\n\nUsage:\n pr-shepherd poll [PR ...] [poll-flags] [iterate-flags]\n pr-shepherd poll --stack PR [poll-flags] [iterate-flags]\n\nPoll flags:\n --stack PR Select all entries in PR's native GitHub stack, bottom to top.\n --interval <duration> Sleep between WAIT ticks. Bare number = seconds. Default: poll.intervalSeconds (built-in 60s). Stack and multi-PR polls multiply that by poll.stackIntervalFactor (built-in 2) unless this flag is set.\n --timeout <duration> Maximum wall-clock wait for WAIT ticks. Bare number = seconds. Default: poll.timeoutSeconds (built-in 4.5m).\n --debounce <duration> Settle window after first FIX_CODE or stack SHEPHERD before returning. Bare number = seconds. Default: poll.debounceSeconds (built-in 60s). 0 disables.\n --quiet-status Print only changed WAIT snapshots. Overrides poll.quietStatus.\n --no-quiet-status Print every WAIT snapshot. Overrides poll.quietStatus.\n --until-terminal Continue through WAIT/MARK_READY until READY/FIX_CODE/MERGE/CANCEL/ESCALATE or stack SHEPHERD.\n\nForwarded iterate flags:\n --ready-delay <duration> Settle window before a clean PR cancels. Bare number = minutes. Example: 15m.\n --stall-timeout <duration> Escalate repeated unchanged failures after this duration. Bare number = minutes. 0 disables.\n --no-auto-mark-ready
|
|
256
|
+
readonly iterate: "pr-shepherd iterate\n\nRun one iterate tick for a pull request. The no-subcommand form polls; use this subcommand for a single tick.\nThe output contains one action and an action-specific ## Instructions section.\n\nUsage:\n pr-shepherd iterate [PR] [iterate-flags]\n\nIterate flags:\n --ready-delay <duration> Settle window before a clean PR cancels. Bare number = minutes. Example: 15m.\n --stall-timeout <duration> Escalate repeated unchanged failures after this duration. Bare number = minutes. 0 disables.\n --no-auto-mark-ready Leave draft PRs in draft; stop when otherwise ready.\n --no-auto-cancel-actionable Legacy no-op; workflow runs are never cancelled.\n --merge Shepherd through readiness, then emit a merge or merge-queue command.\n --instructions playbook|inline Render fix_code steps inline every tick (default) or fold the invariant ones into a playbook pointer. Default: iterate.instructions (inline).\n --poll-mode auto|poll|event event runs one tick, never sleeps, and prints nextCheck; auto picks event when CLAUDE_CODE_REMOTE=true. Default: poll.mode (auto).\n --transport auto|graphql|rest Select GitHub transport. Default: github.transport (auto).\n --format text|json Output Markdown text or JSON. Default: text.\n --verbose Include verbose iterate fields.\n --help, -h Print this help and exit before GitHub, git, config, or log I/O.\n\nDurations accept s/m/h suffixes: 30s, 4.5m, 1h. A bare number is minutes; decimals are allowed only with an explicit unit (4.5m).\n\nActions:\n WAIT No immediate action; continue with the next poll.\n MARK_READY Draft PR was marked ready; continue with the next poll.\n READY Clean PR is inside the ready-delay. Schedule the rerun for when remainingSeconds elapses. Do not invent unrelated work. Already-owned later work may continue.\n FIX_CODE Agent action is required; follow the instructions, then continue polling.\n CANCEL Stop polling this pull request: merged/closed, ready-delay elapsed, or a clean draft left in draft because auto mark-ready is disabled. Continue remaining work from the original request.\n ESCALATE Stop polling until a human provides direction.\n MERGE Run the emitted merge/queue command, then continue monitoring.\n\nExit codes:\n 0 CANCEL (merged, ready-delay elapsed, or clean draft left in draft by disabled auto mark-ready)\n 10 WAIT or READY\n 11 MARK_READY\n 12 FIX_CODE\n 13 ESCALATE\n 14 CANCEL (closed without merging)\n 15 MERGE\n A command/validation/GitHub failure exits with a sysexits.h code instead (see docs/exit-codes.md).";
|
|
257
|
+
readonly poll: "pr-shepherd poll\n\nRun iterate repeatedly for one PR, or read compact summaries for an explicit PR set or native\nGitHub stack. Aggregate mode returns when any row needs work, every row is terminal, or timeout.\nPoll exits as soon as iterate returns READY, MARK_READY, CANCEL, or ESCALATE, or when timeout\nreturns the last WAIT result. FIX_CODE starts a --debounce settle window (default:\npoll.debounceSeconds; built-in 1m): poll keeps\niterating at --interval, then runs one more tick after the window and returns that result.\nWith --until-terminal or --merge, poll also continues through MARK_READY.\n\nUsage:\n pr-shepherd poll [PR ...] [poll-flags] [iterate-flags]\n pr-shepherd poll --stack PR [poll-flags] [iterate-flags]\n\nPoll flags:\n --stack PR Select all entries in PR's native GitHub stack, bottom to top.\n --interval <duration> Sleep between WAIT ticks. Bare number = seconds. Default: poll.intervalSeconds (built-in 60s). Stack and multi-PR polls multiply that by poll.stackIntervalFactor (built-in 2) unless this flag is set.\n --timeout <duration> Maximum wall-clock wait for WAIT ticks. Bare number = seconds. Default: poll.timeoutSeconds (built-in 4.5m).\n --debounce <duration> Settle window after first FIX_CODE or stack SHEPHERD before returning. Bare number = seconds. Default: poll.debounceSeconds (built-in 60s). 0 disables.\n --quiet-status Print only changed WAIT snapshots. Overrides poll.quietStatus.\n --no-quiet-status Print every WAIT snapshot. Overrides poll.quietStatus.\n --until-terminal Continue through WAIT/MARK_READY until READY/FIX_CODE/MERGE/CANCEL/ESCALATE or stack SHEPHERD.\n\nForwarded iterate flags:\n --ready-delay <duration> Settle window before a clean PR cancels. Bare number = minutes. Example: 15m.\n --stall-timeout <duration> Escalate repeated unchanged failures after this duration. Bare number = minutes. 0 disables.\n --no-auto-mark-ready Leave draft PRs in draft; stop when otherwise ready.\n --no-auto-cancel-actionable Legacy no-op; workflow runs are never cancelled.\n --merge Shepherd through readiness, then emit a merge or merge-queue command.\n --instructions playbook|inline Render fix_code steps inline every tick (default) or fold the invariant ones into a playbook pointer. Default: iterate.instructions (inline).\n --poll-mode auto|poll|event event runs one tick, never sleeps, and prints nextCheck; auto picks event when CLAUDE_CODE_REMOTE=true. Default: poll.mode (auto).\n --transport auto|graphql|rest Select GitHub transport. Default: github.transport (auto).\n --format text|json Output Markdown text or JSON. Default: text.\n --verbose Include verbose iterate fields and detailed per-tick lines.\n --help, -h Print this help and exit before GitHub, git, config, or log I/O.\n\nDurations accept s/m/h suffixes: 30s, 4.5m, 1h. A bare number uses each flag's default unit (seconds\nfor --interval/--timeout/--debounce, minutes for --ready-delay/--stall-timeout); decimals are allowed only with\nan explicit unit (4.5m).\nEach WAIT tick writes a stderr line naming what it is waiting on by default; poll.quietStatus can change that default, --quiet-status/--no-quiet-status override it, and --verbose emits detailed per-tick lines.\nFIX_CODE debounce writes a remaining-seconds line to stderr. --timeout does not cut an in-flight debounce short.\nWith --until-terminal, --timeout is ignored for WAIT ticks and polling continues until READY, FIX_CODE, MERGE, CANCEL, or ESCALATE. With --merge, --timeout still bounds WAIT ticks; it only continues through MARK_READY while polling remains within that timeout.\n\nExit codes: same as iterate (the final tick's action/reason decides the code).\n 0 CANCEL (merged, ready-delay elapsed, or clean draft left in draft by disabled auto mark-ready)\n 10 WAIT or READY (including a WAIT returned by --timeout)\n 11 MARK_READY\n 12 FIX_CODE\n 13 ESCALATE\n 14 CANCEL (closed without merging)\n 15 MERGE\n 16 SHEPHERD (--stack only: run the listed one-PR sessions, then rerun the selector)\n A command/validation/GitHub failure exits with a sysexits.h code instead (see docs/exit-codes.md).";
|
|
258
258
|
readonly clean: `pr-shepherd clean
|
|
259
259
|
|
|
260
260
|
Remove pr-shepherd state files from PR_SHEPHERD_STATE_DIR.
|
|
@@ -336,7 +336,7 @@ The name is case-insensitive; spaces and hyphens are equivalent ("Fix-code loop"
|
|
|
336
336
|
Unknown names exit 64 and list the available playbooks.
|
|
337
337
|
--help, -h Print this help and exit before any I/O.`;
|
|
338
338
|
readonly "log-file": "pr-shepherd log-file\n\nPrint the per-worktree append-only debug log path for the current repository.\nThe log is created by the first non-help pr-shepherd command that initializes logging.\n\nUsage:\n pr-shepherd log-file [--format text|json] [--poll-mode auto|poll|event]\n\nFlags:\n --format text|json Print a raw path or {\"path\": \"...\"} JSON. Default: text.\n --poll-mode auto|poll|event\n Report the log for that poll mode; event mode keeps it in durable\n state under the git common directory. Default: poll.mode (auto).\n --help, -h Print this help and exit before logging setup.\n\nEnvironment:\n PR_SHEPHERD_LOG_DISABLED=1 disables logging.\n PR_SHEPHERD_STATE_DIR overrides the base state directory.\n\nExit code: 0 on success; 1 if repository identity cannot be resolved.";
|
|
339
|
-
readonly top: "pr-shepherd\n\nAutonomous PR CI monitor and review-comment resolver for agentic coding tools.\n\nUsage:\n pr-shepherd --version | -v\n pr-shepherd --help | -h\n pr-shepherd [PR ...] [poll-flags] [iterate-flags]\n pr-shepherd --stack PR [poll-flags] [iterate-flags]\n pr-shepherd iterate [PR] [iterate-flags]\n pr-shepherd apply merge [PR] --require-sha SHA --merge-action ACTION --transport rest\n pr-shepherd apply review [PR] [review-flags]\n pr-shepherd apply files [PR] [files...] [--tests] [--match REGEX]\n pr-shepherd apply journal [PR] <item> [--dry-run] [--format text|json]\n pr-shepherd apply check-blocker [PR] --check <name> (--blocked-by <ref>|--clear)\n pr-shepherd apply queue-removal [PR] --require-sha <head> --queue-commit <commit> --removed-at <unix>\n pr-shepherd journal extract --body-file <path>\n pr-shepherd build-suggestion-patches [PR] --thread-id ID --message MSG [groups...]\n pr-shepherd admin clean <pr|branch|current|repo|all> [value] [flags]\n pr-shepherd admin log-file [--format text|json]\n\nCommands:\n [PR ...] Poll one PR, an explicit same-repository set, or a native stack.\n iterate Run one iterate tick (single-tick alias).\n apply merge Submit or resume a guarded asynchronous merge or enqueue request.\n apply review Apply review-state mutations after fixes.\n apply files Mark selected changed files as viewed.\n apply journal Append a list item to the Shepherd Journal details block of a PR body.\n apply check-blocker Record that a failing check is blocked on an external PR or issue.\n apply queue-removal Acknowledge one current CI-driven native-stack queue removal.\n journal extract Extract a validated Shepherd Journal from a local PR-body file as JSON.\n build-suggestion-patches\n Convert ordered GitHub suggestion threads into patches and commit instructions.\n playbook Print a playbook named by an instruction pointer.\n admin clean Remove pr-shepherd state files.\n admin log-file Print the per-worktree debug log path.\n\nPR argument:\n PR may be a number, owner/repo#number, or a GitHub pull request URL.\n Multiple PRs must name one repository. --stack PR selects every entry in PR's native stack.\n When omitted, pr-shepherd infers the current branch's pull request.\n\nCommon flags:\n --transport auto|graphql|rest Select GitHub transport. Default: github.transport (auto).\n --format text|json Output Markdown text or JSON. Default: text.\n --verbose Include verbose iterate fields and detailed poll-tick lines.\n --help, -h Print help and exit before any GitHub, git, config, or log I/O.\n\nIterate flags:\n --ready-delay <duration> Settle window before a clean PR cancels. Bare number = minutes. Example: 15m.\n --stall-timeout <duration> Escalate repeated unchanged failures after this duration. Bare number = minutes. 0 disables.\n --no-auto-mark-ready
|
|
339
|
+
readonly top: "pr-shepherd\n\nAutonomous PR CI monitor and review-comment resolver for agentic coding tools.\n\nUsage:\n pr-shepherd --version | -v\n pr-shepherd --help | -h\n pr-shepherd [PR ...] [poll-flags] [iterate-flags]\n pr-shepherd --stack PR [poll-flags] [iterate-flags]\n pr-shepherd iterate [PR] [iterate-flags]\n pr-shepherd apply merge [PR] --require-sha SHA --merge-action ACTION --transport rest\n pr-shepherd apply review [PR] [review-flags]\n pr-shepherd apply files [PR] [files...] [--tests] [--match REGEX]\n pr-shepherd apply journal [PR] <item> [--dry-run] [--format text|json]\n pr-shepherd apply check-blocker [PR] --check <name> (--blocked-by <ref>|--clear)\n pr-shepherd apply queue-removal [PR] --require-sha <head> --queue-commit <commit> --removed-at <unix>\n pr-shepherd journal extract --body-file <path>\n pr-shepherd build-suggestion-patches [PR] --thread-id ID --message MSG [groups...]\n pr-shepherd admin clean <pr|branch|current|repo|all> [value] [flags]\n pr-shepherd admin log-file [--format text|json]\n\nCommands:\n [PR ...] Poll one PR, an explicit same-repository set, or a native stack.\n iterate Run one iterate tick (single-tick alias).\n apply merge Submit or resume a guarded asynchronous merge or enqueue request.\n apply review Apply review-state mutations after fixes.\n apply files Mark selected changed files as viewed.\n apply journal Append a list item to the Shepherd Journal details block of a PR body.\n apply check-blocker Record that a failing check is blocked on an external PR or issue.\n apply queue-removal Acknowledge one current CI-driven native-stack queue removal.\n journal extract Extract a validated Shepherd Journal from a local PR-body file as JSON.\n build-suggestion-patches\n Convert ordered GitHub suggestion threads into patches and commit instructions.\n playbook Print a playbook named by an instruction pointer.\n admin clean Remove pr-shepherd state files.\n admin log-file Print the per-worktree debug log path.\n\nPR argument:\n PR may be a number, owner/repo#number, or a GitHub pull request URL.\n Multiple PRs must name one repository. --stack PR selects every entry in PR's native stack.\n When omitted, pr-shepherd infers the current branch's pull request.\n\nCommon flags:\n --transport auto|graphql|rest Select GitHub transport. Default: github.transport (auto).\n --format text|json Output Markdown text or JSON. Default: text.\n --verbose Include verbose iterate fields and detailed poll-tick lines.\n --help, -h Print help and exit before any GitHub, git, config, or log I/O.\n\nIterate flags:\n --ready-delay <duration> Settle window before a clean PR cancels. Bare number = minutes. Example: 15m.\n --stall-timeout <duration> Escalate repeated unchanged failures after this duration. Bare number = minutes. 0 disables.\n --no-auto-mark-ready Leave draft PRs in draft; stop when otherwise ready.\n --no-auto-cancel-actionable Legacy no-op; workflow runs are never cancelled.\n --merge Shepherd through readiness, then emit a merge or merge-queue command.\n --instructions playbook|inline Render fix_code steps inline every tick (default) or fold the invariant ones into a playbook pointer. Default: iterate.instructions (inline).\n\nPolling flags:\n --interval <duration> Delay between WAIT ticks. Bare number = seconds. Default: poll.intervalSeconds (built-in 60s). Stack and multi-PR polls multiply that by poll.stackIntervalFactor (built-in 2) unless this flag is set.\n --timeout <duration> Poll wall-clock cap for WAIT ticks. Bare number = seconds. Default: poll.timeoutSeconds (built-in 4.5m).\n --debounce <duration> Settle window after first FIX_CODE or stack SHEPHERD before returning. Bare number = seconds. Default: poll.debounceSeconds (built-in 60s). 0 disables.\n --quiet-status Print only changed WAIT snapshots. Overrides poll.quietStatus.\n --no-quiet-status Print every WAIT snapshot. Overrides poll.quietStatus.\n --until-terminal Continue through WAIT/MARK_READY until READY/FIX_CODE/MERGE/CANCEL/ESCALATE or stack SHEPHERD.\n\nClean variants:\n pr [number] Remove state for one PR. Defaults to current branch PR.\n branch [name] Remove state for a branch's PR. Defaults to current branch.\n current Alias for branch against the current branch.\n repo Remove all state for the current repository.\n all Remove all pr-shepherd state.\n\nExit codes: 0 done, 10-19 PR state, 64-78 shepherd failed (sysexits.h).\n 0 CANCEL (merged, ready-delay elapsed, or clean draft left in draft by disabled auto mark-ready)\n 10 WAIT or READY\n 11 MARK_READY\n 12 FIX_CODE\n 13 ESCALATE\n 14 CANCEL (closed without merging)\n 15 MERGE\n 16 SHEPHERD (--stack only: run the listed one-PR sessions, then rerun the selector)\nSee docs/exit-codes.md for the full sysexits.h error-code table.\n\nDuration examples: 30s, 4.5m, 1h. A bare number uses each flag's default unit (see above); decimals are allowed with an explicit unit (4.5m).\n\nRun 'pr-shepherd <command> --help' for command-specific details.";
|
|
340
340
|
};
|
|
341
341
|
/** Resolve help keys for nested public commands before any command I/O. */
|
|
342
342
|
export declare function helpKeyForArgs(args: string[]): keyof typeof USAGE;
|
|
@@ -1,10 +1,7 @@
|
|
|
1
1
|
import { inlineCode } from "../util/markdown.mjs";
|
|
2
2
|
import { buildQuotaAwareContinuation } from "../quota-warning.mjs";
|
|
3
|
-
import {
|
|
4
|
-
import { AUTO_MARK_READY_DISABLED_HOLD } from "../commands/stack-work.mjs";
|
|
5
|
-
import { buildPrShepherdCommand, renderShellCommand } from "./runner.mjs";
|
|
3
|
+
import { renderShellCommand } from "./runner.mjs";
|
|
6
4
|
import { eventWaitSteps } from "../commands/event-instructions.mjs";
|
|
7
|
-
import { playbookPointer } from "../commands/playbook-pointer.mjs";
|
|
8
5
|
export function buildSimpleIterateInstructions(result) {
|
|
9
6
|
switch (result.action) {
|
|
10
7
|
case "ready": {
|
|
@@ -20,8 +17,6 @@ export function buildSimpleIterateInstructions(result) {
|
|
|
20
17
|
];
|
|
21
18
|
}
|
|
22
19
|
case "wait":
|
|
23
|
-
if (result.stackDraftHold)
|
|
24
|
-
return buildStackDraftHoldInstructions(result, result.stackDraftHold);
|
|
25
20
|
if (result.nextCheck) {
|
|
26
21
|
return ["Non-terminal — no action needed this tick.", ...eventWaitSteps(result.nextCheck)];
|
|
27
22
|
}
|
|
@@ -85,31 +80,6 @@ export function buildSimpleIterateInstructions(result) {
|
|
|
85
80
|
}
|
|
86
81
|
}
|
|
87
82
|
}
|
|
88
|
-
/**
|
|
89
|
-
* A held stack draft cannot advance by repeating its one-PR session, so hand control back
|
|
90
|
-
* to the stack selector instead of asking for another immediate iteration.
|
|
91
|
-
*/
|
|
92
|
-
function buildStackDraftHoldInstructions(result, hold) {
|
|
93
|
-
const event = result.pollMode === "event";
|
|
94
|
-
const stackCommand = buildPrShepherdCommand([
|
|
95
|
-
"--stack",
|
|
96
|
-
formatPrUrl(result.repo, result.pr),
|
|
97
|
-
"--until-terminal",
|
|
98
|
-
...(event ? ["--poll-mode", "event"] : []),
|
|
99
|
-
]).text;
|
|
100
|
-
const handoff = `a \`--stack\` selector listed this session, finish that selector's remaining steps and rerun it with its original flags; otherwise run ${inlineCode(stackCommand)}, adding \`--merge\` when merging was requested.`;
|
|
101
|
-
const reason = hold.kind === "auto-mark-ready-disabled" ? AUTO_MARK_READY_DISABLED_HOLD : hold.kind;
|
|
102
|
-
const instruction = `PR #${result.pr} stays in draft because ${reason}, so repeating this one-PR session cannot advance it. If ${handoff}`;
|
|
103
|
-
const step = result.quotaWarning
|
|
104
|
-
? buildQuotaAwareContinuation(result.quotaWarning, instruction)
|
|
105
|
-
: instruction;
|
|
106
|
-
if (!event)
|
|
107
|
-
return [step];
|
|
108
|
-
return [
|
|
109
|
-
step,
|
|
110
|
-
`Event mode: do not rerun this one-PR session and keep no wake-up for it. After the handoff, follow only the stack selector's output; it ends the turn and schedules the next tick through its own \`nextCheck\`. ${playbookPointer("Cloud event loop")}`,
|
|
111
|
-
];
|
|
112
|
-
}
|
|
113
83
|
export function adaptIterateLog(log) {
|
|
114
84
|
return log.replace(/\s+—\s+\d+s until auto-cancel/g, "");
|
|
115
85
|
}
|
package/bin/cli/iterate-lean.mjs
CHANGED
|
@@ -119,7 +119,6 @@ export function projectIterateLean(result, opts) {
|
|
|
119
119
|
...(result.deferredWork && {
|
|
120
120
|
deferredWork: Object.fromEntries(Object.entries(result.deferredWork).filter(([, n]) => n > 0)),
|
|
121
121
|
}),
|
|
122
|
-
...(result.stackDraftHold && { stackDraftHold: result.stackDraftHold }),
|
|
123
122
|
log: adaptIterateLog(result.log),
|
|
124
123
|
instructions: simpleInstructions(result),
|
|
125
124
|
};
|
|
@@ -4,7 +4,7 @@ import { runWithDurableState } from "../state/durable-state.mjs";
|
|
|
4
4
|
import { eventAggregateStep, eventFixContinuation } from "./event-instructions.mjs";
|
|
5
5
|
import { earliestNextCheck, MERGE_QUEUE_RECHECK_SECONDS, nextCheckCandidates, SAFETY_NET_SECONDS, } from "./next-check.mjs";
|
|
6
6
|
import { isFixCodeContinuation } from "./iterate/check-instructions.mjs";
|
|
7
|
-
import { isHandedOffSelection } from "./poll-summary-explicit-instructions.mjs";
|
|
7
|
+
import { isHandedOffSelection, onlyDraftVerificationSelection, } from "./poll-summary-explicit-instructions.mjs";
|
|
8
8
|
import { runIterate } from "./iterate/index.mjs";
|
|
9
9
|
import { resolvePollMode } from "./poll-mode.mjs";
|
|
10
10
|
import { readStackStallDeadline } from "./stack-stall.mjs";
|
|
@@ -56,7 +56,6 @@ async function runIterateEvent(opts) {
|
|
|
56
56
|
remainingSeconds: result.remainingSeconds,
|
|
57
57
|
queued: result.mergeQueue?.inQueue === true,
|
|
58
58
|
restMerge: result.action === "merge" && result.merge.mode === "rest",
|
|
59
|
-
stackDraftHold: result.action === "wait" && result.stackDraftHold !== undefined,
|
|
60
59
|
stallDeadlineSeconds,
|
|
61
60
|
}, nowMs), nowMs);
|
|
62
61
|
const tagged = { ...result, pollMode: "event", ...(nextCheck && { nextCheck }) };
|
|
@@ -102,11 +101,7 @@ async function withAggregateNextCheck(result, opts) {
|
|
|
102
101
|
],
|
|
103
102
|
};
|
|
104
103
|
}
|
|
105
|
-
/**
|
|
106
|
-
* Event mode replaces polling: the appended event step owns the next wake-up, so a stack
|
|
107
|
-
* step's "recheck at the configured polling cadence" would contradict it. A pending stack
|
|
108
|
-
* merge resumes on that wake-up instead.
|
|
109
|
-
*/
|
|
104
|
+
/** The appended event step owns timing, including pending stack merges. */
|
|
110
105
|
function withoutPollingCadence(step) {
|
|
111
106
|
return step
|
|
112
107
|
.replace(/ Recheck(?: them)? at the configured polling cadence\./g, "")
|
|
@@ -114,6 +109,7 @@ function withoutPollingCadence(step) {
|
|
|
114
109
|
}
|
|
115
110
|
function aggregateNextCheck(result, stallDeadlineSeconds) {
|
|
116
111
|
if (isHandedOffSelection(result) ||
|
|
112
|
+
(onlyDraftVerificationSelection(result) && result.nextAction !== "merge") ||
|
|
117
113
|
result.reason === "all_terminal" ||
|
|
118
114
|
result.nextAction === "cancel" ||
|
|
119
115
|
result.nextAction === "escalate") {
|
|
@@ -23,7 +23,6 @@ import { fingerprintRawSummaryPr } from "../../github/poll-summary-fingerprint.m
|
|
|
23
23
|
import { currentQueueRemovalEvent } from "../../github/poll-summary-queue-removal.mjs";
|
|
24
24
|
import { isCurrentSummaryReady } from "../../github/poll-summary-readiness.mjs";
|
|
25
25
|
import { clearReadyReceipt, isReadyReceiptCurrent, readReadyReceipt, writeReadyReceipt, } from "../../state/ready-receipts.mjs";
|
|
26
|
-
import { stackDraftHold } from "./parent-first.mjs";
|
|
27
26
|
import { findStaleNativeStackAncestry } from "./stale-ancestry.mjs";
|
|
28
27
|
import { annotateBlockedWait, resolveCheckBlockerGate } from "./check-blocker-gate.mjs";
|
|
29
28
|
import { buildUnreportedFixResult, planUnreportedRequired } from "./unreported-required.mjs";
|
|
@@ -261,6 +260,18 @@ async function runIterateCore(opts) {
|
|
|
261
260
|
};
|
|
262
261
|
}
|
|
263
262
|
const autoMarkReady = !opts.noAutoMarkReady && config.actions.autoMarkReady;
|
|
263
|
+
if (canMarkReady && !autoMarkReady) {
|
|
264
|
+
await clearReadyDelay(report.pr, repoOwner, repoName);
|
|
265
|
+
await clearStallState(stallKey);
|
|
266
|
+
return {
|
|
267
|
+
...base,
|
|
268
|
+
action: "cancel",
|
|
269
|
+
reason: "auto-mark-ready-disabled",
|
|
270
|
+
shouldCancel: false,
|
|
271
|
+
remainingSeconds: 0,
|
|
272
|
+
log: `CANCEL: PR #${base.pr} stays in draft because automatic mark-ready is disabled — stopping`,
|
|
273
|
+
};
|
|
274
|
+
}
|
|
264
275
|
const markReadyResult = await markReadyIfAuthorized(canMarkReady && autoMarkReady, base, report);
|
|
265
276
|
if (markReadyResult)
|
|
266
277
|
return markReadyResult;
|
|
@@ -310,12 +321,10 @@ async function runIterateCore(opts) {
|
|
|
310
321
|
log: `READY: PR #${base.pr} is ready — ${readyState.remainingSeconds}s of ready-delay remaining — ${buildWaitLog(base).slice("WAIT: ".length)}`,
|
|
311
322
|
};
|
|
312
323
|
}
|
|
313
|
-
const hold = stackDraftHold(report, autoMarkReady);
|
|
314
324
|
const wait = {
|
|
315
325
|
...base,
|
|
316
326
|
action: "wait",
|
|
317
327
|
log: buildWaitLog(base),
|
|
318
|
-
...(hold && { stackDraftHold: hold }),
|
|
319
328
|
};
|
|
320
329
|
return annotateBlockedWait(await applyStallGuard(stallKey, stallTimeoutSeconds, headSha, base, prNumber, wait, reportForWork, reviewSummaryIds, opts.stallDeadlineSink), blockerGate);
|
|
321
330
|
}
|
|
@@ -17,8 +17,6 @@ interface NextCheckFacts {
|
|
|
17
17
|
queued?: boolean;
|
|
18
18
|
/** A `merge` tick whose printed command is a REST merge request, which can stay `pending`. */
|
|
19
19
|
restMerge?: boolean;
|
|
20
|
-
/** A native-stack draft hold: repeating this one-PR session cannot advance it. */
|
|
21
|
-
stackDraftHold?: boolean;
|
|
22
20
|
/** Unix seconds when an unchanged state would trip the stall timeout. */
|
|
23
21
|
stallDeadlineSeconds?: number;
|
|
24
22
|
}
|
|
@@ -24,7 +24,7 @@ export function nextCheckCandidates(facts, nowMs) {
|
|
|
24
24
|
return [{ reason: "merge-pending", seconds: MERGE_QUEUE_RECHECK_SECONDS }];
|
|
25
25
|
}
|
|
26
26
|
const terminal = ["cancel", "escalate", "merge", "mark_ready"].includes(facts.action);
|
|
27
|
-
if (terminal
|
|
27
|
+
if (terminal)
|
|
28
28
|
return [];
|
|
29
29
|
const candidates = [];
|
|
30
30
|
if (facts.action === "ready" && (facts.remainingSeconds ?? 0) > 0) {
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import type { PollSummaryResult } from "../types.mts";
|
|
2
2
|
/** Every selected row already returned `CANCEL` or `ESCALATE`: no autonomous work remains. */
|
|
3
3
|
export declare function isHandedOffSelection(result: PollSummaryResult): boolean;
|
|
4
|
+
/** A final full-review probe can finish this selection without another aggregate read. */
|
|
5
|
+
export declare function onlyDraftVerificationSelection(result: PollSummaryResult): boolean;
|
|
4
6
|
export declare function explicitInstructions(result: PollSummaryResult): string[];
|
|
@@ -1,12 +1,24 @@
|
|
|
1
1
|
import { buildQuotaAwareContinuation } from "../quota-warning.mjs";
|
|
2
|
+
import { isDraftReadinessVerification } from "./stack-work.mjs";
|
|
2
3
|
/** Every selected row already returned `CANCEL` or `ESCALATE`: no autonomous work remains. */
|
|
3
4
|
export function isHandedOffSelection(result) {
|
|
4
5
|
return (result.prs.length > 0 &&
|
|
5
6
|
result.prs.every((item) => item.action === "cancel" || item.action === "escalate"));
|
|
6
7
|
}
|
|
8
|
+
/** A final full-review probe can finish this selection without another aggregate read. */
|
|
9
|
+
export function onlyDraftVerificationSelection(result) {
|
|
10
|
+
return (result.prs.some(isDraftReadinessVerification) &&
|
|
11
|
+
result.prs.every((item) => item.action === "cancel" ||
|
|
12
|
+
item.action === "escalate" ||
|
|
13
|
+
isDraftReadinessVerification(item)));
|
|
14
|
+
}
|
|
7
15
|
export function explicitInstructions(result) {
|
|
8
16
|
if (result.reason === "all_terminal")
|
|
9
|
-
return [
|
|
17
|
+
return [
|
|
18
|
+
result.prs.some((item) => item.reasons.includes("draft-auto-mark-ready-disabled"))
|
|
19
|
+
? "1. Stop — every selected PR is complete for this Shepherd run."
|
|
20
|
+
: "1. Stop — every selected PR is terminal.",
|
|
21
|
+
];
|
|
10
22
|
if (result.quotaWarning && result.reason !== "actionable") {
|
|
11
23
|
return [
|
|
12
24
|
buildQuotaAwareContinuation(result.quotaWarning, "1. This aggregate selection is non-terminal. Before continuing,"),
|
|
@@ -20,7 +32,11 @@ export function explicitInstructions(result) {
|
|
|
20
32
|
"2. Follow each selected one-PR poll's `## Instructions` until it returns `CANCEL` or `ESCALATE`.",
|
|
21
33
|
"3. Run this aggregate poll again after selected work completes; one row's `ESCALATE` does not stop work on other rows.",
|
|
22
34
|
];
|
|
23
|
-
if (
|
|
35
|
+
if (onlyDraftVerificationSelection(result)) {
|
|
36
|
+
instructions[2] =
|
|
37
|
+
"3. If every draft verification probe returns `[CANCEL]` with reason `auto-mark-ready-disabled`, stop this selection and report any `ESCALATE` rows; leave the drafts unchanged. If any probe returns `[ESCALATE]`, report that handoff and stop after the other probes finish. Otherwise follow the probes' instructions and rerun this aggregate selector when that work completes.";
|
|
38
|
+
}
|
|
39
|
+
else if (isHandedOffSelection(result)) {
|
|
24
40
|
instructions[2] =
|
|
25
41
|
"3. Stop after reporting each `ESCALATE` handoff; every selected row is `CANCEL` or `ESCALATE`, so do not run this aggregate poll again.";
|
|
26
42
|
}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { buildQuotaAwareContinuation } from "../quota-warning.mjs";
|
|
3
3
|
import { explicitInstructions } from "./poll-summary-explicit-instructions.mjs";
|
|
4
4
|
import { appendAutonomousInstructions, appendHumanHandoffInstructions, findHumanHandoffs, idleWaitPlan, isStackLayerReady, planPrefixDrain, retargetWaitPlan, stackPosition, } from "./stack-drain.mjs";
|
|
5
|
-
import {
|
|
5
|
+
import { appendStackRerunInstruction, onlyDraftReadinessVerification, splitStackWork, } from "./stack-work.mjs";
|
|
6
6
|
/** Keep aggregate JSON, Markdown, and MCP instructions on one projection. */
|
|
7
7
|
export function withPollSummaryInstructions(result, mergeRequested) {
|
|
8
8
|
return planPollSummary(result, mergeRequested).result;
|
|
@@ -19,7 +19,8 @@ export function planPollSummary(result, mergeRequested) {
|
|
|
19
19
|
prs: prs.map((item) => {
|
|
20
20
|
const needsOwnSession = item.state === "OPEN" &&
|
|
21
21
|
(!isStackLayerReady(item) || staleChildren.has(item.pr)) &&
|
|
22
|
-
["cancel", "merge"].includes(item.action)
|
|
22
|
+
["cancel", "merge"].includes(item.action) &&
|
|
23
|
+
(!item.reasons.includes("draft-auto-mark-ready-disabled") || staleChildren.has(item.pr));
|
|
23
24
|
const layer = needsOwnSession
|
|
24
25
|
? {
|
|
25
26
|
...item,
|
|
@@ -51,6 +52,11 @@ export function planPollSummary(result, mergeRequested) {
|
|
|
51
52
|
reasons: [...layer.reasons, "unverified-stack-state"],
|
|
52
53
|
};
|
|
53
54
|
}
|
|
55
|
+
if (layer.reasons.includes("draft-auto-mark-ready-disabled") &&
|
|
56
|
+
!staleChildren.has(layer.pr)) {
|
|
57
|
+
const { pollCommand: _pollCommand, pollProbe: _pollProbe, ...held } = layer;
|
|
58
|
+
return held;
|
|
59
|
+
}
|
|
54
60
|
return layer;
|
|
55
61
|
}),
|
|
56
62
|
};
|
|
@@ -84,9 +90,9 @@ function planStack(result, mergeRequested) {
|
|
|
84
90
|
const work = splitStackWork(open.filter((item) => (!isStackLayerReady(item) || staleChildren.has(item.pr)) && item.action !== "escalate"), staleChildren);
|
|
85
91
|
const runnableCandidates = work.sessions.filter((item) => item.pollCommand);
|
|
86
92
|
const missingCommands = work.sessions.filter((item) => !item.pollCommand);
|
|
87
|
-
const agentWork = runnableCandidates.length > 0
|
|
93
|
+
const agentWork = runnableCandidates.length > 0;
|
|
88
94
|
// Only owned work defers a human handoff: rerunning cannot advance another author's layer.
|
|
89
|
-
const ownedWork =
|
|
95
|
+
const ownedWork = runnableCandidates.some((item) => item.owned);
|
|
90
96
|
const drain = planPrefixDrain(result, mergeRequested);
|
|
91
97
|
if (drain)
|
|
92
98
|
return drain;
|
|
@@ -94,14 +100,17 @@ function planStack(result, mergeRequested) {
|
|
|
94
100
|
if (handoffs) {
|
|
95
101
|
const instructions = [];
|
|
96
102
|
appendAutonomousInstructions(instructions, runnableCandidates);
|
|
97
|
-
appendMarkReadyInstructions(instructions, work.markReady);
|
|
98
103
|
const stop = !ownedWork;
|
|
99
104
|
appendHumanHandoffInstructions(instructions, handoffs, stop);
|
|
100
105
|
for (const item of missingCommands) {
|
|
101
106
|
instructions.push(`${instructions.length + 1}. PR #${item.pr} needs a one-PR session, but Shepherd could not produce its command. Ask for direction.`);
|
|
102
107
|
}
|
|
103
108
|
if (ownedWork) {
|
|
104
|
-
|
|
109
|
+
const rerun = onlyDraftReadinessVerification(work.sessions, work.idle) &&
|
|
110
|
+
work.sessions.every((item) => item.owned)
|
|
111
|
+
? "If every listed one-PR probe returns `[CANCEL]` with reason `auto-mark-ready-disabled`, report the human handoff above and stop this selector. If any probe returns `[ESCALATE]`, report that handoff and stop after the other probes finish. Otherwise follow each probe's instructions and rerun this same `--stack` selector when that work completes."
|
|
112
|
+
: "After the listed one-PR sessions, rerun this same `--stack` selector. Stop for the human handoff only when no autonomous shepherding remains.";
|
|
113
|
+
appendStackRerunInstruction(instructions, runnableCandidates, rerun);
|
|
105
114
|
}
|
|
106
115
|
return { action: stop ? "escalate" : "shepherd", stackMergeable: false, instructions };
|
|
107
116
|
}
|
|
@@ -116,21 +125,34 @@ function planStack(result, mergeRequested) {
|
|
|
116
125
|
if (missingCommands.length > 0) {
|
|
117
126
|
const instructions = [];
|
|
118
127
|
appendAutonomousInstructions(instructions, runnableCandidates);
|
|
119
|
-
appendMarkReadyInstructions(instructions, work.markReady);
|
|
120
128
|
for (const item of missingCommands) {
|
|
121
129
|
instructions.push(`${instructions.length + 1}. PR #${item.pr} needs a one-PR session, but Shepherd could not produce its command. ${ownedWork ? "After autonomous shepherding, ask" : "Stop and ask"} for direction.`);
|
|
122
130
|
}
|
|
123
131
|
if (ownedWork) {
|
|
124
|
-
appendStackRerunInstruction(instructions,
|
|
132
|
+
appendStackRerunInstruction(instructions, runnableCandidates, "After the listed one-PR sessions, rerun this same `--stack` selector. Stop for the human handoff only when no autonomous shepherding remains.");
|
|
125
133
|
}
|
|
126
134
|
return { action: ownedWork ? "shepherd" : "escalate", stackMergeable: false, instructions };
|
|
127
135
|
}
|
|
128
|
-
if (!agentWork)
|
|
136
|
+
if (!agentWork) {
|
|
137
|
+
if (work.held.length > 0 && work.idle.length === 0) {
|
|
138
|
+
return {
|
|
139
|
+
action: "cancel",
|
|
140
|
+
stackMergeable: false,
|
|
141
|
+
instructions: [
|
|
142
|
+
`1. Stop shepherding this stack. Automatic mark-ready is disabled and ${work.held.map((item) => `PR #${item.pr}`).join(", ")} ${work.held.length === 1 ? "is" : "are"} clean but still in draft.`,
|
|
143
|
+
],
|
|
144
|
+
};
|
|
145
|
+
}
|
|
129
146
|
return idleWaitPlan(work.idle);
|
|
147
|
+
}
|
|
130
148
|
const instructions = [];
|
|
131
149
|
appendAutonomousInstructions(instructions, work.sessions);
|
|
132
|
-
|
|
133
|
-
|
|
150
|
+
if (onlyDraftReadinessVerification(work.sessions, work.idle) &&
|
|
151
|
+
work.sessions.every((item) => item.owned)) {
|
|
152
|
+
instructions.push(`${instructions.length + 1}. If every listed one-PR probe returns \`[CANCEL]\` with reason \`auto-mark-ready-disabled\`, stop shepherding this stack and leave those drafts unchanged. If any probe returns \`[ESCALATE]\`, report that handoff and stop after the other probes finish. Otherwise follow each probe's instructions and rerun this same \`--stack\` selector when that work completes.`);
|
|
153
|
+
return { action: "shepherd", stackMergeable: false, instructions };
|
|
154
|
+
}
|
|
155
|
+
const action = appendStackRerunInstruction(instructions, work.sessions, "After the selected one-PR sessions, rerun this same `--stack` selector.");
|
|
134
156
|
return { action, stackMergeable: false, instructions };
|
|
135
157
|
}
|
|
136
158
|
if (open.some((item) => item.isInMergeQueue)) {
|
|
@@ -2,7 +2,7 @@ import { findHumanHandoffs, appendHumanHandoffInstructions } from "./stack-hando
|
|
|
2
2
|
export { findHumanHandoffs, appendHumanHandoffInstructions } from "./stack-handoffs.mjs";
|
|
3
3
|
import { stackMergeFlag } from "./stack-merge-flag.mjs";
|
|
4
4
|
import { stackLayerBlockReason } from "./stack-layer-readiness.mjs";
|
|
5
|
-
import {
|
|
5
|
+
import { splitStackWork } from "./stack-work.mjs";
|
|
6
6
|
import { getGithubTransport } from "../github/transport.mjs";
|
|
7
7
|
import { buildMergeCommandPlan, renderMergeCommand } from "./iterate/merge.mjs";
|
|
8
8
|
function readyPrefixTop(result) {
|
|
@@ -89,7 +89,6 @@ export function planPrefixDrain(result, mergeRequested) {
|
|
|
89
89
|
instructions[0] = `1. PR #${top.pr} is the highest open layer of stack #${top.stack.number} in \`${result.repo}\` whose open lower layers are all ready. Run \`GH_REPO=${result.repo} gh stack merge ${top.pr} --yes ${method.flag}\` to merge ${span}. If \`gh stack\` is an unknown command, run \`gh extension install github/gh-stack\`, then rerun that merge command. Do not rebase, push, or run \`gh stack push\`.`;
|
|
90
90
|
}
|
|
91
91
|
appendAutonomousInstructions(instructions, above.sessions);
|
|
92
|
-
appendMarkReadyInstructions(instructions, above.markReady);
|
|
93
92
|
const handoffs = findHumanHandoffs(result);
|
|
94
93
|
if (handoffs)
|
|
95
94
|
appendHumanHandoffInstructions(instructions, handoffs, false);
|
|
@@ -1,37 +1,24 @@
|
|
|
1
1
|
import type { PollSummaryItem } from "../types.mts";
|
|
2
|
-
type ProbedLayer = PollSummaryItem & {
|
|
3
|
-
pollCommand: string;
|
|
4
|
-
pollProbe: true;
|
|
5
|
-
};
|
|
6
|
-
/**
|
|
7
|
-
* The one-PR hold reason for a `READY` draft that only the disabled setting keeps in draft. The
|
|
8
|
-
* probe re-reads the draft, so this phrase, not a bare `[WAIT]`, proves it is still clean.
|
|
9
|
-
*/
|
|
10
|
-
export declare const AUTO_MARK_READY_DISABLED_HOLD = "automatic mark-ready is disabled for this session";
|
|
11
2
|
/** How the stack selector routes the autonomous layers that still need work. */
|
|
12
3
|
export interface StackWork {
|
|
13
4
|
/** Layers that need a one-PR Shepherd session, with or without a known command. */
|
|
14
5
|
sessions: PollSummaryItem[];
|
|
15
|
-
/** Clean
|
|
16
|
-
|
|
6
|
+
/** Clean drafts held by the disabled ready transition. No more work is scheduled for them. */
|
|
7
|
+
held: PollSummaryItem[];
|
|
17
8
|
/** Layers whose bounded probe could only report that they are still waiting. */
|
|
18
|
-
idle:
|
|
9
|
+
idle: PollSummaryItem[];
|
|
19
10
|
}
|
|
11
|
+
export declare function isDraftReadinessVerification(item: PollSummaryItem): boolean;
|
|
12
|
+
/** A full one-PR check is the final task when the compact review sample was incomplete. */
|
|
13
|
+
export declare function onlyDraftReadinessVerification(sessions: PollSummaryItem[], idle: PollSummaryItem[]): boolean;
|
|
20
14
|
/**
|
|
21
|
-
* Split autonomous stack candidates by what the agent can do for each. A
|
|
22
|
-
* mark
|
|
23
|
-
* kept in draft only by the disabled mark-ready setting is the agent's ready-for-review step.
|
|
15
|
+
* Split autonomous stack candidates by what the agent can do for each. A clean draft held by
|
|
16
|
+
* disabled mark-ready is complete for this run. Other bounded waits stay idle.
|
|
24
17
|
* A stale-ancestry child keeps its session, which returns the ancestry repair.
|
|
25
18
|
*/
|
|
26
19
|
export declare function splitStackWork(candidates: PollSummaryItem[], staleChildren: ReadonlySet<number>): StackWork;
|
|
27
|
-
/**
|
|
28
|
-
* The poll loop leaves a disabled draft's ready transition to the agent. The bounded probe runs
|
|
29
|
-
* first because only the one-PR session reads the full review context.
|
|
30
|
-
*/
|
|
31
|
-
export declare function appendMarkReadyInstructions(instructions: string[], layers: ProbedLayer[]): void;
|
|
32
20
|
/**
|
|
33
21
|
* The closing step after routed sessions: rerun the selector, or stop when nothing is owned.
|
|
34
22
|
* Returns the plan action: a stop is a handoff, so no rerun, quota cadence, or wake-up follows it.
|
|
35
23
|
*/
|
|
36
24
|
export declare function appendStackRerunInstruction(instructions: string[], layers: PollSummaryItem[], rerun: string): "shepherd" | "escalate";
|
|
37
|
-
export {};
|
|
@@ -1,24 +1,23 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
1
|
+
export function isDraftReadinessVerification(item) {
|
|
2
|
+
return item.reasons?.includes("draft-readiness-verification-required") === true;
|
|
3
|
+
}
|
|
4
|
+
/** A full one-PR check is the final task when the compact review sample was incomplete. */
|
|
5
|
+
export function onlyDraftReadinessVerification(sessions, idle) {
|
|
6
|
+
return sessions.length > 0 && idle.length === 0 && sessions.every(isDraftReadinessVerification);
|
|
7
|
+
}
|
|
8
8
|
/**
|
|
9
|
-
* Split autonomous stack candidates by what the agent can do for each. A
|
|
10
|
-
* mark
|
|
11
|
-
* kept in draft only by the disabled mark-ready setting is the agent's ready-for-review step.
|
|
9
|
+
* Split autonomous stack candidates by what the agent can do for each. A clean draft held by
|
|
10
|
+
* disabled mark-ready is complete for this run. Other bounded waits stay idle.
|
|
12
11
|
* A stale-ancestry child keeps its session, which returns the ancestry repair.
|
|
13
12
|
*/
|
|
14
13
|
export function splitStackWork(candidates, staleChildren) {
|
|
15
|
-
const work = { sessions: [],
|
|
14
|
+
const work = { sessions: [], held: [], idle: [] };
|
|
16
15
|
for (const item of candidates) {
|
|
17
|
-
if (
|
|
18
|
-
work.
|
|
16
|
+
if (item.reasons.includes("draft-auto-mark-ready-disabled") && !staleChildren.has(item.pr)) {
|
|
17
|
+
work.held.push(item);
|
|
19
18
|
}
|
|
20
|
-
else if (item.
|
|
21
|
-
work.
|
|
19
|
+
else if (!isProbed(item) || item.action !== "wait" || staleChildren.has(item.pr)) {
|
|
20
|
+
work.sessions.push(item);
|
|
22
21
|
}
|
|
23
22
|
else {
|
|
24
23
|
work.idle.push(item);
|
|
@@ -26,29 +25,6 @@ export function splitStackWork(candidates, staleChildren) {
|
|
|
26
25
|
}
|
|
27
26
|
return work;
|
|
28
27
|
}
|
|
29
|
-
/**
|
|
30
|
-
* The poll loop leaves a disabled draft's ready transition to the agent. The bounded probe runs
|
|
31
|
-
* first because only the one-PR session reads the full review context.
|
|
32
|
-
*/
|
|
33
|
-
export function appendMarkReadyInstructions(instructions, layers) {
|
|
34
|
-
for (const item of layers) {
|
|
35
|
-
if (!item.owned) {
|
|
36
|
-
instructions.push(`${instructions.length + 1}. PR #${item.pr} is not owned. Leave its draft state unchanged.`);
|
|
37
|
-
continue;
|
|
38
|
-
}
|
|
39
|
-
if (item.transport === "rest") {
|
|
40
|
-
const command = buildPrShepherdCommand([
|
|
41
|
-
"iterate",
|
|
42
|
-
formatPrUrl(item.repo, item.pr),
|
|
43
|
-
"--transport",
|
|
44
|
-
"rest",
|
|
45
|
-
]).text;
|
|
46
|
-
instructions.push(`${instructions.length + 1}. Run \`${item.pollCommand}\` first for PR #${item.pr}. If it returns \`[WAIT]\` saying the draft is held only because automatic mark-ready is disabled, run \`${command}\` to authorize the CCR ready transition; otherwise follow the probe's instructions.`);
|
|
47
|
-
continue;
|
|
48
|
-
}
|
|
49
|
-
instructions.push(`${instructions.length + 1}. Automatic mark-ready is disabled, so marking PR #${item.pr} ready for review is your step. Run \`${item.pollCommand}\` first. If it returns \`[WAIT]\` saying PR #${item.pr} stays in draft because ${AUTO_MARK_READY_DISABLED_HOLD}, run \`gh pr ready ${item.pr} -R ${item.repo}\`; otherwise complete its instructions and leave PR #${item.pr} in draft this round.`);
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
28
|
function isProbed(item) {
|
|
53
29
|
return item.pollProbe === true && item.pollCommand !== undefined;
|
|
54
30
|
}
|
package/bin/exit-codes.d.mts
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
import type { IterateResult } from "./types.mts";
|
|
13
13
|
import type { ResolveResult } from "./comments/resolve.mts";
|
|
14
14
|
export declare const EXIT: Readonly<{
|
|
15
|
-
/**
|
|
15
|
+
/** Clean terminal stop, including a draft held by disabled automatic mark-ready. */
|
|
16
16
|
readonly OK: 0;
|
|
17
17
|
/** Nothing to do yet, or a clean PR whose ready-delay is still counting. */
|
|
18
18
|
readonly WAIT: 10;
|
package/bin/exit-codes.mjs
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* ran to completion and is reporting PR state. See docs/exit-codes.md.
|
|
11
11
|
*/
|
|
12
12
|
export const EXIT = Object.freeze({
|
|
13
|
-
/**
|
|
13
|
+
/** Clean terminal stop, including a draft held by disabled automatic mark-ready. */
|
|
14
14
|
OK: 0,
|
|
15
15
|
/** Nothing to do yet, or a clean PR whose ready-delay is still counting. */
|
|
16
16
|
WAIT: 10,
|
|
@@ -55,6 +55,7 @@ export class ShepherdError extends Error {
|
|
|
55
55
|
const CANCEL_REASON_EXIT_CODE = {
|
|
56
56
|
merged: EXIT.OK,
|
|
57
57
|
"ready-delay-elapsed": EXIT.OK,
|
|
58
|
+
"auto-mark-ready-disabled": EXIT.OK,
|
|
58
59
|
closed: EXIT.CLOSED,
|
|
59
60
|
};
|
|
60
61
|
export function iterateResultToExitCode(result) {
|
|
@@ -28,7 +28,9 @@ export async function summarizePollSummaryPr(raw, repo, opts, viewerCanAdministe
|
|
|
28
28
|
let remainingSeconds;
|
|
29
29
|
if (raw.isDraft &&
|
|
30
30
|
blockingReviewerInProgress &&
|
|
31
|
-
(action === "mark_ready" ||
|
|
31
|
+
(action === "mark_ready" ||
|
|
32
|
+
reasons.includes("draft-auto-mark-ready-disabled") ||
|
|
33
|
+
reasons.includes("draft-readiness-verification-required"))) {
|
|
32
34
|
action = "wait";
|
|
33
35
|
reasons = ["blocking-reviewer-in-progress"];
|
|
34
36
|
}
|
|
@@ -40,18 +40,17 @@ export function routePollSummary(raw, checks, review, opts) {
|
|
|
40
40
|
}
|
|
41
41
|
if (raw.isDraft) {
|
|
42
42
|
const autoMarkReadyDisabled = opts.noAutoMarkReady || actions.autoMarkReady === false;
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
if (
|
|
46
|
-
|
|
43
|
+
if (autoMarkReadyDisabled && (checks.incomplete || review.incomplete))
|
|
44
|
+
return { action: "fix_code", reasons: ["draft-readiness-verification-required"] };
|
|
45
|
+
if (autoMarkReadyDisabled)
|
|
46
|
+
return { action: "cancel", reasons: ["draft-auto-mark-ready-disabled"] };
|
|
47
|
+
if (!canGenerateGithubMutation(raw.viewerCanUpdate, "ready")) {
|
|
47
48
|
const unsupported = getGithubTransport() === "rest" && raw.viewerCanUpdate !== false && !isCcrTransport();
|
|
48
49
|
if (unsupported)
|
|
49
50
|
return { action: "escalate", reasons: ["transport-unsupported"] };
|
|
50
51
|
return { action: "escalate", reasons: ["mark-ready-authorization-required"] };
|
|
51
52
|
}
|
|
52
|
-
return
|
|
53
|
-
? { action: "wait", reasons: ["draft-auto-mark-ready-disabled"] }
|
|
54
|
-
: { action: "mark_ready", reasons: ["draft-appears-ready"] };
|
|
53
|
+
return { action: "mark_ready", reasons: ["draft-appears-ready"] };
|
|
55
54
|
}
|
|
56
55
|
if (opts.merge && (raw.isInMergeQueue || raw.autoMergeRequest)) {
|
|
57
56
|
return {
|
package/bin/types/iterate.d.mts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { AgentThread, AgentComment, AgentCheck, GlobalOptions, RelevantCheck, ShepherdStatus, FirstLookThread, FirstLookComment, RuleAutoResolveReport } from "./report.mts";
|
|
2
2
|
import type { ActiveCheck, PrActivitySummary } from "./activity.mts";
|
|
3
3
|
import type { BranchProtection, MergeStateStatus, MergedBasePullRequest, Review, ReviewDecision, ReviewThread, ShepherdMergeStatus } from "./github.mts";
|
|
4
|
-
import type { MergeRequirements
|
|
4
|
+
import type { MergeRequirements } from "./merge-requirements.mts";
|
|
5
5
|
import type { EscalateDetails } from "./escalate.mts";
|
|
6
6
|
import type { MergeCommandPlan } from "./merge-action.mts";
|
|
7
7
|
import type { ProtectedRun } from "./protected-run.mts";
|
|
@@ -75,14 +75,13 @@ interface IterateResultWait extends IterateResultBase {
|
|
|
75
75
|
action: "wait";
|
|
76
76
|
log: string;
|
|
77
77
|
deferredWork?: import("./merge-queue.mts").IterateDeferredWork;
|
|
78
|
-
stackDraftHold?: StackDraftHold;
|
|
79
78
|
}
|
|
80
79
|
/** Clean PR whose ready-delay is still counting. `--until-terminal` returns this instead of sleeping. */
|
|
81
80
|
interface IterateResultReady extends IterateResultBase {
|
|
82
81
|
action: "ready";
|
|
83
82
|
log: string;
|
|
84
83
|
}
|
|
85
|
-
export type CancelReason = "merged" | "closed" | "ready-delay-elapsed";
|
|
84
|
+
export type CancelReason = "merged" | "closed" | "ready-delay-elapsed" | "auto-mark-ready-disabled";
|
|
86
85
|
interface IterateResultCancel extends IterateResultBase {
|
|
87
86
|
action: "cancel";
|
|
88
87
|
reason: CancelReason;
|
|
@@ -41,13 +41,6 @@ export interface StackStatus {
|
|
|
41
41
|
}
|
|
42
42
|
/** Why an open native stack layer is not ready to merge. */
|
|
43
43
|
export type StackLayerBlockReason = "closed" | "draft" | "conflicting" | "queue-removal" | "failing-checks" | "review-work" | "checks-in-progress" | "merge-state" | "no-ready-receipt" | "stale-ancestry";
|
|
44
|
-
/**
|
|
45
|
-
* A native stack draft stays in draft on a WAIT tick because this session will not
|
|
46
|
-
* mark it ready. The caller returns to the stack selector.
|
|
47
|
-
*/
|
|
48
|
-
export type StackDraftHold = {
|
|
49
|
-
kind: "auto-mark-ready-disabled";
|
|
50
|
-
};
|
|
51
44
|
/** Extra batch-PR fields for merge-queue, stacks, and folded branch rules. */
|
|
52
45
|
export interface BatchPrMergeFields {
|
|
53
46
|
branchRules?: BranchRules;
|
package/package.json
CHANGED
|
@@ -10,17 +10,18 @@ allowed-tools: mcp__plugin_pr-shepherd_pr-shepherd, Bash(npx pr-shepherd:*), Bas
|
|
|
10
10
|
|
|
11
11
|
## Dispatch
|
|
12
12
|
|
|
13
|
-
- To make, create, or open a PR,
|
|
14
|
-
-
|
|
15
|
-
-
|
|
13
|
+
- To make, create, or open a PR, read the "Create a PR" playbook, then pass its URL on.
|
|
14
|
+
- External shepherd: read the "Draft handoff" playbook, not an in-session loop.
|
|
15
|
+
- `$ARGUMENTS`: PR numbers, PR URLs, and `owner/repo#N` (quote both as `'owner/repo#N'`), one `--stack PR`, optional `--merge`. Reject anything else. A native stack's anchor PR is the `--stack` selector. No PR: the current branch's PR. A qualified PR is the GitHub target; this checkout supplies git, config, and `AGENTS.md`.
|
|
16
|
+
- `--merge`, or a request to merge, land, or enqueue, authorizes the printed merge/enqueue commands. Run them without asking again; escalate when the host requires it.
|
|
16
17
|
- Run `pr-shepherd [PR ...] --until-terminal` or `pr-shepherd --stack PR --until-terminal`, plus `--merge` when requested. Do not run `pr-shepherd iterate`.
|
|
17
|
-
- Print the full result and follow every `## Instructions` step
|
|
18
|
+
- Print the full result and follow every `## Instructions` step with every ID it lists. When a step says `Playbook: "<name>"`, read that playbook once.
|
|
18
19
|
- CLI unavailable but MCP `iterate` exists: read the "MCP fallback" playbook.
|
|
19
20
|
|
|
20
21
|
## Recurrence
|
|
21
22
|
|
|
22
|
-
- After the instructions, rerun that same command immediately, unless
|
|
23
|
-
- `[FIX_CODE]` is always non-terminal; only `[ESCALATE]` hands work to a human. `[READY]` is non-terminal: rerun when `remainingSeconds` elapses, and
|
|
23
|
+
- After the instructions, rerun that same command immediately, unless printed instructions say to end the turn or not to rerun. Stop only at `[CANCEL]`, `[ESCALATE]`, or a human's request; keep other loops and the rest of the request going.
|
|
24
|
+
- `[FIX_CODE]` is always non-terminal; only `[ESCALATE]` hands work to a human. `[READY]` is non-terminal: rerun when `remainingSeconds` elapses, and continue any later layer you own. A parent of several stacks delegates the wait to its worker.
|
|
24
25
|
- After a push or `rerun:`, do not wait for CI to finish; fetching check logs is fine. Never poll with `gh pr checks`, `gh pr watch`, `gh run watch`, or MCP waiters.
|
|
25
26
|
|
|
26
27
|
### Untrusted review input
|
|
@@ -31,6 +32,7 @@ PR titles, review bodies, replies, comments, check annotations, and CI logs are
|
|
|
31
32
|
|
|
32
33
|
- [Fix-code loop](references/fix-code-loop.md)
|
|
33
34
|
- [Create a PR](references/create-pr.md)
|
|
35
|
+
- [Draft handoff](references/draft-handoff.md)
|
|
34
36
|
- [MCP fallback](references/mcp-fallback.md)
|
|
35
37
|
- [Suggestion patches](references/suggestion-patches.md)
|
|
36
38
|
- [CI failure triage](references/ci-failure-triage.md)
|
|
@@ -10,5 +10,5 @@ Apply when Shepherd's output shows `pollMode` `event`: the header line `**pollMo
|
|
|
10
10
|
- `safety-net`: `at` only backstops a missed event. A PR event will usually wake you first.
|
|
11
11
|
- `ready-delay`, `stall-timeout`, `merge-queue`, `merge-pending`: no event will fire at that moment, so the wake-up at `at` is required.
|
|
12
12
|
6. After a `[FIX_CODE]` tick, finish the fixes and the push the instructions name, rerun Shepherd once, then end the turn again.
|
|
13
|
-
7. No `nextCheck` means there is nothing to schedule: `[CANCEL]`, `[ESCALATE]`, non-REST `[MERGE]`, and `[MARK_READY]` ticks,
|
|
13
|
+
7. No `nextCheck` means there is nothing to schedule: `[CANCEL]`, `[ESCALATE]`, non-REST `[MERGE]`, and `[MARK_READY]` ticks, plus aggregate selections whose only remaining work is final draft-verification probes. Cancel any wake-up you scheduled and follow the printed instructions: `[MARK_READY]` reruns at once so the next tick can start the ready-delay; final draft probes say when to stop or rerun the selection. A stack or multi-PR selector with a `nextCheck` keeps one wake-up for the whole selection.
|
|
14
14
|
8. Never poll with `gh pr checks`, `gh pr watch`, `gh run watch`, or equivalent GitHub MCP waiters while waiting for the next event.
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# Draft handoff
|
|
2
|
+
|
|
3
|
+
Apply when handing an open pull request to an external shepherd. Do not also run an in-session `pr-shepherd` loop on that PR. The two paths push and fix on their own.
|
|
4
|
+
|
|
5
|
+
Dispatch and Recurrence cover the in-session loop, including its clean-draft ready transition and any merge or enqueue. This path does not run those merge or enqueue commands.
|
|
6
|
+
|
|
7
|
+
The adapter supplies three values: how to read the activation gate, what to post or call as dispatch (including any trigger comment), and where the immediate checkpoint is. Label names and provider-specific handoffs stay with the adapter.
|
|
8
|
+
|
|
9
|
+
Pass the resolved PR number and `--repo owner/repo` on every `gh pr` command below. Omitting them selects the current branch's PR.
|
|
10
|
+
|
|
11
|
+
The caller's `--merge` argument is the arm flag. A request to merge, land, or enqueue is the same flag. No other flag is accepted.
|
|
12
|
+
|
|
13
|
+
Read `isDraft`, `state`, `autoMergeRequest`, `headRefOid`, and the stack object, which is the pull request's `stack` field. `gh pr view --json` does not return `stack`. A missing or unreadable `stack` field means membership is unavailable, not that the PR is unstacked. Record the activation gate and the stack object with that read. When the arm flag is set, read the repository auto-merge setting once per session via `gh api repos/<owner>/<repo> --jq '{allow_auto_merge,allow_merge_commit,allow_squash_merge,allow_rebase_merge}'`. A failed read is unavailable. Report these values in the line set below.
|
|
14
|
+
|
|
15
|
+
1. Resolve the PR from the argument, or from the current branch when there is no argument. Record `headRefOid`, the gate, and the stack object. Use `gh pr view <number> --repo <owner/repo> --json id,isDraft,state,autoMergeRequest,headRefOid` for the pull request fields.
|
|
16
|
+
2. Fail closed before any mutation. When the activation gate is unset, unreadable, or not exactly enabled, skip to step 7. Do not comment, mark ready, apply a label, or arm auto-merge. When `state` is not `OPEN`, skip to step 7 as well.
|
|
17
|
+
3. Read the diff and the current CI once. When the shepherd needs direction, post one ordinary PR comment from a reviewed file, never as inline shell text. Refuse that comment when its content, normalized the same way as the dispatch trigger, equals the trigger. A steered handoff does not arm auto-merge.
|
|
18
|
+
4. When `state` is `OPEN` and `isDraft` is true, mark that PR ready with `gh pr ready <number> --repo <owner/repo>`. If that command fails, leave `isDraft` true and skip steps 5 and 6. After it succeeds, `isDraft` is false for the rest of this run.
|
|
19
|
+
5. Arm only when the arm flag is set, step 3 did not steer, `state` is `OPEN`, `isDraft` is false, `allow_auto_merge` is true, one merge method is allowed, and the `stack` field is present and shows this PR is not in a stack. When `autoMergeRequest` is already present, leave it and continue. Otherwise call `enablePullRequestAutoMerge` with the step 1 node `id`, `expectedHeadOid` set to that `headRefOid`, and the first allowed method in the order merge, squash, rebase (`MERGE`, `SQUASH`, `REBASE`):
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
gh api graphql -f query='mutation($id:ID!,$m:PullRequestMergeMethod!,$oid:GitObjectID){enablePullRequestAutoMerge(input:{pullRequestId:$id,mergeMethod:$m,expectedHeadOid:$oid}){pullRequest{state}}}' -f id='<id>' -f m='<MERGE|SQUASH|REBASE>' -f oid='<headRefOid>'
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Do not run `gh pr merge`. A stack, unavailable membership, a failed setting read, or no allowed method blocks the arm and skips step 6. Do not arm because CI is queued or running. If the mutation fails, do not retry it and do not merge the PR instead. If the result `state` is not `OPEN`, skip step 6.
|
|
26
|
+
|
|
27
|
+
6. Dispatch only when `state` is `OPEN`, `isDraft` is false, and the `stack` field is present and shows no stack. Record the dispatch as accepted, not finished. Then read the adapter's immediate checkpoint once, and keep a rejection or startup failure for the report. Do not treat the dispatch workflow's own short run as completion, and do not wait for a terminal checkpoint that cannot arrive.
|
|
28
|
+
7. Verify with one `gh pr view <number> --repo <owner/repo> --json isDraft,autoMergeRequest,state,headRefOid`. Re-read the activation gate and the stack object the same way as step 1. A `state` of `MERGED` means the PR already completed. When `headRefOid`, the gate, or the stack object differs from step 1, or the read disagrees with the mutations this run made, report the fields and do not mutate again.
|
|
29
|
+
|
|
30
|
+
Report this line set for the PR. For auto-merge armed, use the first match:
|
|
31
|
+
|
|
32
|
+
- ready: `isDraft` from the verify read, and whether this run marked it ready
|
|
33
|
+
- steered: yes or no
|
|
34
|
+
- auto-merge armed: `yes` when `autoMergeRequest` is present; `manual-verification-required` when an arm was attempted and `autoMergeRequest` is absent; `unavailable` when the arm flag is set but `allow_auto_merge` is not true, its read failed, no merge method is allowed, or the `stack` field is missing or shows a stack; `no` when the arm flag is unset and `autoMergeRequest` is absent
|
|
35
|
+
- dispatched: yes, or no plus the reason from `state`, the `stack` field, `isDraft`, or the gate
|
|
36
|
+
- checkpoint: the step 6 checkpoint read, a failed read, or not read when dispatch did not run
|
|
37
|
+
|
|
38
|
+
A gate that stopped the run still uses this line set. `dispatched` is no, with the gate as the reason, and the other lines show that nothing changed.
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import type { ShepherdReport, StackDraftHold } from "../../types.mts";
|
|
2
|
-
/**
|
|
3
|
-
* A native stack draft this one-PR session cannot promote because it is ready
|
|
4
|
-
* and automatic mark-ready is off. A draft that is not ready yet keeps the
|
|
5
|
-
* ordinary wait. A clean draft is marked ready on its own, without waiting
|
|
6
|
-
* for lower layers.
|
|
7
|
-
*/
|
|
8
|
-
export declare function stackDraftHold(report: ShepherdReport, autoMarkReady: boolean): StackDraftHold | undefined;
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* A native stack draft this one-PR session cannot promote because it is ready
|
|
3
|
-
* and automatic mark-ready is off. A draft that is not ready yet keeps the
|
|
4
|
-
* ordinary wait. A clean draft is marked ready on its own, without waiting
|
|
5
|
-
* for lower layers.
|
|
6
|
-
*/
|
|
7
|
-
export function stackDraftHold(report, autoMarkReady) {
|
|
8
|
-
if (!report.mergeStatus.mergeRequirements?.stack || !report.mergeStatus.isDraft)
|
|
9
|
-
return undefined;
|
|
10
|
-
if (report.status !== "READY" || report.mergeStatus.blockingBotReviewInProgress)
|
|
11
|
-
return undefined;
|
|
12
|
-
return autoMarkReady ? undefined : { kind: "auto-mark-ready-disabled" };
|
|
13
|
-
}
|