pr-shepherd 0.18.0 → 0.19.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "pr-shepherd",
3
3
  "description": "Autonomous PR CI monitor and review-comment resolver for agentic coding tools",
4
- "version": "0.18.0",
4
+ "version": "0.19.0",
5
5
  "author": {
6
6
  "name": "Jonathan Ong",
7
7
  "email": "jonathanrichardong@gmail.com"
@@ -1,4 +1,5 @@
1
1
  import { parsePrNumber } from "./args.mjs";
2
+ import { USAGE } from "./help.mjs";
2
3
  const DEFAULT_ITERATE_FLAGS_WITH_VALUES = new Set(["--format", "--ready-delay", "--stall-timeout"]);
3
4
  const DEFAULT_ITERATE_BOOLEAN_FLAGS = new Set([
4
5
  "--verbose",
@@ -6,6 +7,8 @@ const DEFAULT_ITERATE_BOOLEAN_FLAGS = new Set([
6
7
  "--no-auto-cancel-actionable",
7
8
  ]);
8
9
  export function isDefaultIterateInvocation(subcommand) {
10
+ if (subcommand === "--help" || subcommand === "-h")
11
+ return false;
9
12
  return (subcommand === undefined ||
10
13
  parsePrNumber(subcommand) !== null ||
11
14
  isDefaultIterateFlag(subcommand));
@@ -42,8 +45,6 @@ function isDefaultIterateFlag(arg) {
42
45
  }
43
46
  function writeDefaultUsageError(arg) {
44
47
  process.stderr.write(`Unknown subcommand: ${arg}\n`);
45
- process.stderr.write("Usage: pr-shepherd [PR] [options]\n" +
46
- " pr-shepherd <resolve|commit-suggestion|iterate|poll|log-file|clean> [options]\n" +
47
- " pr-shepherd --version | -v\n");
48
+ process.stderr.write(`${USAGE.top}\n`);
48
49
  process.exitCode = 1;
49
50
  }
@@ -3,6 +3,7 @@ import { runIterate } from "../commands/iterate/index.mjs";
3
3
  import { runClean } from "../commands/clean.mjs";
4
4
  import { loadConfig } from "../config/load.mjs";
5
5
  import { parseCommonArgs, getFlag } from "./args.mjs";
6
+ import { USAGE } from "./help.mjs";
6
7
  import { formatCommitSuggestionResult, formatCleanResult } from "./formatters.mjs";
7
8
  import { parseIterateFlags } from "./iterate-flags.mjs";
8
9
  import { emitIterateResult } from "./iterate-emitter.mjs";
@@ -10,7 +11,7 @@ const CLEAN_VARIANTS = new Set(["pr", "branch", "current", "repo", "all"]);
10
11
  export async function handleClean(args) {
11
12
  const variant = args[0];
12
13
  if (!variant || !CLEAN_VARIANTS.has(variant)) {
13
- process.stderr.write("Usage: pr-shepherd clean <pr|branch|current|repo|all> [value] [--dry-run] [--format text|json]\n");
14
+ process.stderr.write(`${USAGE.clean}\n`);
14
15
  process.exitCode = 1;
15
16
  return;
16
17
  }
@@ -65,7 +66,7 @@ export async function handleCommitSuggestion(args) {
65
66
  const { prNumber, global: globalOpts, extra } = parseCommonArgs(args);
66
67
  const threadId = getFlag(extra, "--thread-id");
67
68
  if (!threadId) {
68
- process.stderr.write("Usage: pr-shepherd commit-suggestion [PR] --thread-id ID --message MSG [--description DESC]\n");
69
+ process.stderr.write(`${USAGE["commit-suggestion"]}\n`);
69
70
  process.exitCode = 1;
70
71
  return;
71
72
  }
@@ -0,0 +1,40 @@
1
+ import { hasFlag } from "./args.mjs";
2
+ export const USAGE = {
3
+ top: "Usage:\n" +
4
+ " pr-shepherd --version | -v\n" +
5
+ " pr-shepherd [PR] [--format text|json] [--ready-delay Nm]\n" +
6
+ " [--stall-timeout <duration>] [--no-auto-mark-ready]\n" +
7
+ " [--no-auto-cancel-actionable]\n" +
8
+ " pr-shepherd resolve [PR] [--fetch] [--resolve-thread-ids A,B] [--minimize-comment-ids X,Y]\n" +
9
+ " [--dismiss-review-ids Q] [--message MSG] [--require-sha SHA]\n" +
10
+ " pr-shepherd commit-suggestion [PR] --thread-id ID --message MSG [--description DESC]\n" +
11
+ " [--format text|json]\n" +
12
+ " pr-shepherd iterate [PR] [--format text|json] [--ready-delay Nm]\n" +
13
+ " [--stall-timeout <duration>] [--no-auto-mark-ready]\n" +
14
+ " [--no-auto-cancel-actionable]\n" +
15
+ " pr-shepherd poll [PR] [--interval 30s] [--timeout 5m] [--format text|json] [--ready-delay Nm]\n" +
16
+ " [--stall-timeout <duration>] [--no-auto-mark-ready]\n" +
17
+ " [--no-auto-cancel-actionable]\n" +
18
+ " pr-shepherd clean <pr|branch|current|repo|all> [value] [--dry-run] [--format text|json]\n" +
19
+ " pr-shepherd log-file [--format text|json]",
20
+ resolve: "Usage: pr-shepherd resolve [PR] [--fetch] [--resolve-thread-ids A,B]\n" +
21
+ " [--minimize-comment-ids X,Y] [--dismiss-review-ids Q]\n" +
22
+ " [--message MSG] [--require-sha SHA]",
23
+ "commit-suggestion": "Usage: pr-shepherd commit-suggestion [PR] --thread-id ID --message MSG\n" +
24
+ " [--description DESC] [--format text|json]",
25
+ iterate: "Usage: pr-shepherd iterate [PR] [--format text|json] [--ready-delay Nm]\n" +
26
+ " [--stall-timeout <duration>] [--no-auto-mark-ready]\n" +
27
+ " [--no-auto-cancel-actionable]",
28
+ poll: "Usage: pr-shepherd poll [PR] [--interval 30s] [--timeout 5m] [--format text|json]\n" +
29
+ " [--ready-delay Nm] [--stall-timeout <duration>]\n" +
30
+ " [--no-auto-mark-ready] [--no-auto-cancel-actionable]",
31
+ clean: "Usage: pr-shepherd clean <pr|branch|current|repo|all> [value] [--dry-run] [--format text|json]",
32
+ "log-file": "Usage: pr-shepherd log-file [--format text|json]",
33
+ };
34
+ /** Prints usage for `key` to stdout and returns true if `--help` or `-h` is in args. */
35
+ export function maybePrintHelp(args, key) {
36
+ if (!hasFlag(args, "--help") && !hasFlag(args, "-h"))
37
+ return false;
38
+ process.stdout.write(`${USAGE[key]}\n`);
39
+ return true;
40
+ }
@@ -8,9 +8,8 @@
8
8
  * [--no-auto-cancel-actionable]
9
9
  * pr-shepherd resolve [PR] [--fetch] [--resolve-thread-ids A,B] [--minimize-comment-ids X,Y]
10
10
  * [--dismiss-review-ids Q] [--message MSG] [--require-sha SHA]
11
- * pr-shepherd commit-suggestion [PR] --thread-id ID [--message MSG] [--description DESC]
12
- * [--dry-run] [--format text|json]
13
- * (--message is required unless --dry-run is set)
11
+ * pr-shepherd commit-suggestion [PR] --thread-id ID --message MSG [--description DESC]
12
+ * [--format text|json]
14
13
  * pr-shepherd iterate [PR] [--format text|json] [--ready-delay Nm]
15
14
  * [--stall-timeout <duration>] [--no-auto-mark-ready]
16
15
  * [--no-auto-cancel-actionable]
@@ -24,6 +23,7 @@ import { runResolveFetch, runResolveMutate } from "./commands/resolve.mjs";
24
23
  import { runLogFile } from "./commands/log-file.mjs";
25
24
  import { parseCommonArgs, getFlag, hasFlag, parseList } from "./cli/args.mjs";
26
25
  import { isDefaultIterateInvocation, validateDefaultIterateArgs } from "./cli/default-iterate.mjs";
26
+ import { USAGE, maybePrintHelp } from "./cli/help.mjs";
27
27
  import { formatFetchResult, formatMutateResult } from "./cli/formatters.mjs";
28
28
  import { handleClean, handleCommitSuggestion, handleIterate } from "./cli/handlers.mjs";
29
29
  import { handlePoll } from "./cli/poll-handler.mjs";
@@ -38,11 +38,28 @@ export async function main(argv) {
38
38
  process.stdout.write(`${readVersion()}\n`);
39
39
  return;
40
40
  }
41
+ if (subcommand === "--help" || subcommand === "-h") {
42
+ process.stdout.write(`${USAGE.top}\n`);
43
+ return;
44
+ }
41
45
  // log-file must run before the stdout tee and log init to avoid recursion.
42
46
  if (subcommand === "log-file") {
43
47
  await handleLogFile(args.slice(1));
44
48
  return;
45
49
  }
50
+ // Short-circuit all --help/-h before any I/O or logging.
51
+ if (hasFlag(args, "--help") || hasFlag(args, "-h")) {
52
+ if (isDefaultIterateInvocation(subcommand)) {
53
+ process.stdout.write(`${USAGE.iterate}\n`);
54
+ }
55
+ else {
56
+ const key = subcommand != null && subcommand in USAGE
57
+ ? subcommand
58
+ : "top";
59
+ process.stdout.write(`${USAGE[key]}\n`);
60
+ }
61
+ return;
62
+ }
46
63
  // Initialize the per-worktree log and install a stdout tee.
47
64
  await setupLog(argv);
48
65
  if (isDefaultIterateInvocation(subcommand)) {
@@ -69,8 +86,7 @@ export async function main(argv) {
69
86
  break;
70
87
  default:
71
88
  process.stderr.write(`Unknown subcommand: ${subcommand ?? "(none)"}\n`);
72
- process.stderr.write("Usage: pr-shepherd <resolve|commit-suggestion|iterate|poll|log-file|clean> [options]\n" +
73
- " pr-shepherd --version | -v\n");
89
+ process.stderr.write(`${USAGE.top}\n`);
74
90
  process.exitCode = 1;
75
91
  return;
76
92
  }
@@ -84,6 +100,8 @@ function readVersion() {
84
100
  // Subcommand handlers
85
101
  // ---------------------------------------------------------------------------
86
102
  async function handleLogFile(args) {
103
+ if (maybePrintHelp(args, "log-file"))
104
+ return;
87
105
  const jsonOut = args.some((a) => a === "--format=json") ||
88
106
  (() => {
89
107
  const idx = args.indexOf("--format");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pr-shepherd",
3
- "version": "0.18.0",
3
+ "version": "0.19.0",
4
4
  "description": "Autonomous PR CI monitor and review-comment resolver for agentic coding tools",
5
5
  "license": "MIT",
6
6
  "author": "Jonathan Ong",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pr-shepherd",
3
- "version": "0.18.0",
3
+ "version": "0.19.0",
4
4
  "description": "Autonomous PR CI monitor and review-comment resolver for Codex.",
5
5
  "author": {
6
6
  "name": "Jonathan Ong",