@vimhead.dev/norn-cli 0.1.0-tip.35614826665.1 → 0.1.0-tip.35724621678.1

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 (119) hide show
  1. package/assets/README.md +41 -13
  2. package/assets/docs/README.md +16 -16
  3. package/assets/docs/agents.md +23 -15
  4. package/assets/docs/cli.md +10 -8
  5. package/assets/docs/composition.md +7 -7
  6. package/assets/docs/persistence.md +22 -22
  7. package/assets/docs/projects.md +6 -6
  8. package/assets/docs/recovery.md +10 -10
  9. package/assets/docs/schemas.md +42 -36
  10. package/assets/docs/workflows.md +39 -32
  11. package/assets/examples/agent-then-analysis/input.json +3 -3
  12. package/assets/examples/agent-then-analysis/norn.project.json +2 -2
  13. package/assets/examples/agent-then-analysis/plugin.ts +37 -9
  14. package/assets/examples/caller-owned-routing/README.md +6 -6
  15. package/assets/examples/caller-owned-routing/assessment.ts +18 -4
  16. package/assets/examples/caller-owned-routing/contracts.ts +7 -2
  17. package/assets/examples/caller-owned-routing/input.json +12 -12
  18. package/assets/examples/caller-owned-routing/norn.project.json +2 -2
  19. package/assets/examples/caller-owned-routing/revision.ts +7 -2
  20. package/assets/examples/caller-owned-routing/router.ts +14 -3
  21. package/assets/examples/caller-selected-continuation/caller.ts +38 -12
  22. package/assets/examples/caller-selected-continuation/input.json +7 -7
  23. package/assets/examples/caller-selected-continuation/norn.project.json +2 -2
  24. package/assets/examples/caller-selected-continuation/producer.ts +10 -3
  25. package/assets/examples/coordinating-multiple-agents/README.md +6 -6
  26. package/assets/examples/coordinating-multiple-agents/input.json +20 -8
  27. package/assets/examples/coordinating-multiple-agents/norn.project.json +2 -2
  28. package/assets/examples/coordinating-multiple-agents/plugin.ts +165 -46
  29. package/assets/examples/coordinating-multiple-agents/queue-tools.ts +30 -7
  30. package/assets/examples/coordinating-multiple-agents/work-queue.ts +211 -63
  31. package/assets/examples/getting-started/norn.project.json +2 -2
  32. package/assets/examples/getting-started/plugin.ts +33 -13
  33. package/assets/examples/minimal-workflow/norn.project.json +2 -2
  34. package/assets/examples/minimal-workflow/plugin.ts +12 -3
  35. package/assets/examples/shared-state/README.md +6 -6
  36. package/assets/examples/shared-state/input.json +1 -1
  37. package/assets/examples/shared-state/norn.project.json +2 -2
  38. package/assets/examples/shared-state/plugin.ts +44 -15
  39. package/assets/examples/shared-state/shared-state.ts +46 -13
  40. package/assets/examples/shared-state/state-tools.ts +68 -16
  41. package/assets/examples/worktree-development-loop/README.md +12 -12
  42. package/assets/examples/worktree-development-loop/norn.project.json +7 -7
  43. package/assets/examples/worktree-development-loop/plugin.ts +7 -1
  44. package/assets/examples/worktree-development-loop/scope.ts +4 -1
  45. package/assets/examples/worktree-development-loop/shared/commands.ts +6 -2
  46. package/assets/examples/worktree-development-loop/workflows/development-loop/execute.ts +18 -4
  47. package/assets/examples/worktree-development-loop/workflows/development-loop/index.ts +4 -1
  48. package/assets/examples/worktree-development-loop/workflows/development-loop/repository.ts +11 -1
  49. package/assets/examples/worktree-development-loop/workflows/development-loop/schema.ts +6 -2
  50. package/assets/examples/worktree-development-loop/workflows/implementation/execute.ts +40 -10
  51. package/assets/examples/worktree-development-loop/workflows/implementation/index.ts +5 -1
  52. package/assets/examples/worktree-development-loop/workflows/planning/execute.ts +1 -1
  53. package/assets/examples/worktree-development-loop/workflows/planning/index.ts +5 -1
  54. package/assets/examples/worktree-development-loop/workflows/review/execute.ts +33 -9
  55. package/assets/examples/worktree-development-loop/workflows/review-router/execute.ts +51 -8
  56. package/assets/package.json +1 -1
  57. package/assets/packages/cli/src/build-info.ts +4 -1
  58. package/assets/packages/cli/src/bun/cli.ts +21 -5
  59. package/assets/packages/cli/src/cli.ts +585 -170
  60. package/assets/packages/cli/src/client.ts +194 -36
  61. package/assets/packages/cli/src/documentation.ts +135 -30
  62. package/assets/packages/cli/src/generated-build-info.ts +2 -2
  63. package/assets/packages/cli/src/internal/agent-directory.ts +7 -2
  64. package/assets/packages/cli/src/internal/agent-response-tool.ts +57 -15
  65. package/assets/packages/cli/src/internal/agents.ts +248 -60
  66. package/assets/packages/cli/src/internal/commands.ts +82 -20
  67. package/assets/packages/cli/src/internal/documentation-bundle.ts +44 -13
  68. package/assets/packages/cli/src/internal/engine.ts +396 -87
  69. package/assets/packages/cli/src/internal/errors.ts +13 -5
  70. package/assets/packages/cli/src/internal/execution-context.ts +20 -12
  71. package/assets/packages/cli/src/internal/file-coordinator.ts +95 -26
  72. package/assets/packages/cli/src/internal/file-names.ts +4 -1
  73. package/assets/packages/cli/src/internal/launch-request.ts +74 -22
  74. package/assets/packages/cli/src/internal/logs.ts +10 -2
  75. package/assets/packages/cli/src/internal/metrics.ts +247 -61
  76. package/assets/packages/cli/src/internal/pi-assets.ts +105 -23
  77. package/assets/packages/cli/src/internal/run-lease.ts +72 -22
  78. package/assets/packages/cli/src/internal/run-log.ts +49 -20
  79. package/assets/packages/cli/src/internal/run-names.ts +120 -12
  80. package/assets/packages/cli/src/internal/run-state.ts +306 -71
  81. package/assets/packages/cli/src/internal/run-store.ts +216 -53
  82. package/assets/packages/cli/src/internal/usage.ts +23 -7
  83. package/assets/packages/cli/src/internal/worker-directory.ts +9 -3
  84. package/assets/packages/cli/src/internal/workflow-registry.ts +281 -70
  85. package/assets/packages/cli/src/internal/working-directory.ts +2 -1
  86. package/assets/packages/cli/src/workflow-loader.ts +341 -74
  87. package/assets/packages/core/src/atomic-files.ts +13 -4
  88. package/assets/packages/core/src/workflow-transition.ts +13 -2
  89. package/assets/packages/sdk/src/api.ts +248 -80
  90. package/assets/packages/sdk/src/index.ts +6 -1
  91. package/assets/packages/sdk/src/schema.ts +75 -21
  92. package/assets/tests/workflow-ref.test.ts +242 -57
  93. package/bin/norn.mjs +13 -4
  94. package/dist/cli.js +344 -90
  95. package/dist/client.js +100 -22
  96. package/dist/documentation.js +102 -25
  97. package/dist/generated-build-info.d.ts +2 -2
  98. package/dist/generated-build-info.js +2 -2
  99. package/dist/internal/agent-directory.js +3 -1
  100. package/dist/internal/agent-response-tool.js +42 -11
  101. package/dist/internal/agents.js +149 -37
  102. package/dist/internal/commands.js +65 -16
  103. package/dist/internal/documentation-bundle.js +23 -11
  104. package/dist/internal/engine.js +304 -66
  105. package/dist/internal/errors.js +4 -2
  106. package/dist/internal/execution-context.js +2 -1
  107. package/dist/internal/file-coordinator.js +59 -19
  108. package/dist/internal/launch-request.js +32 -14
  109. package/dist/internal/metrics.js +138 -38
  110. package/dist/internal/pi-assets.js +70 -19
  111. package/dist/internal/run-lease.js +29 -9
  112. package/dist/internal/run-log.js +24 -12
  113. package/dist/internal/run-state.js +172 -48
  114. package/dist/internal/run-store.js +157 -45
  115. package/dist/internal/worker-directory.js +6 -2
  116. package/dist/internal/workflow-registry.js +123 -32
  117. package/dist/internal/working-directory.js +2 -1
  118. package/dist/workflow-loader.js +198 -41
  119. package/package.json +2 -2
package/dist/cli.js CHANGED
@@ -9,25 +9,61 @@ function isNodeError(error) {
9
9
  // src/cli.ts
10
10
  import { spawn } from "node:child_process";
11
11
  import { createHash, randomUUID } from "node:crypto";
12
- import { chmod, mkdir, readFile, rename, rm, stat, writeFile } from "node:fs/promises";
12
+ import {
13
+ chmod,
14
+ mkdir,
15
+ readFile,
16
+ rename,
17
+ rm,
18
+ stat,
19
+ writeFile
20
+ } from "node:fs/promises";
13
21
  import { homedir } from "node:os";
14
22
  import { dirname, isAbsolute, join, resolve } from "node:path";
15
23
  import { setTimeout as delay } from "node:timers/promises";
16
24
  import { fileURLToPath } from "node:url";
17
25
  import { Value } from "typebox/value";
18
- import { NORN_BUILD_INFO } from "./build-info.js";
19
- import { renderNornDocumentationIntro, resolveDocumentationCacheRoot, resolveNornDocumentation } from "./documentation.js";
26
+ import {
27
+ NORN_BUILD_INFO
28
+ } from "./build-info.js";
29
+ import {
30
+ renderNornDocumentationIntro,
31
+ resolveDocumentationCacheRoot,
32
+ resolveNornDocumentation
33
+ } from "./documentation.js";
20
34
  import { NornEngine } from "./internal/engine.js";
21
35
  import { resolveNornAgentDirectory } from "./internal/agent-directory.js";
22
- import { errorMessage, NornProjectLoadError, NornRunStoppedError } from "./internal/errors.js";
23
- import { clearRunResumeRequest, readRunLaunchRequest, readRunResumeRequest, writeRunLaunchRequest, writeRunResumeRequest } from "./internal/launch-request.js";
36
+ import {
37
+ errorMessage,
38
+ NornProjectLoadError,
39
+ NornRunStoppedError
40
+ } from "./internal/errors.js";
41
+ import {
42
+ clearRunResumeRequest,
43
+ readRunLaunchRequest,
44
+ readRunResumeRequest,
45
+ writeRunLaunchRequest,
46
+ writeRunResumeRequest
47
+ } from "./internal/launch-request.js";
24
48
  import { readRunMetrics } from "./internal/metrics.js";
25
49
  import { getRunLeaseOwner, NornRunLease } from "./internal/run-lease.js";
26
50
  import { generateRunName } from "./internal/run-names.js";
27
- import { assertRunVersion, getRunInfo, listRuns, mergeInterruptedWorkflowArgs, resolveRunRoot } from "./internal/run-state.js";
51
+ import {
52
+ assertRunVersion,
53
+ getRunInfo,
54
+ listRuns,
55
+ mergeInterruptedWorkflowArgs,
56
+ resolveRunRoot
57
+ } from "./internal/run-state.js";
28
58
  import { NornRunStore } from "./internal/run-store.js";
29
59
  import { prepareRunWorkerDirectory } from "./internal/worker-directory.js";
30
- import { discoverNornProject, findNornProject, inspectNornWorkflow, loadNornProject, NORN_PROJECT_FILE_NAME } from "./workflow-loader.js";
60
+ import {
61
+ discoverNornProject,
62
+ findNornProject,
63
+ inspectNornWorkflow,
64
+ loadNornProject,
65
+ NORN_PROJECT_FILE_NAME
66
+ } from "./workflow-loader.js";
31
67
  var RUNS_ROOT = join(".norn", "runs");
32
68
  var RUN_WAIT_INTERVAL_MS = 1e3;
33
69
  var CLI_DESCRIPTION = "Norn is a harness-agnostic runtime for agent-driven and code-driven workflows, built primarily for agents. Build workflows with the Norn SDK; use this JSON-native CLI to discover workflows, start or resume runs, inspect evidence, and manage the installed runtime.";
@@ -37,9 +73,16 @@ var COMMANDS = [
37
73
  path: ["pi"],
38
74
  description: "Run Norn's bundled Pi CLI for interactive authentication, provider packages, model configuration, or direct Pi use. No Norn project is required.",
39
75
  usage: "norn pi [pi arguments...]",
40
- arguments: ["pi arguments: forwarded unchanged; use norn pi --help for Pi's CLI contract"],
76
+ arguments: [
77
+ "pi arguments: forwarded unchanged; use norn pi --help for Pi's CLI contract"
78
+ ],
41
79
  output: "Pi's native terminal, text, JSON, or RPC output and exit status; not wrapped in Norn JSON.",
42
- examples: ["norn pi", "norn pi install npm:pi-cursor-sdk", "norn pi --list-models cursor", "norn pi --help"],
80
+ examples: [
81
+ "norn pi",
82
+ "norn pi install npm:pi-cursor-sdk",
83
+ "norn pi --list-models cursor",
84
+ "norn pi --help"
85
+ ],
43
86
  execute: (args) => runPi([...args])
44
87
  },
45
88
  {
@@ -67,9 +110,16 @@ var COMMANDS = [
67
110
  path: ["help"],
68
111
  description: "Use when reading JSON help for all Norn commands, one command group, or one command.",
69
112
  usage: "norn help [command-or-group]",
70
- arguments: ["command-or-group: optional command path such as runs or runs start"],
113
+ arguments: [
114
+ "command-or-group: optional command path such as runs or runs start"
115
+ ],
71
116
  output: "JSON object with help metadata under help.",
72
- examples: ["norn help", "norn help runs", "norn help runs start", "norn --help"],
117
+ examples: [
118
+ "norn help",
119
+ "norn help runs",
120
+ "norn help runs start",
121
+ "norn --help"
122
+ ],
73
123
  execute: (args) => writeCliHelp(args)
74
124
  },
75
125
  {
@@ -81,7 +131,9 @@ var COMMANDS = [
81
131
  examples: ["norn docs inspect"],
82
132
  execute: async (args, documentationSource) => {
83
133
  assertNoExtraArgs("docs inspect", args);
84
- writeJson({ documentation: await resolveCliDocumentation(documentationSource) });
134
+ writeJson({
135
+ documentation: await resolveCliDocumentation(documentationSource)
136
+ });
85
137
  }
86
138
  },
87
139
  {
@@ -93,10 +145,15 @@ var COMMANDS = [
93
145
  examples: ["norn docs intro"],
94
146
  execute: async (args, documentationSource) => {
95
147
  assertNoExtraArgs("docs intro", args);
96
- writeJson({ intro: renderNornDocumentationIntro({
97
- documentation: await resolveCliDocumentation(documentationSource),
98
- invocation: documentationSource.kind === "embedded" ? [process.execPath] : [process.execPath, fileURLToPath(new URL("../bin/norn.mjs", import.meta.url))]
99
- }) });
148
+ writeJson({
149
+ intro: renderNornDocumentationIntro({
150
+ documentation: await resolveCliDocumentation(documentationSource),
151
+ invocation: documentationSource.kind === "embedded" ? [process.execPath] : [
152
+ process.execPath,
153
+ fileURLToPath(new URL("../bin/norn.mjs", import.meta.url))
154
+ ]
155
+ })
156
+ });
100
157
  }
101
158
  },
102
159
  {
@@ -128,7 +185,10 @@ var COMMANDS = [
128
185
  path: ["workflows", "list"],
129
186
  description: "Use when selecting a Norn workflow for a user task; defaults to entrypoint workflows.",
130
187
  usage: "norn workflows list [--entrypoints|--all]",
131
- options: ["--entrypoints: list entrypoint workflows", "--all: include internal workflow steps"],
188
+ options: [
189
+ "--entrypoints: list entrypoint workflows",
190
+ "--all: include internal workflow steps"
191
+ ],
132
192
  output: "JSON object with workflow summaries under workflows, isComplete, and registration diagnostics. Successful discovery can be incomplete; start/resume remain strict.",
133
193
  examples: ["norn workflows list", "norn workflows list --all"],
134
194
  execute: listWorkflows
@@ -142,7 +202,12 @@ var COMMANDS = [
142
202
  output: "JSON object with workflow details, isComplete, and registration diagnostics. workflow is null if unavailable in an incomplete catalog or its schema cannot be inspected; an unknown id in a complete catalog is an error.",
143
203
  examples: ["norn workflows inspect example.plan"],
144
204
  execute: async (args) => {
145
- const workflowId = requiredArg("workflows inspect", args, 0, "workflow id");
205
+ const workflowId = requiredArg(
206
+ "workflows inspect",
207
+ args,
208
+ 0,
209
+ "workflow id"
210
+ );
146
211
  assertNoExtraArgs("workflows inspect", args.slice(1));
147
212
  await inspectWorkflow(workflowId);
148
213
  }
@@ -155,7 +220,9 @@ var COMMANDS = [
155
220
  arguments: ["workflow-id: fully qualified workflow id to start"],
156
221
  stdin: 'Optional JSON object: {"args":{...},"config":{"workflowOrScopeId":{...}}}.',
157
222
  output: "JSON object with started run info under run.",
158
- examples: [`printf '{"args":{"task":"Add tests"}}' | norn runs start example.plan`],
223
+ examples: [
224
+ `printf '{"args":{"task":"Add tests"}}' | norn runs start example.plan`
225
+ ],
159
226
  execute: async (args) => {
160
227
  const workflowId = requiredArg("runs start", args, 0, "workflow id");
161
228
  await startRun(workflowId, args.slice(1));
@@ -169,7 +236,9 @@ var COMMANDS = [
169
236
  arguments: ["run: run id, generated name, or run path"],
170
237
  stdin: 'Optional JSON object: {"args":{...}}. Interrupted runs require a patch containing only editable gate fields; pending-resume runs do not accept args.',
171
238
  output: "JSON object with resumed run info under run.",
172
- examples: [`printf '{"args":{"decision":"accept"}}' | norn runs resume quiet-river-lantern`],
239
+ examples: [
240
+ `printf '{"args":{"decision":"accept"}}' | norn runs resume quiet-river-lantern`
241
+ ],
173
242
  execute: async (args) => {
174
243
  const run = requiredArg("runs resume", args, 0, "run");
175
244
  await resumeRun(run, args.slice(1));
@@ -228,7 +297,9 @@ var COMMANDS = [
228
297
  assertNoExtraArgs("runs checkpoints", args.slice(1));
229
298
  const project = await findNornProject(process.cwd());
230
299
  const runRoot = await resolveRunRoot(project.projectRoot, run);
231
- writeJson({ checkpoints: await (await NornRunStore.open(runRoot)).listCheckpoints() });
300
+ writeJson({
301
+ checkpoints: await (await NornRunStore.open(runRoot)).listCheckpoints()
302
+ });
232
303
  }
233
304
  },
234
305
  {
@@ -255,7 +326,10 @@ var COMMANDS = [
255
326
  arguments: ["run: run id, generated name, or run path"],
256
327
  options: ["--follow: continue streaming until the run stops"],
257
328
  output: "JSON Lines stream of run events.",
258
- examples: ["norn runs logs quiet-river-lantern", "norn runs logs quiet-river-lantern --follow"],
329
+ examples: [
330
+ "norn runs logs quiet-river-lantern",
331
+ "norn runs logs quiet-river-lantern --follow"
332
+ ],
259
333
  execute: async (args) => {
260
334
  const run = requiredArg("runs logs", args, 0, "run");
261
335
  const logArgs = args.slice(1);
@@ -268,7 +342,10 @@ var COMMANDS = [
268
342
  path: ["runs", "rollback"],
269
343
  description: "Use when restoring a failed or stopped run to a checkpoint and marking it pending resume.",
270
344
  usage: "norn runs rollback <run> <checkpoint-id>",
271
- arguments: ["run: run id, generated name, or run path", "checkpoint-id: checkpoint id from runs.checkpoints"],
345
+ arguments: [
346
+ "run: run id, generated name, or run path",
347
+ "checkpoint-id: checkpoint id from runs.checkpoints"
348
+ ],
272
349
  output: "JSON object with rolled-back run info under run.",
273
350
  examples: ["norn runs rollback quiet-river-lantern checkpoint-1"],
274
351
  execute: async (args) => {
@@ -338,7 +415,9 @@ var COMMANDS = [
338
415
  path: ["upgrade"],
339
416
  description: "Use when upgrading this Norn CLI installation according to explicit build metadata.",
340
417
  usage: "norn upgrade [--dry-run]",
341
- options: ["--dry-run: report the upgrade plan without changing files or running installers"],
418
+ options: [
419
+ "--dry-run: report the upgrade plan without changing files or running installers"
420
+ ],
342
421
  output: "JSON object with upgrade status, plan, or unsupported reason under upgrade.",
343
422
  examples: ["norn upgrade --dry-run", "norn upgrade"],
344
423
  execute: upgradeNorn
@@ -416,11 +495,13 @@ async function main(args, documentationSource) {
416
495
  try {
417
496
  await runCommand(args, documentationSource);
418
497
  } catch (error) {
419
- writeJson({ error: {
420
- code: errorCode(error),
421
- message: errorMessage(error),
422
- ...error instanceof NornProjectLoadError ? { isComplete: error.isComplete, diagnostics: error.diagnostics } : {}
423
- } });
498
+ writeJson({
499
+ error: {
500
+ code: errorCode(error),
501
+ message: errorMessage(error),
502
+ ...error instanceof NornProjectLoadError ? { isComplete: error.isComplete, diagnostics: error.diagnostics } : {}
503
+ }
504
+ });
424
505
  process.exitCode = 1;
425
506
  }
426
507
  }
@@ -445,7 +526,11 @@ async function runCommand(args, documentationSource) {
445
526
  async function listCliCommands(args) {
446
527
  assertKnownFlags("commands list", args, ["--all"]);
447
528
  const shouldIncludeHidden = args.includes("--all");
448
- writeJson({ commands: COMMANDS.filter((command) => shouldIncludeHidden || !command.hidden).map(cliCommandInfo) });
529
+ writeJson({
530
+ commands: COMMANDS.filter(
531
+ (command) => shouldIncludeHidden || !command.hidden
532
+ ).map(cliCommandInfo)
533
+ });
449
534
  }
450
535
  async function inspectCliCommand(args) {
451
536
  const commandId = requiredArg("commands inspect", args, 0, "command id");
@@ -482,8 +567,13 @@ function writeCliHelp(path) {
482
567
  process.stdout.write(renderCommandHelp(command));
483
568
  return;
484
569
  }
485
- const groupCommands = sortedCommandsForHelp(visibleCommands().filter((candidate) => path.length === 0 || startsWithPath(candidate.path, path)));
486
- if (groupCommands.length === 0) throw new Error(`Unknown norn help topic: ${path.join(" ")}`);
570
+ const groupCommands = sortedCommandsForHelp(
571
+ visibleCommands().filter(
572
+ (candidate) => path.length === 0 || startsWithPath(candidate.path, path)
573
+ )
574
+ );
575
+ if (groupCommands.length === 0)
576
+ throw new Error(`Unknown norn help topic: ${path.join(" ")}`);
487
577
  process.stdout.write(renderGroupHelp(path, groupCommands));
488
578
  }
489
579
  function renderGroupHelp(path, commands) {
@@ -526,27 +616,42 @@ function renderCommandHelp(command) {
526
616
  function renderCommandSummary(commands) {
527
617
  const commandNames = commands.map((command) => command.path.join(" "));
528
618
  const width = Math.max(...commandNames.map((name) => name.length));
529
- return commands.map((command, index) => ` ${commandNames[index].padEnd(width)} ${commandHumanSummary(command)}`).join("\n");
619
+ return commands.map(
620
+ (command, index) => ` ${commandNames[index].padEnd(width)} ${commandHumanSummary(command)}`
621
+ ).join("\n");
530
622
  }
531
623
  function helpSection(title, lines) {
532
624
  return ["", `${title}:`, ...lines.map((line) => ` ${line}`)];
533
625
  }
534
626
  function groupHelpUsage(path) {
535
- if (path.length === 0) return ["norn <command> [args]", "norn help <command>", "norn --version"];
627
+ if (path.length === 0)
628
+ return ["norn <command> [args]", "norn help <command>", "norn --version"];
536
629
  const prefix = `norn ${path.join(" ")}`;
537
- return [`${prefix} <command> [args]`, `norn help ${path.join(" ")} <command>`, "norn --version"];
630
+ return [
631
+ `${prefix} <command> [args]`,
632
+ `norn help ${path.join(" ")} <command>`,
633
+ "norn --version"
634
+ ];
538
635
  }
539
636
  function findCliCommand(args) {
540
- return sortedCommandsByPathLength(COMMANDS).find((command) => startsWithPath(args, command.path));
637
+ return sortedCommandsByPathLength(COMMANDS).find(
638
+ (command) => startsWithPath(args, command.path)
639
+ );
541
640
  }
542
641
  function findExactCliCommand(path) {
543
- return COMMANDS.find((command) => command.path.length === path.length && startsWithPath(command.path, path));
642
+ return COMMANDS.find(
643
+ (command) => command.path.length === path.length && startsWithPath(command.path, path)
644
+ );
544
645
  }
545
646
  function sortedCommandsByPathLength(commands) {
546
- return [...commands].sort((left, right) => right.path.length - left.path.length);
647
+ return [...commands].sort(
648
+ (left, right) => right.path.length - left.path.length
649
+ );
547
650
  }
548
651
  function sortedCommandsForHelp(commands) {
549
- return [...commands].sort((left, right) => commandHelpOrder(left) - commandHelpOrder(right));
652
+ return [...commands].sort(
653
+ (left, right) => commandHelpOrder(left) - commandHelpOrder(right)
654
+ );
550
655
  }
551
656
  function commandHelpOrder(command) {
552
657
  const index = HELP_COMMAND_ORDER.indexOf(command.id);
@@ -565,7 +670,11 @@ async function resolveCliDocumentation(source) {
565
670
  return resolveNornDocumentation({
566
671
  source,
567
672
  build: { ...NORN_BUILD_INFO, version: await readPackageVersion() },
568
- cacheRoot: resolveDocumentationCacheRoot({ platform: process.platform, home: homedir(), environment: process.env })
673
+ cacheRoot: resolveDocumentationCacheRoot({
674
+ platform: process.platform,
675
+ home: homedir(),
676
+ environment: process.env
677
+ })
569
678
  });
570
679
  }
571
680
  async function versionInfo() {
@@ -573,11 +682,15 @@ async function versionInfo() {
573
682
  }
574
683
  async function readPackageVersion() {
575
684
  try {
576
- const packageJson = JSON.parse(await readFile(new URL("../package.json", import.meta.url), "utf8"));
577
- if (typeof packageJson.version !== "string") throw new Error("Invalid Norn package version");
685
+ const packageJson = JSON.parse(
686
+ await readFile(new URL("../package.json", import.meta.url), "utf8")
687
+ );
688
+ if (typeof packageJson.version !== "string")
689
+ throw new Error("Invalid Norn package version");
578
690
  return packageJson.version;
579
691
  } catch (error) {
580
- if (isNodeError(error) && error.code === "ENOENT") return NORN_BUILD_INFO.version;
692
+ if (isNodeError(error) && error.code === "ENOENT")
693
+ return NORN_BUILD_INFO.version;
581
694
  throw error;
582
695
  }
583
696
  }
@@ -587,10 +700,14 @@ async function upgradeNorn(args) {
587
700
  const currentVersion = await readPackageVersion();
588
701
  const build = NORN_BUILD_INFO;
589
702
  if (build.kind !== "github-release-binary") {
590
- writeJson({ upgrade: unsupportedUpgrade(build, currentVersion, build.upgrade.reason) });
703
+ writeJson({
704
+ upgrade: unsupportedUpgrade(build, currentVersion, build.upgrade.reason)
705
+ });
591
706
  return;
592
707
  }
593
- writeJson({ upgrade: await upgradeGithubReleaseBinary(build, currentVersion, dryRun) });
708
+ writeJson({
709
+ upgrade: await upgradeGithubReleaseBinary(build, currentVersion, dryRun)
710
+ });
594
711
  }
595
712
  function unsupportedUpgrade(build, currentVersion, reason) {
596
713
  return {
@@ -604,13 +721,27 @@ function unsupportedUpgrade(build, currentVersion, reason) {
604
721
  async function upgradeGithubReleaseBinary(build, currentVersion, dryRun) {
605
722
  const plan = githubReleaseBinaryUpgradePlan(build, currentVersion, dryRun);
606
723
  if (dryRun) return { ...plan, status: "planned" };
607
- if (process.platform === "win32") return unsupportedUpgrade(build, currentVersion, "Replacing a running Windows executable is not supported yet.");
724
+ if (process.platform === "win32")
725
+ return unsupportedUpgrade(
726
+ build,
727
+ currentVersion,
728
+ "Replacing a running Windows executable is not supported yet."
729
+ );
608
730
  const binary = await downloadReleaseAsset(plan.downloadUrl);
609
731
  const checksumText = await downloadReleaseText(plan.checksumUrl);
610
- const expectedChecksum = parseSha256Checksum(checksumText, build.checksumAssetName);
732
+ const expectedChecksum = parseSha256Checksum(
733
+ checksumText,
734
+ build.checksumAssetName
735
+ );
611
736
  const actualChecksum = createHash("sha256").update(Buffer.from(binary)).digest("hex");
612
- if (actualChecksum !== expectedChecksum) throw new Error(`Downloaded Norn binary checksum mismatch: expected ${expectedChecksum}, got ${actualChecksum}`);
613
- const tempPath = join(dirname(plan.targetPath), `.norn-upgrade-${process.pid}-${build.assetName}`);
737
+ if (actualChecksum !== expectedChecksum)
738
+ throw new Error(
739
+ `Downloaded Norn binary checksum mismatch: expected ${expectedChecksum}, got ${actualChecksum}`
740
+ );
741
+ const tempPath = join(
742
+ dirname(plan.targetPath),
743
+ `.norn-upgrade-${process.pid}-${build.assetName}`
744
+ );
614
745
  try {
615
746
  await writeFile(tempPath, binary);
616
747
  await chmod(tempPath, 493);
@@ -642,17 +773,24 @@ function githubReleaseDownloadUrl(build, assetName) {
642
773
  }
643
774
  async function downloadReleaseAsset(url) {
644
775
  const response = await fetch(url);
645
- if (!response.ok) throw new Error(`Failed to download Norn release asset: ${url} returned ${response.status}`);
776
+ if (!response.ok)
777
+ throw new Error(
778
+ `Failed to download Norn release asset: ${url} returned ${response.status}`
779
+ );
646
780
  return new Uint8Array(await response.arrayBuffer());
647
781
  }
648
782
  async function downloadReleaseText(url) {
649
783
  const response = await fetch(url);
650
- if (!response.ok) throw new Error(`Failed to download Norn release metadata: ${url} returned ${response.status}`);
784
+ if (!response.ok)
785
+ throw new Error(
786
+ `Failed to download Norn release metadata: ${url} returned ${response.status}`
787
+ );
651
788
  return response.text();
652
789
  }
653
790
  function parseSha256Checksum(text, checksumAssetName) {
654
791
  const checksum = text.trim().split(/\s+/)[0] ?? "";
655
- if (!/^[a-f0-9]{64}$/i.test(checksum)) throw new Error(`Invalid Norn checksum asset: ${checksumAssetName}`);
792
+ if (!/^[a-f0-9]{64}$/i.test(checksum))
793
+ throw new Error(`Invalid Norn checksum asset: ${checksumAssetName}`);
656
794
  return checksum.toLowerCase();
657
795
  }
658
796
  function requiredArg(command, args, index, label) {
@@ -661,18 +799,30 @@ function requiredArg(command, args, index, label) {
661
799
  return value;
662
800
  }
663
801
  function assertNoExtraArgs(command, args) {
664
- if (args.length > 0) throw new Error(`${command} does not accept CLI arguments: ${args.join(" ")}`);
802
+ if (args.length > 0)
803
+ throw new Error(
804
+ `${command} does not accept CLI arguments: ${args.join(" ")}`
805
+ );
665
806
  }
666
807
  function assertKnownFlags(command, args, flags) {
667
808
  const allowedFlags = new Set(flags);
668
809
  const unsupportedFlags = args.filter((arg) => !allowedFlags.has(arg));
669
- if (unsupportedFlags.length > 0) throw new Error(`${command} has unsupported flags or arguments: ${unsupportedFlags.join(" ")}`);
810
+ if (unsupportedFlags.length > 0)
811
+ throw new Error(
812
+ `${command} has unsupported flags or arguments: ${unsupportedFlags.join(" ")}`
813
+ );
670
814
  }
671
815
  async function listWorkflows(args) {
672
816
  assertKnownFlags("workflows list", args, ["--entrypoints", "--all"]);
673
817
  const entrypointsOnly = workflowListEntrypointsOnly(args);
674
- const { workflows, isComplete, diagnostics } = await discoverNornProject(process.cwd());
675
- writeJson({ workflows: entrypointsOnly ? workflows.filter((workflow) => workflow.isEntrypoint) : workflows, isComplete, diagnostics });
818
+ const { workflows, isComplete, diagnostics } = await discoverNornProject(
819
+ process.cwd()
820
+ );
821
+ writeJson({
822
+ workflows: entrypointsOnly ? workflows.filter((workflow) => workflow.isEntrypoint) : workflows,
823
+ isComplete,
824
+ diagnostics
825
+ });
676
826
  }
677
827
  async function inspectWorkflow(workflowId) {
678
828
  writeJson(await inspectNornWorkflow({ cwd: process.cwd(), workflowId }));
@@ -680,25 +830,39 @@ async function inspectWorkflow(workflowId) {
680
830
  function workflowListEntrypointsOnly(args) {
681
831
  const entrypoints = args.includes("--entrypoints");
682
832
  const all = args.includes("--all");
683
- if (entrypoints && all) throw new Error("Use either --entrypoints or --all, not both");
833
+ if (entrypoints && all)
834
+ throw new Error("Use either --entrypoints or --all, not both");
684
835
  return !all;
685
836
  }
686
837
  async function initProject() {
687
838
  const projectRoot = process.cwd();
688
839
  const projectPath = resolve(projectRoot, NORN_PROJECT_FILE_NAME);
689
- if (await isFile(projectPath)) throw new Error(`Norn project already exists: ${projectPath}`);
840
+ if (await isFile(projectPath))
841
+ throw new Error(`Norn project already exists: ${projectPath}`);
690
842
  await mkdir(resolve(projectRoot, RUNS_ROOT), { recursive: true });
691
- await writeFile(projectPath, `${JSON.stringify({ version: 1, workflows: [], includes: [], config: {} }, null, 2)}
692
- `, "utf8");
843
+ await writeFile(
844
+ projectPath,
845
+ `${JSON.stringify({ version: 1, workflows: [], includes: [], config: {} }, null, 2)}
846
+ `,
847
+ "utf8"
848
+ );
693
849
  await ensureGitignoreExcludesRunState(projectRoot);
694
- writeJson({ project: { path: projectPath, root: projectRoot, runsRoot: resolve(projectRoot, RUNS_ROOT) } });
850
+ writeJson({
851
+ project: {
852
+ path: projectPath,
853
+ root: projectRoot,
854
+ runsRoot: resolve(projectRoot, RUNS_ROOT)
855
+ }
856
+ });
695
857
  }
696
858
  async function listCurrentProjectRuns() {
697
859
  const project = await findNornProject(process.cwd());
698
860
  return listRuns(project.projectRoot);
699
861
  }
700
862
  async function inspectProject() {
701
- const { project, isComplete, diagnostics } = await discoverNornProject(process.cwd());
863
+ const { project, isComplete, diagnostics } = await discoverNornProject(
864
+ process.cwd()
865
+ );
702
866
  writeJson({ project, isComplete, diagnostics });
703
867
  }
704
868
  async function startRun(workflowId, commandArgs) {
@@ -711,13 +875,33 @@ async function startRun(workflowId, commandArgs) {
711
875
  Value.Decode(workflow.args, args);
712
876
  const configOverride = input.config;
713
877
  const id = randomUUID();
714
- const name = generateRunName(new Set((await listRuns(project.projectRoot)).map((run) => run.name)));
878
+ const name = generateRunName(
879
+ new Set((await listRuns(project.projectRoot)).map((run) => run.name))
880
+ );
715
881
  const runRoot = resolve(project.projectRoot, RUNS_ROOT, id);
716
882
  await mkdir(runRoot, { recursive: true });
717
883
  const createdAt = (/* @__PURE__ */ new Date()).toISOString();
718
- await writeRunLaunchRequest(runRoot, { version: 2, type: "run", id, name, workflowId, args, configOverride, createdAt });
884
+ await writeRunLaunchRequest(runRoot, {
885
+ version: 2,
886
+ type: "run",
887
+ id,
888
+ name,
889
+ workflowId,
890
+ args,
891
+ configOverride,
892
+ createdAt
893
+ });
719
894
  await startDetachedExecuteRun(id, project.projectRoot);
720
- writeJson({ run: startedRunInfo({ id, name, workflow, runRoot, projectRoot: project.projectRoot, createdAt }) });
895
+ writeJson({
896
+ run: startedRunInfo({
897
+ id,
898
+ name,
899
+ workflow,
900
+ runRoot,
901
+ projectRoot: project.projectRoot,
902
+ createdAt
903
+ })
904
+ });
721
905
  }
722
906
  async function resumeRun(run, args) {
723
907
  assertNoStructuredInputArgs("runs resume", args);
@@ -730,7 +914,14 @@ async function resumeRun(run, args) {
730
914
  const runInfo = await getRunInfo(runRoot);
731
915
  assertRunVersion(runInfo.version);
732
916
  const args2 = await parseResumeArgs(runInfo, input.args);
733
- request = { version: 2, type: "resume", id: runInfo.id, requestId: randomUUID(), args: args2, createdAt: (/* @__PURE__ */ new Date()).toISOString() };
917
+ request = {
918
+ version: 2,
919
+ type: "resume",
920
+ id: runInfo.id,
921
+ requestId: randomUUID(),
922
+ args: args2,
923
+ createdAt: (/* @__PURE__ */ new Date()).toISOString()
924
+ };
734
925
  await writeRunResumeRequest(runRoot, request);
735
926
  } finally {
736
927
  await lease.release();
@@ -745,16 +936,33 @@ async function resumeRun(run, args) {
745
936
  }
746
937
  async function parseResumeArgs(runInfo, args) {
747
938
  if (runInfo.status === "interrupted") {
748
- if (args === void 0) throw new Error(`Interrupted workflow resume requires args: ${runInfo.name}`);
749
- if (!runInfo.currentWorkflowId) throw new Error(`Run has no current workflow: ${runInfo.name}`);
939
+ if (args === void 0)
940
+ throw new Error(
941
+ `Interrupted workflow resume requires args: ${runInfo.name}`
942
+ );
943
+ if (!runInfo.currentWorkflowId)
944
+ throw new Error(`Run has no current workflow: ${runInfo.name}`);
750
945
  const project = await loadNornProject(process.cwd());
751
946
  const workflow = project.registry.workflowById(runInfo.currentWorkflowId);
752
- if (!workflow) throw new Error(`Unknown workflow for resumed run: ${runInfo.currentWorkflowId}`);
753
- Value.Decode(workflow.args, mergeInterruptedWorkflowArgs(runInfo.interruption?.args, args, runInfo.interruption?.fields));
947
+ if (!workflow)
948
+ throw new Error(
949
+ `Unknown workflow for resumed run: ${runInfo.currentWorkflowId}`
950
+ );
951
+ Value.Decode(
952
+ workflow.args,
953
+ mergeInterruptedWorkflowArgs(
954
+ runInfo.interruption?.args,
955
+ args,
956
+ runInfo.interruption?.fields
957
+ )
958
+ );
754
959
  return args;
755
960
  }
756
961
  if (runInfo.status === "pendingResume") {
757
- if (args !== void 0) throw new Error(`Pending-resume workflows do not accept args: ${runInfo.name}`);
962
+ if (args !== void 0)
963
+ throw new Error(
964
+ `Pending-resume workflows do not accept args: ${runInfo.name}`
965
+ );
758
966
  return void 0;
759
967
  }
760
968
  throw new Error(`Run must be rolled back before resuming: ${runInfo.name}`);
@@ -769,7 +977,8 @@ async function waitForInactiveRun(projectRoot, run) {
769
977
  runRoot ??= await resolveWaitableRunRoot(projectRoot, run);
770
978
  try {
771
979
  const runInfo = await readRunInspection(runRoot);
772
- if (runInfo.status !== "running" || runInfo.health === "unhealthy") return runInfo;
980
+ if (runInfo.status !== "running" || runInfo.health === "unhealthy")
981
+ return runInfo;
773
982
  } catch (error) {
774
983
  if (!isNodeError(error) || error.code !== "ENOENT") throw error;
775
984
  }
@@ -780,7 +989,10 @@ async function resolveWaitableRunRoot(sessionCwd, run) {
780
989
  try {
781
990
  return await resolveRunRoot(sessionCwd, run);
782
991
  } catch (error) {
783
- for (const candidate of [resolve(sessionCwd, run), resolve(sessionCwd, RUNS_ROOT, run)]) {
992
+ for (const candidate of [
993
+ resolve(sessionCwd, run),
994
+ resolve(sessionCwd, RUNS_ROOT, run)
995
+ ]) {
784
996
  if (await isDirectory(candidate)) return candidate;
785
997
  }
786
998
  throw error;
@@ -813,31 +1025,55 @@ async function ensureGitignoreExcludesRunState(projectRoot) {
813
1025
  }
814
1026
  if (currentText.split(/\r?\n/).includes(runStatePattern)) return;
815
1027
  const separator = currentText.length === 0 || currentText.endsWith("\n") ? "" : "\n";
816
- await writeFile(gitignorePath, `${currentText}${separator}${runStatePattern}
817
- `, "utf8");
1028
+ await writeFile(
1029
+ gitignorePath,
1030
+ `${currentText}${separator}${runStatePattern}
1031
+ `,
1032
+ "utf8"
1033
+ );
818
1034
  }
819
1035
  async function executeRun(runId) {
820
1036
  const abortController = new AbortController();
821
- process.once("SIGTERM", () => abortController.abort(new NornRunStoppedError()));
822
- process.once("SIGINT", () => abortController.abort(new NornRunStoppedError()));
1037
+ process.once(
1038
+ "SIGTERM",
1039
+ () => abortController.abort(new NornRunStoppedError())
1040
+ );
1041
+ process.once(
1042
+ "SIGINT",
1043
+ () => abortController.abort(new NornRunStoppedError())
1044
+ );
823
1045
  const location = await findNornProject(process.cwd());
824
1046
  const runRoot = resolve(location.projectRoot, RUNS_ROOT, runId);
825
1047
  const request = await readOptionalRunLaunchRequest(runRoot) ?? await readRunResumeRequest(runRoot);
826
1048
  try {
827
- const agentDir = resolveNornAgentDirectory({ home: homedir(), environment: process.env });
1049
+ const agentDir = resolveNornAgentDirectory({
1050
+ home: homedir(),
1051
+ environment: process.env
1052
+ });
828
1053
  process.chdir(await prepareRunWorkerDirectory(runRoot));
829
1054
  const project = await loadNornProject(location.projectRoot);
830
- const engine = new NornEngine({ cwd: project.projectRoot, agentDir, signal: abortController.signal, gateMode: "pause", config: project.projectConfig });
1055
+ const engine = new NornEngine({
1056
+ cwd: project.projectRoot,
1057
+ agentDir,
1058
+ signal: abortController.signal,
1059
+ gateMode: "pause",
1060
+ config: project.projectConfig
1061
+ });
831
1062
  engine.registerWorkflows(project.definitions);
832
1063
  if (request.type === "run") {
833
1064
  const workflow = project.registry.workflowById(request.workflowId);
834
1065
  if (!workflow) throw new Error(`Unknown workflow: ${request.workflowId}`);
835
- await engine.runWorkflow(workflow, request.args, { id: request.id, name: request.name, configOverride: request.configOverride });
1066
+ await engine.runWorkflow(workflow, request.args, {
1067
+ id: request.id,
1068
+ name: request.name,
1069
+ configOverride: request.configOverride
1070
+ });
836
1071
  } else {
837
1072
  await engine.resumeRequestedWorkflow({ runRoot, request });
838
1073
  }
839
1074
  } finally {
840
- if (request.type === "run") await rm(join(runRoot, "launch-request.json"), { force: true });
1075
+ if (request.type === "run")
1076
+ await rm(join(runRoot, "launch-request.json"), { force: true });
841
1077
  else await removeResumeRequest({ runRoot, request });
842
1078
  }
843
1079
  }
@@ -854,7 +1090,10 @@ async function rollbackRun(run, args) {
854
1090
  assertNoExtraArgs("runs rollback", args.slice(1));
855
1091
  const project = await findNornProject(process.cwd());
856
1092
  const runRoot = await resolveRunRoot(project.projectRoot, run);
857
- const engine = new NornEngine({ cwd: project.projectRoot, gateMode: "pause" });
1093
+ const engine = new NornEngine({
1094
+ cwd: project.projectRoot,
1095
+ gateMode: "pause"
1096
+ });
858
1097
  writeJson({ run: await engine.rollbackRun(runRoot, checkpointId) });
859
1098
  }
860
1099
  async function inspectRun(run) {
@@ -874,7 +1113,8 @@ async function deleteRun(run) {
874
1113
  const project = await findNornProject(process.cwd());
875
1114
  const runRoot = await resolveRunRoot(project.projectRoot, run);
876
1115
  const runInfo = await getRunInfo(runRoot);
877
- if (runInfo.status === "running") throw new Error(`Stop run before deleting it: ${runInfo.name}`);
1116
+ if (runInfo.status === "running")
1117
+ throw new Error(`Stop run before deleting it: ${runInfo.name}`);
878
1118
  await rm(runRoot, { recursive: true, force: true });
879
1119
  return { id: runInfo.id, name: runInfo.name, path: runInfo.path };
880
1120
  }
@@ -890,7 +1130,8 @@ async function writeRunLogs(run, options) {
890
1130
  let written = 0;
891
1131
  while (true) {
892
1132
  const events = await readRunEvents(runRoot);
893
- for (const event of events.slice(written)) process.stdout.write(`${JSON.stringify(event)}
1133
+ for (const event of events.slice(written))
1134
+ process.stdout.write(`${JSON.stringify(event)}
894
1135
  `);
895
1136
  written = events.length;
896
1137
  if (!options.follow) return;
@@ -912,7 +1153,8 @@ async function startDetachedExecuteRun(runId, projectRoot) {
912
1153
  child.unref();
913
1154
  }
914
1155
  function detachedExecuteRunArgs(runId) {
915
- if (NORN_BUILD_INFO.kind === "github-release-binary") return ["execute-run", runId];
1156
+ if (NORN_BUILD_INFO.kind === "github-release-binary")
1157
+ return ["execute-run", runId];
916
1158
  const scriptPath = process.argv[1];
917
1159
  return scriptPath && isAbsolute(scriptPath) && /\.(?:c?m?js|ts)$/.test(scriptPath) ? [scriptPath, "execute-run", runId] : ["execute-run", runId];
918
1160
  }
@@ -922,7 +1164,10 @@ function startedRunInfo(input) {
922
1164
  id: input.id,
923
1165
  name: input.name,
924
1166
  path: input.runRoot,
925
- paths: { project: input.projectRoot, workspace: join(input.runRoot, "current", "workspace") },
1167
+ paths: {
1168
+ project: input.projectRoot,
1169
+ workspace: join(input.runRoot, "current", "workspace")
1170
+ },
926
1171
  entrypointWorkflowId: input.workflow.id,
927
1172
  currentWorkflowId: input.workflow.id,
928
1173
  status: "running",
@@ -941,7 +1186,9 @@ async function readOptionalRunLaunchRequest(runRoot) {
941
1186
  }
942
1187
  async function readRunEvents(runRoot) {
943
1188
  try {
944
- const manifest = JSON.parse(await readFile(join(runRoot, "current", "manifest.json"), "utf8"));
1189
+ const manifest = JSON.parse(
1190
+ await readFile(join(runRoot, "current", "manifest.json"), "utf8")
1191
+ );
945
1192
  return manifest.events ?? [];
946
1193
  } catch (error) {
947
1194
  if (isNodeError(error) && error.code === "ENOENT") return [];
@@ -979,16 +1226,23 @@ function parseResumeRunInput(value) {
979
1226
  return { args: input.args };
980
1227
  }
981
1228
  function parseStructuredInputObject(command, value) {
982
- if (!value || typeof value !== "object" || Array.isArray(value)) throw new Error(`${command} reads a JSON object from stdin`);
1229
+ if (!value || typeof value !== "object" || Array.isArray(value))
1230
+ throw new Error(`${command} reads a JSON object from stdin`);
983
1231
  return value;
984
1232
  }
985
1233
  function assertStructuredInputKeys(command, input, allowedKeys) {
986
1234
  const allowed = new Set(allowedKeys);
987
1235
  const unexpected = Object.keys(input).filter((key) => !allowed.has(key));
988
- if (unexpected.length > 0) throw new Error(`${command} stdin JSON has unsupported keys: ${unexpected.join(", ")}`);
1236
+ if (unexpected.length > 0)
1237
+ throw new Error(
1238
+ `${command} stdin JSON has unsupported keys: ${unexpected.join(", ")}`
1239
+ );
989
1240
  }
990
1241
  function assertNoStructuredInputArgs(command, args) {
991
- if (args.length > 0) throw new Error(`${command} reads structured input from stdin, not CLI arguments: ${args.join(" ")}`);
1242
+ if (args.length > 0)
1243
+ throw new Error(
1244
+ `${command} reads structured input from stdin, not CLI arguments: ${args.join(" ")}`
1245
+ );
992
1246
  }
993
1247
  function sendSignal(processGroupId, pid, signal) {
994
1248
  try {