@os-eco/overstory-cli 0.6.1 → 0.6.4

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.
Files changed (80) hide show
  1. package/README.md +7 -6
  2. package/package.json +12 -4
  3. package/src/agents/hooks-deployer.test.ts +94 -16
  4. package/src/agents/hooks-deployer.ts +18 -0
  5. package/src/agents/manifest.test.ts +86 -0
  6. package/src/commands/agents.test.ts +3 -3
  7. package/src/commands/agents.ts +59 -88
  8. package/src/commands/clean.test.ts +31 -46
  9. package/src/commands/clean.ts +28 -49
  10. package/src/commands/completions.ts +14 -0
  11. package/src/commands/coordinator.test.ts +131 -24
  12. package/src/commands/coordinator.ts +100 -63
  13. package/src/commands/costs.test.ts +2 -2
  14. package/src/commands/costs.ts +96 -75
  15. package/src/commands/dashboard.test.ts +2 -2
  16. package/src/commands/dashboard.ts +73 -93
  17. package/src/commands/doctor.test.ts +2 -2
  18. package/src/commands/doctor.ts +92 -79
  19. package/src/commands/errors.test.ts +2 -2
  20. package/src/commands/errors.ts +56 -50
  21. package/src/commands/feed.test.ts +2 -2
  22. package/src/commands/feed.ts +86 -83
  23. package/src/commands/group.ts +167 -177
  24. package/src/commands/hooks.test.ts +2 -2
  25. package/src/commands/hooks.ts +52 -42
  26. package/src/commands/init.test.ts +19 -19
  27. package/src/commands/init.ts +7 -16
  28. package/src/commands/inspect.test.ts +2 -2
  29. package/src/commands/inspect.ts +54 -57
  30. package/src/commands/log.test.ts +5 -10
  31. package/src/commands/log.ts +90 -84
  32. package/src/commands/logs.test.ts +1 -1
  33. package/src/commands/logs.ts +101 -104
  34. package/src/commands/mail.ts +157 -169
  35. package/src/commands/merge.test.ts +20 -58
  36. package/src/commands/merge.ts +13 -43
  37. package/src/commands/metrics.test.ts +2 -2
  38. package/src/commands/metrics.ts +33 -34
  39. package/src/commands/monitor.test.ts +3 -3
  40. package/src/commands/monitor.ts +56 -61
  41. package/src/commands/nudge.ts +41 -89
  42. package/src/commands/prime.test.ts +15 -47
  43. package/src/commands/prime.ts +7 -44
  44. package/src/commands/replay.test.ts +2 -2
  45. package/src/commands/replay.ts +79 -86
  46. package/src/commands/run.ts +97 -77
  47. package/src/commands/sling.test.ts +196 -0
  48. package/src/commands/sling.ts +24 -54
  49. package/src/commands/spec.test.ts +13 -39
  50. package/src/commands/spec.ts +30 -99
  51. package/src/commands/status.ts +46 -42
  52. package/src/commands/stop.test.ts +21 -39
  53. package/src/commands/stop.ts +18 -33
  54. package/src/commands/supervisor.test.ts +3 -5
  55. package/src/commands/supervisor.ts +136 -157
  56. package/src/commands/trace.test.ts +9 -9
  57. package/src/commands/trace.ts +54 -77
  58. package/src/commands/watch.test.ts +2 -2
  59. package/src/commands/watch.ts +38 -45
  60. package/src/commands/worktree.test.ts +8 -8
  61. package/src/commands/worktree.ts +63 -46
  62. package/src/config.test.ts +96 -0
  63. package/src/doctor/databases.test.ts +22 -2
  64. package/src/doctor/databases.ts +16 -0
  65. package/src/doctor/dependencies.test.ts +55 -1
  66. package/src/doctor/dependencies.ts +113 -18
  67. package/src/e2e/init-sling-lifecycle.test.ts +6 -6
  68. package/src/index.ts +223 -213
  69. package/src/logging/color.test.ts +74 -91
  70. package/src/logging/color.ts +52 -46
  71. package/src/logging/reporter.test.ts +10 -10
  72. package/src/logging/reporter.ts +6 -5
  73. package/src/merge/queue.test.ts +66 -0
  74. package/src/merge/queue.ts +15 -0
  75. package/src/schema-consistency.test.ts +239 -0
  76. package/src/sessions/compat.ts +1 -1
  77. package/src/sessions/store.test.ts +37 -0
  78. package/src/sessions/store.ts +11 -0
  79. package/src/worktree/tmux.test.ts +98 -9
  80. package/src/worktree/tmux.ts +18 -0
@@ -66,41 +66,9 @@ describe("primeCommand", () => {
66
66
  return stderrChunks.join("");
67
67
  }
68
68
 
69
- describe("Help", () => {
70
- test("--help shows help text", async () => {
71
- await primeCommand(["--help"]);
72
- const out = output();
73
-
74
- expect(out).toContain("overstory prime");
75
- expect(out).toContain("--agent");
76
- expect(out).toContain("--compact");
77
- });
78
-
79
- test("-h shows help text", async () => {
80
- await primeCommand(["-h"]);
81
- const out = output();
82
-
83
- expect(out).toContain("overstory prime");
84
- expect(out).toContain("--agent");
85
- expect(out).toContain("--compact");
86
- });
87
- });
88
-
89
- describe("parseArgs validation", () => {
90
- test("--agent without a name throws AgentError", async () => {
91
- await expect(primeCommand(["--agent"])).rejects.toThrow("--agent requires a name argument");
92
- });
93
-
94
- test("--agent followed by another flag throws AgentError", async () => {
95
- await expect(primeCommand(["--agent", "--compact"])).rejects.toThrow(
96
- "--agent requires a name argument",
97
- );
98
- });
99
- });
100
-
101
69
  describe("Orchestrator priming (no --agent flag)", () => {
102
70
  test("default prime outputs project context", async () => {
103
- await primeCommand([]);
71
+ await primeCommand({});
104
72
  const out = output();
105
73
 
106
74
  expect(out).toContain("# Overstory Context");
@@ -111,7 +79,7 @@ describe("primeCommand", () => {
111
79
  });
112
80
 
113
81
  test("includes agent manifest section", async () => {
114
- await primeCommand([]);
82
+ await primeCommand({});
115
83
  const out = output();
116
84
 
117
85
  expect(out).toContain("## Agent Manifest");
@@ -120,7 +88,7 @@ describe("primeCommand", () => {
120
88
  });
121
89
 
122
90
  test("without metrics.db shows no recent sessions message", async () => {
123
- await primeCommand([]);
91
+ await primeCommand({});
124
92
  const out = output();
125
93
 
126
94
  expect(out).toContain("## Recent Activity");
@@ -128,7 +96,7 @@ describe("primeCommand", () => {
128
96
  });
129
97
 
130
98
  test("--compact skips Recent Activity and Expertise sections", async () => {
131
- await primeCommand(["--compact"]);
99
+ await primeCommand({ compact: true });
132
100
  const out = output();
133
101
 
134
102
  // Should still have project basics
@@ -143,7 +111,7 @@ describe("primeCommand", () => {
143
111
 
144
112
  describe("Agent priming (--agent <name>)", () => {
145
113
  test("unknown agent outputs basic context and warns", async () => {
146
- await primeCommand(["--agent", "unknown-agent"]);
114
+ await primeCommand({ agent: "unknown-agent" });
147
115
  const out = output();
148
116
  const err = stderr();
149
117
 
@@ -172,7 +140,7 @@ recentTasks:
172
140
  `,
173
141
  );
174
142
 
175
- await primeCommand(["--agent", "my-builder"]);
143
+ await primeCommand({ agent: "my-builder" });
176
144
  const out = output();
177
145
 
178
146
  expect(out).toContain("# Agent Context: my-builder");
@@ -212,7 +180,7 @@ recentTasks:
212
180
  `${JSON.stringify(sessions, null, 2)}\n`,
213
181
  );
214
182
 
215
- await primeCommand(["--agent", "active-builder"]);
183
+ await primeCommand({ agent: "active-builder" });
216
184
  const out = output();
217
185
 
218
186
  expect(out).toContain("# Agent Context: active-builder");
@@ -249,7 +217,7 @@ recentTasks:
249
217
  `${JSON.stringify(sessions, null, 2)}\n`,
250
218
  );
251
219
 
252
- await primeCommand(["--agent", "completed-builder"]);
220
+ await primeCommand({ agent: "completed-builder" });
253
221
  const out = output();
254
222
 
255
223
  expect(out).toContain("# Agent Context: completed-builder");
@@ -291,7 +259,7 @@ recentTasks: []
291
259
  `,
292
260
  );
293
261
 
294
- await primeCommand(["--agent", "recovery-agent", "--compact"]);
262
+ await primeCommand({ agent: "recovery-agent", compact: true });
295
263
  const out = output();
296
264
 
297
265
  expect(out).toContain("# Agent Context: recovery-agent");
@@ -317,7 +285,7 @@ recentTasks: []
317
285
  `,
318
286
  );
319
287
 
320
- await primeCommand(["--agent", "compact-agent", "--compact"]);
288
+ await primeCommand({ agent: "compact-agent", compact: true });
321
289
  const out = output();
322
290
 
323
291
  expect(out).toContain("# Agent Context: compact-agent");
@@ -340,7 +308,7 @@ recentTasks: []
340
308
  // Save and change cwd to the git repo
341
309
  process.chdir(gitRepoDir);
342
310
 
343
- await primeCommand([]);
311
+ await primeCommand({});
344
312
  const out = output();
345
313
 
346
314
  expect(out).toContain("# Overstory Context");
@@ -375,7 +343,7 @@ recentTasks: []
375
343
 
376
344
  process.chdir(gitRepoDir);
377
345
 
378
- await primeCommand([]);
346
+ await primeCommand({});
379
347
  const out = output();
380
348
 
381
349
  expect(out).toContain("Session branch: feature/my-work (merge target)");
@@ -412,7 +380,7 @@ recentTasks: []
412
380
  expect(existsBefore).toBe(false);
413
381
 
414
382
  // Run primeCommand
415
- await primeCommand([]);
383
+ await primeCommand({});
416
384
 
417
385
  // Verify .gitignore was created with correct content
418
386
  const content = await Bun.file(gitignorePath).text();
@@ -435,7 +403,7 @@ sessions.db
435
403
  expect(contentBefore).toBe(staleContent);
436
404
 
437
405
  // Run primeCommand
438
- await primeCommand([]);
406
+ await primeCommand({});
439
407
 
440
408
  // Verify .gitignore now has the wildcard+whitelist content
441
409
  const contentAfter = await Bun.file(gitignorePath).text();
@@ -455,7 +423,7 @@ sessions.db
455
423
  await new Promise((resolve) => setTimeout(resolve, 10));
456
424
 
457
425
  // Run primeCommand
458
- await primeCommand([]);
426
+ await primeCommand({});
459
427
 
460
428
  // Verify content is still correct
461
429
  const contentAfter = await Bun.file(gitignorePath).text();
@@ -12,7 +12,6 @@ import { loadCheckpoint } from "../agents/checkpoint.ts";
12
12
  import { loadIdentity } from "../agents/identity.ts";
13
13
  import { createManifestLoader } from "../agents/manifest.ts";
14
14
  import { loadConfig } from "../config.ts";
15
- import { AgentError } from "../errors.ts";
16
15
  import { createMetricsStore } from "../metrics/store.ts";
17
16
  import { createMulchClient } from "../mulch/client.ts";
18
17
  import { openSessionStore } from "../sessions/compat.ts";
@@ -35,32 +34,9 @@ const OVERSTORY_GITIGNORE = `# Wildcard+whitelist: ignore everything, whitelist
35
34
  !agent-defs/
36
35
  `;
37
36
 
38
- /**
39
- * Parse CLI flags from the args array.
40
- *
41
- * Supports:
42
- * - `--agent <name>` — Prime for a specific agent
43
- * - `--compact` — Output reduced context
44
- */
45
- function parseArgs(args: string[]): { agentName: string | null; compact: boolean } {
46
- let agentName: string | null = null;
47
- let compact = false;
48
-
49
- for (let i = 0; i < args.length; i++) {
50
- const arg = args[i];
51
- if (arg === "--agent") {
52
- const next = args[i + 1];
53
- if (next === undefined || next.startsWith("--")) {
54
- throw new AgentError("--agent requires a name argument");
55
- }
56
- agentName = next;
57
- i++; // Skip the value
58
- } else if (arg === "--compact") {
59
- compact = true;
60
- }
61
- }
62
-
63
- return { agentName, compact };
37
+ export interface PrimeOptions {
38
+ agent?: string;
39
+ compact?: boolean;
64
40
  }
65
41
 
66
42
  /**
@@ -156,24 +132,11 @@ async function healGitignore(overstoryDir: string): Promise<void> {
156
132
  * Gathers project state and outputs context to stdout for injection
157
133
  * into Claude Code's context.
158
134
  *
159
- * @param args - CLI arguments after "prime" subcommand
135
+ * @param opts - Command options
160
136
  */
161
- const PRIME_HELP = `overstory prime Load context for orchestrator/agent
162
-
163
- Usage: overstory prime [--agent <name>] [--compact]
164
-
165
- Options:
166
- --agent <name> Prime for a specific agent (default: orchestrator)
167
- --compact Output reduced context (for PreCompact hook)
168
- --help, -h Show this help`;
169
-
170
- export async function primeCommand(args: string[]): Promise<void> {
171
- if (args.includes("--help") || args.includes("-h")) {
172
- process.stdout.write(`${PRIME_HELP}\n`);
173
- return;
174
- }
175
-
176
- const { agentName, compact } = parseArgs(args);
137
+ export async function primeCommand(opts: PrimeOptions): Promise<void> {
138
+ const agentName = opts.agent ?? null;
139
+ const compact = opts.compact ?? false;
177
140
 
178
141
  // 1. Load config
179
142
  const config = await loadConfig(process.cwd());
@@ -78,7 +78,7 @@ describe("replayCommand", () => {
78
78
  await replayCommand(["--help"]);
79
79
  const out = output();
80
80
 
81
- expect(out).toContain("overstory replay");
81
+ expect(out).toContain("replay");
82
82
  expect(out).toContain("--run");
83
83
  expect(out).toContain("--agent");
84
84
  expect(out).toContain("--json");
@@ -91,7 +91,7 @@ describe("replayCommand", () => {
91
91
  await replayCommand(["-h"]);
92
92
  const out = output();
93
93
 
94
- expect(out).toContain("overstory replay");
94
+ expect(out).toContain("replay");
95
95
  });
96
96
  });
97
97
 
@@ -7,14 +7,16 @@
7
7
  */
8
8
 
9
9
  import { join } from "node:path";
10
+ import { Command } from "commander";
10
11
  import { loadConfig } from "../config.ts";
11
12
  import { ValidationError } from "../errors.ts";
12
13
  import { createEventStore } from "../events/store.ts";
14
+ import type { ColorFn } from "../logging/color.ts";
13
15
  import { color } from "../logging/color.ts";
14
16
  import type { EventType, StoredEvent } from "../types.ts";
15
17
 
16
18
  /** Labels and colors for each event type. */
17
- const EVENT_LABELS: Record<EventType, { label: string; color: string }> = {
19
+ const EVENT_LABELS: Record<EventType, { label: string; color: ColorFn }> = {
18
20
  tool_start: { label: "TOOL START", color: color.blue },
19
21
  tool_end: { label: "TOOL END ", color: color.blue },
20
22
  session_start: { label: "SESSION +", color: color.green },
@@ -26,41 +28,14 @@ const EVENT_LABELS: Record<EventType, { label: string; color: string }> = {
26
28
  custom: { label: "CUSTOM ", color: color.gray },
27
29
  };
28
30
 
29
- /** Colors assigned to agents in order of first appearance. */
30
- const AGENT_COLORS = [color.blue, color.green, color.yellow, color.cyan, color.magenta] as const;
31
-
32
- /**
33
- * Parse a named flag value from args.
34
- */
35
- function getFlag(args: string[], flag: string): string | undefined {
36
- const idx = args.indexOf(flag);
37
- if (idx === -1 || idx + 1 >= args.length) {
38
- return undefined;
39
- }
40
- return args[idx + 1];
41
- }
42
-
43
- /**
44
- * Parse all occurrences of a named flag from args.
45
- * Returns an array of values (e.g., --agent a --agent b => ["a", "b"]).
46
- */
47
- function getAllFlags(args: string[], flag: string): string[] {
48
- const values: string[] = [];
49
- for (let i = 0; i < args.length; i++) {
50
- if (args[i] === flag && i + 1 < args.length) {
51
- const value = args[i + 1];
52
- if (value !== undefined) {
53
- values.push(value);
54
- }
55
- i++; // skip the value
56
- }
57
- }
58
- return values;
59
- }
60
-
61
- function hasFlag(args: string[], flag: string): boolean {
62
- return args.includes(flag);
63
- }
31
+ /** Color functions assigned to agents in order of first appearance. */
32
+ const AGENT_COLORS: readonly ColorFn[] = [
33
+ color.blue,
34
+ color.green,
35
+ color.yellow,
36
+ color.cyan,
37
+ color.magenta,
38
+ ];
64
39
 
65
40
  /**
66
41
  * Format a relative time string from a timestamp.
@@ -150,16 +125,16 @@ function buildEventDetail(event: StoredEvent): string {
150
125
  }
151
126
 
152
127
  /**
153
- * Assign a stable color to each agent based on order of first appearance.
128
+ * Assign a stable color function to each agent based on order of first appearance.
154
129
  */
155
- function buildAgentColorMap(events: StoredEvent[]): Map<string, string> {
156
- const colorMap = new Map<string, string>();
130
+ function buildAgentColorMap(events: StoredEvent[]): Map<string, ColorFn> {
131
+ const colorMap = new Map<string, ColorFn>();
157
132
  for (const event of events) {
158
133
  if (!colorMap.has(event.agentName)) {
159
134
  const colorIndex = colorMap.size % AGENT_COLORS.length;
160
- const color = AGENT_COLORS[colorIndex];
161
- if (color !== undefined) {
162
- colorMap.set(event.agentName, color);
135
+ const agentColorFn = AGENT_COLORS[colorIndex];
136
+ if (agentColorFn !== undefined) {
137
+ colorMap.set(event.agentName, agentColorFn);
163
138
  }
164
139
  }
165
140
  }
@@ -172,15 +147,15 @@ function buildAgentColorMap(events: StoredEvent[]): Map<string, string> {
172
147
  function printReplay(events: StoredEvent[], useAbsoluteTime: boolean): void {
173
148
  const w = process.stdout.write.bind(process.stdout);
174
149
 
175
- w(`${color.bold}Replay${color.reset}\n`);
150
+ w(`${color.bold("Replay")}\n`);
176
151
  w(`${"=".repeat(70)}\n`);
177
152
 
178
153
  if (events.length === 0) {
179
- w(`${color.dim}No events found.${color.reset}\n`);
154
+ w(`${color.dim("No events found.")}\n`);
180
155
  return;
181
156
  }
182
157
 
183
- w(`${color.dim}${events.length} event${events.length === 1 ? "" : "s"}${color.reset}\n\n`);
158
+ w(`${color.dim(`${events.length} event${events.length === 1 ? "" : "s"}`)}\n\n`);
184
159
 
185
160
  const colorMap = buildAgentColorMap(events);
186
161
  let lastDate = "";
@@ -192,7 +167,7 @@ function printReplay(events: StoredEvent[], useAbsoluteTime: boolean): void {
192
167
  if (lastDate !== "") {
193
168
  w("\n");
194
169
  }
195
- w(`${color.dim}--- ${date} ---${color.reset}\n`);
170
+ w(`${color.dim(`--- ${date} ---`)}\n`);
196
171
  lastDate = date;
197
172
  }
198
173
 
@@ -205,57 +180,40 @@ function printReplay(events: StoredEvent[], useAbsoluteTime: boolean): void {
205
180
  color: color.gray,
206
181
  };
207
182
 
208
- const levelColor =
209
- event.level === "error" ? color.red : event.level === "warn" ? color.yellow : "";
210
- const levelReset = levelColor ? color.reset : "";
183
+ const levelColorFn =
184
+ event.level === "error" ? color.red : event.level === "warn" ? color.yellow : null;
185
+ const applyLevel = (text: string) => (levelColorFn ? levelColorFn(text) : text);
211
186
 
212
187
  const detail = buildEventDetail(event);
213
- const detailSuffix = detail ? ` ${color.dim}${detail}${color.reset}` : "";
188
+ const detailSuffix = detail ? ` ${color.dim(detail)}` : "";
214
189
 
215
- const agentColor = colorMap.get(event.agentName) ?? color.gray;
216
- const agentLabel = ` ${agentColor}[${event.agentName}]${color.reset}`;
190
+ const agentColorFn = colorMap.get(event.agentName) ?? color.gray;
191
+ const agentLabel = ` ${agentColorFn(`[${event.agentName}]`)}`;
217
192
 
218
193
  w(
219
- `${color.dim}${timeStr.padStart(10)}${color.reset} ` +
220
- `${levelColor}${eventInfo.color}${color.bold}${eventInfo.label}${color.reset}${levelReset}` +
194
+ `${color.dim(timeStr.padStart(10))} ` +
195
+ `${applyLevel(eventInfo.color(color.bold(eventInfo.label)))}` +
221
196
  `${agentLabel}${detailSuffix}\n`,
222
197
  );
223
198
  }
224
199
  }
225
200
 
226
- const REPLAY_HELP = `overstory replay -- Interleaved chronological replay across agents
227
-
228
- Usage: overstory replay [options]
229
-
230
- Options:
231
- --run <id> Filter events by run ID
232
- --agent <name> Filter by agent name (can appear multiple times)
233
- --since <timestamp> Start time filter (ISO 8601)
234
- --until <timestamp> End time filter (ISO 8601)
235
- --limit <n> Max events to show (default: 200)
236
- --json Output as JSON array of StoredEvent objects
237
- --help, -h Show this help
238
-
239
- If --run is specified, shows all events from that run.
240
- If --agent is specified, shows events from those agents merged chronologically.
241
- If neither is specified, tries to read the current run from .overstory/current-run.txt.
242
- Falls back to a 24-hour timeline of all events.`;
243
-
244
- /**
245
- * Entry point for `overstory replay [--run <id>] [--agent <name>...] [--json]`.
246
- */
247
- export async function replayCommand(args: string[]): Promise<void> {
248
- if (args.includes("--help") || args.includes("-h")) {
249
- process.stdout.write(`${REPLAY_HELP}\n`);
250
- return;
251
- }
201
+ interface ReplayOpts {
202
+ run?: string;
203
+ agent: string[]; // repeatable
204
+ since?: string;
205
+ until?: string;
206
+ limit?: string;
207
+ json?: boolean;
208
+ }
252
209
 
253
- const json = hasFlag(args, "--json");
254
- const runId = getFlag(args, "--run");
255
- const agentNames = getAllFlags(args, "--agent");
256
- const sinceStr = getFlag(args, "--since");
257
- const untilStr = getFlag(args, "--until");
258
- const limitStr = getFlag(args, "--limit");
210
+ async function executeReplay(opts: ReplayOpts): Promise<void> {
211
+ const json = opts.json ?? false;
212
+ const runId = opts.run;
213
+ const agentNames = opts.agent;
214
+ const sinceStr = opts.since;
215
+ const untilStr = opts.until;
216
+ const limitStr = opts.limit;
259
217
  const limit = limitStr ? Number.parseInt(limitStr, 10) : 200;
260
218
 
261
219
  if (Number.isNaN(limit) || limit < 1) {
@@ -358,3 +316,38 @@ export async function replayCommand(args: string[]): Promise<void> {
358
316
  eventStore.close();
359
317
  }
360
318
  }
319
+
320
+ export function createReplayCommand(): Command {
321
+ return new Command("replay")
322
+ .description("Interleaved chronological replay across agents")
323
+ .option("--run <id>", "Filter events by run ID")
324
+ .option(
325
+ "--agent <name>",
326
+ "Filter by agent name (can appear multiple times)",
327
+ (val: string, prev: string[]) => [...prev, val],
328
+ [] as string[],
329
+ )
330
+ .option("--since <timestamp>", "Start time filter (ISO 8601)")
331
+ .option("--until <timestamp>", "End time filter (ISO 8601)")
332
+ .option("--limit <n>", "Max events to show (default: 200)")
333
+ .option("--json", "Output as JSON array of StoredEvent objects")
334
+ .action(async (opts: ReplayOpts) => {
335
+ await executeReplay(opts);
336
+ });
337
+ }
338
+
339
+ export async function replayCommand(args: string[]): Promise<void> {
340
+ const cmd = createReplayCommand();
341
+ cmd.exitOverride();
342
+ try {
343
+ await cmd.parseAsync(args, { from: "user" });
344
+ } catch (err: unknown) {
345
+ if (err && typeof err === "object" && "code" in err) {
346
+ const code = (err as { code: string }).code;
347
+ if (code === "commander.helpDisplayed" || code === "commander.version") {
348
+ return;
349
+ }
350
+ }
351
+ throw err;
352
+ }
353
+ }