perttool 0.1.0 → 0.2.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.
Files changed (64) hide show
  1. package/CHANGELOG.md +66 -33
  2. package/README.md +172 -110
  3. package/dist/application/analyze.js +5 -5
  4. package/dist/application/analyze.js.map +1 -1
  5. package/dist/application/init.d.ts +42 -0
  6. package/dist/application/init.d.ts.map +1 -0
  7. package/dist/application/init.js +217 -0
  8. package/dist/application/init.js.map +1 -0
  9. package/dist/application/mutate.d.ts.map +1 -1
  10. package/dist/application/mutate.js +13 -9
  11. package/dist/application/mutate.js.map +1 -1
  12. package/dist/cli.js +245 -372
  13. package/dist/cli.js.map +1 -1
  14. package/dist/command/discovery.d.ts +30 -0
  15. package/dist/command/discovery.d.ts.map +1 -0
  16. package/dist/command/discovery.js +625 -0
  17. package/dist/command/discovery.js.map +1 -0
  18. package/dist/command/registry.d.ts +84 -0
  19. package/dist/command/registry.d.ts.map +1 -0
  20. package/dist/command/registry.js +951 -0
  21. package/dist/command/registry.js.map +1 -0
  22. package/dist/command/usage.d.ts +42 -0
  23. package/dist/command/usage.d.ts.map +1 -0
  24. package/dist/command/usage.js +337 -0
  25. package/dist/command/usage.js.map +1 -0
  26. package/dist/conversion/mermaid-import.js +56 -56
  27. package/dist/conversion/mermaid-import.js.map +1 -1
  28. package/dist/conversion/mermaid.js +1 -1
  29. package/dist/conversion/mermaid.js.map +1 -1
  30. package/dist/help/guide.d.ts +12 -0
  31. package/dist/help/guide.d.ts.map +1 -0
  32. package/dist/help/guide.js +103 -0
  33. package/dist/help/guide.js.map +1 -0
  34. package/dist/help/registry.d.ts +0 -6
  35. package/dist/help/registry.d.ts.map +1 -1
  36. package/dist/help/registry.js +69 -80
  37. package/dist/help/registry.js.map +1 -1
  38. package/dist/index.d.ts +12 -2
  39. package/dist/index.d.ts.map +1 -1
  40. package/dist/index.js +6 -1
  41. package/dist/index.js.map +1 -1
  42. package/dist/io/safe-write.js +17 -17
  43. package/dist/io/safe-write.js.map +1 -1
  44. package/dist/mutation/gate.d.ts +5 -0
  45. package/dist/mutation/gate.d.ts.map +1 -0
  46. package/dist/mutation/gate.js +156 -0
  47. package/dist/mutation/gate.js.map +1 -0
  48. package/dist/mutation/milestone.js +26 -26
  49. package/dist/mutation/milestone.js.map +1 -1
  50. package/dist/mutation/project.js +14 -14
  51. package/dist/mutation/project.js.map +1 -1
  52. package/dist/mutation/resource.js +22 -22
  53. package/dist/mutation/resource.js.map +1 -1
  54. package/dist/mutation/task.js +40 -40
  55. package/dist/mutation/task.js.map +1 -1
  56. package/dist/mutation/types.d.ts +26 -1
  57. package/dist/mutation/types.d.ts.map +1 -1
  58. package/dist/parser/document-parser.js +17 -17
  59. package/dist/parser/document-parser.js.map +1 -1
  60. package/dist/semantic/validator.js +41 -41
  61. package/dist/semantic/validator.js.map +1 -1
  62. package/dist/version.d.ts +1 -1
  63. package/dist/version.js +1 -1
  64. package/package.json +3 -3
package/dist/cli.js CHANGED
@@ -5,14 +5,18 @@ import { TextDecoder } from "node:util";
5
5
  import { analyzeDocument } from "./application/analyze.js";
6
6
  import { checkDocument } from "./application/check.js";
7
7
  import { planFormat } from "./application/format.js";
8
+ import { planProjectInit, projectInitResultToJson, renderProjectInitResult, withProjectInitOutput, } from "./application/init.js";
8
9
  import { planBatchMutation, planMutation } from "./application/mutate.js";
9
10
  import { selectNextTasks } from "./application/next.js";
10
11
  import { getProjectMetadata, } from "./application/project.js";
11
12
  import { getAgentHelp } from "./application/agent-help.js";
12
13
  import { exportMermaid, } from "./conversion/mermaid.js";
13
14
  import { importMermaid } from "./conversion/mermaid-import.js";
14
- import { getAgentHelpCommandHelp, getHelp, } from "./help/registry.js";
15
- import { serializeAgentGuidanceResult } from "./guidance/projection.js";
15
+ import { getGuide, renderGuideResult, serializeGuideResult, } from "./help/guide.js";
16
+ import { commandOptionSets, } from "./command/registry.js";
17
+ import { CONTRACT3_COMMAND_REGISTRY, getCommandDiscovery, renderCommandHelpResult, serializeCommandHelpResult, } from "./command/discovery.js";
18
+ import { handlerCommandUsageError, renderCommandUsageError, serializeCommandUsageError, validateCommandInvocation, } from "./command/usage.js";
19
+ import { agentGuidanceResultToJson } from "./guidance/projection.js";
16
20
  import { agentGuidanceExitCode, renderAgentGuidanceText, } from "./guidance/text.js";
17
21
  import { documentContentFromBytes, readDocumentFile, } from "./io/document-file.js";
18
22
  import { createArtifactFile, createDocumentFile, replaceDocumentFile, SafeWriteConflictError, SafeWriteVerificationError, } from "./io/safe-write.js";
@@ -25,183 +29,6 @@ import { TOOL_VERSION } from "./version.js";
25
29
  class UsageError extends Error {
26
30
  code = "PTCLI-001";
27
31
  }
28
- function topLevelHelp() {
29
- return [
30
- "perttool - document-based PERT/CPM task management",
31
- "",
32
- "Usage:",
33
- " perttool --version",
34
- " perttool --help",
35
- " perttool dsl check <file> [--format text|json]",
36
- " perttool dsl format <file> [--check] [--diff] [--format text|json]",
37
- " perttool dsl help [topic [subtopic]] [--level index|quick|detail] [--format text|json]",
38
- " perttool agent help [provider [surface]] [--level index|quick|detail] [--format text|json]",
39
- " perttool project show <file> [--format text|json]",
40
- " perttool project set <file> [field options] [--diff] [--write | --out <path>]",
41
- " perttool dag analyze <file> [--schedule precedence|resource|both] [--format text|json]",
42
- " perttool dag next <file> [--capacity <resource-id>=<integer>] [--format text|json]",
43
- " perttool dag advance <file> [--diff] [--write | --out <path>] [--format text|json]",
44
- " perttool dag render <file> --to mermaid [--profile perttool|plain] [--format text|json]",
45
- " perttool dag import <file> --from mermaid [--strict-loss] [--out <path>] [--format text|json]",
46
- " perttool task add|set|remove|finish ...",
47
- " perttool milestone add|set|remove ...",
48
- " perttool resource add|set|remove ...",
49
- " perttool mutation apply <file> --request <json-file|-> [--diff] [--format text|json]",
50
- "",
51
- "Format and mutation commands preview by default; use --write or --out for explicit writes.",
52
- ].join("\n");
53
- }
54
- function commandHelp(resource, action) {
55
- if (resource === "agent" && action === "help") {
56
- return getAgentHelpCommandHelp().syntax.join("\n");
57
- }
58
- if (resource === "dsl" && action === "check") {
59
- return [
60
- "Usage: perttool dsl check <file>",
61
- " [--warnings-as-errors]",
62
- " [--max-diagnostics <integer>]",
63
- " [--format text|json]",
64
- " [--color auto|always|never]",
65
- ].join("\n");
66
- }
67
- if (resource === "dsl" && action === "format")
68
- return [
69
- "Usage: perttool dsl format <file>",
70
- " [--check] [--diff]",
71
- " [--write [--expect-digest <digest>] | --out <path>]",
72
- " [--max-diagnostics <integer>] [--warnings-as-errors]",
73
- " [--format text|json] [--color auto|always|never]",
74
- ].join("\n");
75
- if (resource === "dsl" && action === "help")
76
- return [
77
- "Usage: perttool dsl help [topic [subtopic]]",
78
- " [--level index|quick|detail]",
79
- " [--format text|json]",
80
- " [--color auto|always|never]",
81
- ].join("\n");
82
- if (resource === "project" && action === "show")
83
- return [
84
- "Usage: perttool project show <file>",
85
- " [--max-diagnostics <integer>] [--warnings-as-errors]",
86
- " [--format text|json] [--color auto|always|never]",
87
- ].join("\n");
88
- if (resource === "project" && action === "set")
89
- return [
90
- "Usage: perttool project set <file> [field options]",
91
- " [--id <id>] [--version <integer>] [--title <text>] [--description <text>]",
92
- " [--as-of <date-or-date-time>] [--duration-unit day|hour|point]",
93
- " [--velocity <velocity>] [--finish <milestone-id>]",
94
- " [--critical-epsilon <duration>] [--target-duration <duration>]",
95
- " [--clear description|as_of|velocity|critical_epsilon|target_duration]...",
96
- " [--diff] [--write [--expect-digest <digest>] | --out <path>]",
97
- " [--max-diagnostics <integer>] [--warnings-as-errors]",
98
- " [--format text|json] [--color auto|always|never]",
99
- ].join("\n");
100
- if (resource === "dag" && action === "analyze")
101
- return [
102
- "Usage: perttool dag analyze <file>",
103
- " [--schedule precedence|resource|both]",
104
- " [--capacity <resource-id>=<integer>]...",
105
- " [--max-paths <integer>] [--precision <integer>]",
106
- " [--max-diagnostics <integer>]",
107
- " [--warnings-as-errors]",
108
- " [--format text|json] [--color auto|always|never]",
109
- ].join("\n");
110
- if (resource === "dag" && action === "next")
111
- return [
112
- "Usage: perttool dag next <file>",
113
- " [--capacity <resource-id>=<integer>]...",
114
- " [--explain-depth <integer>] [--precision <integer>]",
115
- " [--max-diagnostics <integer>]",
116
- " [--warnings-as-errors]",
117
- " [--format text|json] [--color auto|always|never]",
118
- "Output: Perttool.NextResult.v3 with a complete recommendation graph in JSON.",
119
- "Consumers must inspect schema_version before using recommendation authority.",
120
- ].join("\n");
121
- if (resource === "dag" && action === "advance")
122
- return [
123
- "Usage: perttool dag advance <file>",
124
- " [--diff] [--write [--expect-digest <digest>] | --out <path>]",
125
- " [--max-diagnostics <integer>] [--warnings-as-errors]",
126
- " [--format text|json] [--color auto|always|never]",
127
- ].join("\n");
128
- if (resource === "dag" && action === "render")
129
- return [
130
- "Usage: perttool dag render <file> --to mermaid",
131
- " [--profile perttool|plain] [--analysis none|precedence|resource|both]",
132
- " [--capacity <resource-id>=<integer>]... [--strict-loss] [--out <path>]",
133
- " [--max-diagnostics <integer>] [--warnings-as-errors]",
134
- " [--format text|json] [--color auto|always|never]",
135
- ].join("\n");
136
- if (resource === "dag" && action === "import")
137
- return [
138
- "Usage: perttool dag import <file> --from mermaid",
139
- " [--strict-loss] [--out <path>]",
140
- " [--max-diagnostics <integer>] [--warnings-as-errors]",
141
- " [--format text|json] [--color auto|always|never]",
142
- ].join("\n");
143
- const preview = " [--diff] [--write [--expect-digest <digest>] | --out <path>] [--max-diagnostics <integer>] [--warnings-as-errors] [--format text|json] [--color auto|always|never]";
144
- if (resource === "task" && action === "add")
145
- return [
146
- "Usage: perttool task add <file> <id> <from> <to>",
147
- " --title <text> (--duration <duration> | --optimistic <duration> --most-likely <duration> --pessimistic <duration>)",
148
- " [--description <text>] [--status planned|active|blocked|done] [--priority <integer>]",
149
- " [--owner <text>] [--blocked-reason <text>] [--source <text>] [--tag <tag>]... [--require <resource-id>=<integer>]...",
150
- preview,
151
- ].join("\n");
152
- if (resource === "task" && action === "set")
153
- return [
154
- "Usage: perttool task set <file> <id> [field options]",
155
- " [--from <id>] [--to <id>] [--title <text>] [--description <text>] [--duration <duration>]",
156
- " [--optimistic <duration> --most-likely <duration> --pessimistic <duration>]",
157
- " [--status planned|active|blocked|done] [--priority <integer>] [--owner <text>]",
158
- " [--blocked-reason <text>] [--source <text>] [--require <resource-id>=<integer>]...",
159
- " [--add-tag <tag>]... [--remove-tag <tag>]... [--remove-require <resource-id>]... [--clear <field>]...",
160
- preview,
161
- ].join("\n");
162
- if (resource === "task")
163
- return [
164
- `Usage: perttool task ${action} <file> <id>`,
165
- preview,
166
- ].join("\n");
167
- if (resource === "milestone" && action === "add")
168
- return [
169
- "Usage: perttool milestone add <file> <id> --title <text>",
170
- " [--description <text>] [--state planned|reached] [--tag <tag>]...",
171
- preview,
172
- ].join("\n");
173
- if (resource === "milestone" && action === "set")
174
- return [
175
- "Usage: perttool milestone set <file> <id> [--title <text>] [--description <text>] [--state planned|reached]",
176
- " [--add-tag <tag>]... [--remove-tag <tag>]... [--clear description|state|tags]...",
177
- preview,
178
- ].join("\n");
179
- if (resource === "milestone")
180
- return [
181
- `Usage: perttool milestone ${action} <file> <id>`,
182
- preview,
183
- ].join("\n");
184
- if (resource === "resource" && action === "add")
185
- return [
186
- "Usage: perttool resource add <file> <id> --title <text> --capacity <integer>",
187
- " [--description <text>]",
188
- preview,
189
- ].join("\n");
190
- if (resource === "resource" && action === "set")
191
- return [
192
- "Usage: perttool resource set <file> <id> [--title <text>] [--description <text>] [--capacity <integer>] [--clear description]",
193
- preview,
194
- ].join("\n");
195
- if (resource === "resource")
196
- return [
197
- `Usage: perttool resource ${action} <file> <id>`,
198
- preview,
199
- ].join("\n");
200
- return [
201
- "Usage: perttool mutation apply <file> --request <json-file|->",
202
- preview,
203
- ].join("\n");
204
- }
205
32
  function parseOptions(args, valueOptions, flagOptions, repeatableOptions = new Set()) {
206
33
  const positionals = [];
207
34
  const values = new Map();
@@ -251,6 +78,14 @@ function parseOptions(args, valueOptions, flagOptions, repeatableOptions = new S
251
78
  }
252
79
  return { positionals, values, repeatedValues, flags };
253
80
  }
81
+ function parseCommandOptions(operation, args) {
82
+ const descriptor = CONTRACT3_COMMAND_REGISTRY.find((candidate) => candidate.operation === operation);
83
+ if (descriptor === undefined) {
84
+ throw new Error(`command descriptor is missing for ${operation}`);
85
+ }
86
+ const optionSets = commandOptionSets(descriptor);
87
+ return parseOptions(args, optionSets.values, optionSets.flags, optionSets.repeatable);
88
+ }
254
89
  function outputFormat(value) {
255
90
  if (value === undefined || value === "text")
256
91
  return "text";
@@ -300,7 +135,8 @@ function jsonDiagnostic(diagnostic) {
300
135
  message: related.message,
301
136
  span: jsonSpan(related.span),
302
137
  })),
303
- help_topic: diagnostic.helpTopic ?? null,
138
+ help_topic: null,
139
+ guide_topic: diagnostic.helpTopic ?? null,
304
140
  expected_syntax: diagnostic.expectedSyntax ?? null,
305
141
  fixes: [],
306
142
  data: diagnostic.data ?? {},
@@ -326,7 +162,7 @@ function renderDiagnostic(diagnostic, source, mode) {
326
162
  }
327
163
  if (diagnostic.helpTopic !== undefined) {
328
164
  const [topic, subtopic] = diagnostic.helpTopic.split(".", 2);
329
- lines.push(` help: perttool dsl help ${topic}${subtopic === undefined ? "" : ` ${subtopic}`} --level quick`);
165
+ lines.push(` guide: perttool guide ${topic}${subtopic === undefined ? "" : ` ${subtopic}`} --level quick`);
330
166
  }
331
167
  return lines.join("\n");
332
168
  }
@@ -369,6 +205,7 @@ function cliError(error, exitCode, operation, json) {
369
205
  if (json) {
370
206
  writeJson({
371
207
  schema_version: "Perttool.CliError.v1",
208
+ cli_contract_version: 3,
372
209
  tool_version: TOOL_VERSION,
373
210
  operation,
374
211
  ok: false,
@@ -381,9 +218,9 @@ function cliError(error, exitCode, operation, json) {
381
218
  return exitCode;
382
219
  }
383
220
  async function runCheck(args) {
384
- const parsed = parseOptions(args, new Set(["format", "color", "max-diagnostics"]), new Set(["warnings-as-errors"]));
221
+ const parsed = parseCommandOptions("document.check", args);
385
222
  if (parsed.positionals.length !== 1) {
386
- throw new UsageError("dsl check requires exactly one <file>");
223
+ throw new UsageError("document check requires exactly one <file>");
387
224
  }
388
225
  const format = outputFormat(parsed.values.get("format"));
389
226
  const color = colorMode(parsed.values.get("color"), format);
@@ -395,7 +232,7 @@ async function runCheck(args) {
395
232
  input = await readDocument(sourceOperand);
396
233
  }
397
234
  catch (error) {
398
- return cliError(error instanceof Error ? error : new Error(String(error)), 3, "dsl.check", format === "json");
235
+ return cliError(error instanceof Error ? error : new Error(String(error)), 3, "document.check", format === "json");
399
236
  }
400
237
  const result = checkDocument(input.text, { maxDiagnostics });
401
238
  const warningsAsErrors = parsed.flags.has("warnings-as-errors");
@@ -404,8 +241,9 @@ async function runCheck(args) {
404
241
  if (format === "json") {
405
242
  writeJson({
406
243
  schema_version: "Perttool.CheckResult.v1",
244
+ cli_contract_version: 3,
407
245
  tool_version: TOOL_VERSION,
408
- operation: "dsl.check",
246
+ operation: "document.check",
409
247
  ok,
410
248
  document_id: result.documentId,
411
249
  source,
@@ -460,7 +298,7 @@ function renderProjectText(project) {
460
298
  ].join("\n");
461
299
  }
462
300
  async function runProjectShow(args) {
463
- const parsed = parseOptions(args, new Set(["format", "color", "max-diagnostics"]), new Set(["warnings-as-errors"]));
301
+ const parsed = parseCommandOptions("project.show", args);
464
302
  if (parsed.positionals.length !== 1) {
465
303
  throw new UsageError("project show requires exactly one <file>");
466
304
  }
@@ -484,6 +322,7 @@ async function runProjectShow(args) {
484
322
  if (format === "json") {
485
323
  writeJson({
486
324
  schema_version: "Perttool.ProjectResult.v1",
325
+ cli_contract_version: 3,
487
326
  tool_version: TOOL_VERSION,
488
327
  operation: "project.show",
489
328
  ok,
@@ -509,6 +348,56 @@ async function runProjectShow(args) {
509
348
  }
510
349
  return ok ? 0 : 1;
511
350
  }
351
+ async function runProjectInit(args) {
352
+ const parsed = parseCommandOptions("project.init", args);
353
+ const format = outputFormat(parsed.values.get("format"));
354
+ const color = colorMode(parsed.values.get("color"), format);
355
+ const durationUnit = enumOption(requiredOption(parsed, "duration-unit"), "duration-unit", new Set(["day", "hour", "point"]));
356
+ const version = optionalInteger(parsed, "version", 0, 2_147_483_647);
357
+ let result = planProjectInit({
358
+ projectId: parsed.positionals[0],
359
+ title: requiredOption(parsed, "title"),
360
+ durationUnit,
361
+ initialMilestone: requiredOption(parsed, "initial-milestone"),
362
+ initialMilestoneTitle: requiredOption(parsed, "initial-milestone-title"),
363
+ finish: requiredOption(parsed, "finish"),
364
+ ...(version === undefined ? {} : { version }),
365
+ ...(parsed.values.get("as-of") === undefined
366
+ ? {}
367
+ : { asOf: parsed.values.get("as-of") }),
368
+ ...(parsed.values.get("velocity") === undefined
369
+ ? {}
370
+ : { velocity: parsed.values.get("velocity") }),
371
+ });
372
+ let writeResult = null;
373
+ const output = parsed.values.get("out");
374
+ if (result.ok && output !== undefined) {
375
+ try {
376
+ writeResult = await createDocumentFile(output, result.candidateText);
377
+ result = withProjectInitOutput(result, writeResult);
378
+ }
379
+ catch (error) {
380
+ return writeFailureExit(error, "project.init", format === "json");
381
+ }
382
+ }
383
+ if (format === "json") {
384
+ writeJson(projectInitResultToJson(result));
385
+ }
386
+ else {
387
+ if (result.ok) {
388
+ if (writeResult === null) {
389
+ process.stdout.write(renderProjectInitResult(result));
390
+ }
391
+ else {
392
+ process.stderr.write(renderWriteSummary("project.init", writeResult));
393
+ }
394
+ }
395
+ for (const diagnostic of result.diagnostics) {
396
+ process.stderr.write(`${renderDiagnostic(diagnostic, "<project-init>", color)}\n`);
397
+ }
398
+ }
399
+ return result.ok ? 0 : 1;
400
+ }
512
401
  function boundedInteger(raw, option, defaultValue, minimum, maximum) {
513
402
  if (raw === undefined)
514
403
  return defaultValue;
@@ -546,14 +435,6 @@ function capacityOverrides(values) {
546
435
  }
547
436
  return overrides;
548
437
  }
549
- const mutationCommonValueOptions = [
550
- "format",
551
- "color",
552
- "max-diagnostics",
553
- "out",
554
- "expect-digest",
555
- ];
556
- const mutationCommonFlagOptions = ["diff", "write", "warnings-as-errors"];
557
438
  function editingWriteRequest(parsed, sourceOperand, check = false) {
558
439
  const write = parsed.flags.has("write");
559
440
  const out = parsed.values.get("out");
@@ -594,12 +475,12 @@ function assertExpectedDigest(request, initialDigest) {
594
475
  if (request.mode === "in_place" &&
595
476
  request.expectedDigest !== undefined &&
596
477
  request.expectedDigest !== initialDigest) {
597
- throw new SafeWriteConflictError("expected_digest_mismatch", "--expect-digestinitial document digestと一致しません");
478
+ throw new SafeWriteConflictError("expected_digest_mismatch", "--expect-digest does not match the initial document digest");
598
479
  }
599
480
  }
600
481
  async function commitCandidate(request, candidateText, initialDigest) {
601
482
  if (candidateText === null) {
602
- throw new SafeWriteVerificationError("invalid_candidate", "successful editing resultcandidate textがありません");
483
+ throw new SafeWriteVerificationError("invalid_candidate", "successful editing result has no candidate text");
603
484
  }
604
485
  return request.mode === "in_place"
605
486
  ? replaceDocumentFile(request.target, candidateText, {
@@ -623,9 +504,9 @@ function renderWriteSummary(operation, result) {
623
504
  return `WRITE ${operation} mode=${result.mode} target=${result.target} digest=${result.digest} written=${result.written}\n`;
624
505
  }
625
506
  async function runFormat(args) {
626
- const parsed = parseOptions(args, new Set(["format", "color", "max-diagnostics", "out", "expect-digest"]), new Set(["check", "diff", "write", "warnings-as-errors"]));
507
+ const parsed = parseCommandOptions("document.format", args);
627
508
  if (parsed.positionals.length !== 1) {
628
- throw new UsageError("dsl format requires exactly one <file>");
509
+ throw new UsageError("document format requires exactly one <file>");
629
510
  }
630
511
  const format = outputFormat(parsed.values.get("format"));
631
512
  const color = colorMode(parsed.values.get("color"), format);
@@ -638,7 +519,7 @@ async function runFormat(args) {
638
519
  input = await readDocument(sourceOperand);
639
520
  }
640
521
  catch (error) {
641
- return cliError(error instanceof Error ? error : new Error(String(error)), 3, "dsl.format", format === "json");
522
+ return cliError(error instanceof Error ? error : new Error(String(error)), 3, "document.format", format === "json");
642
523
  }
643
524
  const result = planFormat(input.text, {
644
525
  maxDiagnostics,
@@ -659,14 +540,15 @@ async function runFormat(args) {
659
540
  }
660
541
  }
661
542
  catch (error) {
662
- return writeFailureExit(error, "dsl.format", format === "json");
543
+ return writeFailureExit(error, "document.format", format === "json");
663
544
  }
664
545
  }
665
546
  if (format === "json") {
666
547
  writeJson({
667
548
  schema_version: "Perttool.FormatResult.v1",
549
+ cli_contract_version: 3,
668
550
  tool_version: TOOL_VERSION,
669
- operation: "dsl.format",
551
+ operation: "document.format",
670
552
  ok,
671
553
  document_id: result.documentId,
672
554
  source,
@@ -680,7 +562,7 @@ async function runFormat(args) {
680
562
  const candidateAllowed = result.ok && !warningFailure;
681
563
  if (candidateAllowed) {
682
564
  if (writeResult !== null) {
683
- process.stderr.write(renderWriteSummary("dsl.format", writeResult));
565
+ process.stderr.write(renderWriteSummary("document.format", writeResult));
684
566
  }
685
567
  else if (parsed.flags.has("check")) {
686
568
  if (parsed.flags.has("diff"))
@@ -689,7 +571,7 @@ async function runFormat(args) {
689
571
  else {
690
572
  process.stdout.write(parsed.flags.has("diff") ? (result.diff ?? "") : (result.updatedText ?? ""));
691
573
  if (!parsed.flags.has("diff")) {
692
- process.stderr.write(`PREVIEW dsl.format changed=${result.changed} original_digest=${result.originalDigest} updated_digest=${result.updatedDigest}\n`);
574
+ process.stderr.write(`PREVIEW document.format changed=${result.changed} original_digest=${result.originalDigest} updated_digest=${result.updatedDigest}\n`);
693
575
  }
694
576
  }
695
577
  }
@@ -702,50 +584,6 @@ async function runFormat(args) {
702
584
  }
703
585
  return ok ? 0 : 1;
704
586
  }
705
- function mutationOptionSets(resource, action) {
706
- const values = new Set(mutationCommonValueOptions);
707
- const flags = new Set(mutationCommonFlagOptions);
708
- const repeatable = new Set();
709
- const addValues = (...names) => {
710
- for (const name of names)
711
- values.add(name);
712
- };
713
- const addRepeatable = (...names) => {
714
- for (const name of names)
715
- repeatable.add(name);
716
- };
717
- if (resource === "project" && action === "set") {
718
- addValues("id", "version", "title", "description", "as-of", "duration-unit", "velocity", "finish", "critical-epsilon", "target-duration");
719
- addRepeatable("clear");
720
- }
721
- else if (resource === "task" && action === "add") {
722
- addValues("title", "description", "duration", "optimistic", "most-likely", "pessimistic", "status", "priority", "owner", "blocked-reason", "source");
723
- addRepeatable("tag", "require");
724
- }
725
- else if (resource === "task" && action === "set") {
726
- addValues("from", "to", "title", "description", "duration", "optimistic", "most-likely", "pessimistic", "status", "priority", "owner", "blocked-reason", "source");
727
- addRepeatable("require", "add-tag", "remove-tag", "remove-require", "clear");
728
- }
729
- else if (resource === "milestone" && action === "add") {
730
- addValues("title", "description", "state");
731
- addRepeatable("tag");
732
- }
733
- else if (resource === "milestone" && action === "set") {
734
- addValues("title", "description", "state");
735
- addRepeatable("add-tag", "remove-tag", "clear");
736
- }
737
- else if (resource === "resource" && action === "add") {
738
- addValues("title", "description", "capacity");
739
- }
740
- else if (resource === "resource" && action === "set") {
741
- addValues("title", "description", "capacity");
742
- addRepeatable("clear");
743
- }
744
- else if (resource === "mutation" && action === "apply") {
745
- addValues("request");
746
- }
747
- return { values, flags, repeatable };
748
- }
749
587
  function requiredOption(parsed, name) {
750
588
  const value = parsed.values.get(name);
751
589
  if (value === undefined)
@@ -1086,6 +924,37 @@ function resourceMutationFromOptions(action, parsed) {
1086
924
  ...(clear.length === 0 ? {} : { clear }),
1087
925
  };
1088
926
  }
927
+ function gateMutationFromOptions(action, parsed) {
928
+ const expectedPositionals = action === "add" ? 4 : 2;
929
+ if (parsed.positionals.length !== expectedPositionals) {
930
+ throw new UsageError(`gate ${action} requires ${action === "add" ? "<file> <id> <from> <to>" : "<file> <id>"}`);
931
+ }
932
+ const id = parsed.positionals[1];
933
+ if (action === "remove")
934
+ return { kind: "gate.remove", id };
935
+ if (action === "add") {
936
+ return {
937
+ kind: "gate.add",
938
+ id,
939
+ from: parsed.positionals[2],
940
+ to: parsed.positionals[3],
941
+ gate: { reason: requiredOption(parsed, "reason") },
942
+ };
943
+ }
944
+ const from = parsed.values.get("from");
945
+ const to = parsed.values.get("to");
946
+ const reason = parsed.values.get("reason");
947
+ if (from === undefined && to === undefined && reason === undefined) {
948
+ throw new UsageError("gate set requires --from, --to, or --reason");
949
+ }
950
+ return {
951
+ kind: "gate.set",
952
+ id,
953
+ ...(from === undefined ? {} : { from }),
954
+ ...(to === undefined ? {} : { to }),
955
+ ...(reason === undefined ? {} : { set: { reason } }),
956
+ };
957
+ }
1089
958
  function previewResultJson(result, exposeCandidate, writeRequest = { mode: "preview", target: null }, writeResult = null) {
1090
959
  return {
1091
960
  changed: exposeCandidate ? result.changed : false,
@@ -1116,8 +985,7 @@ async function readMutationRequest(source) {
1116
985
  }
1117
986
  }
1118
987
  async function runMutation(resource, action, args) {
1119
- const config = mutationOptionSets(resource, action);
1120
- const parsed = parseOptions(args, config.values, config.flags, config.repeatable);
988
+ const parsed = parseCommandOptions(`${resource}.${action}`, args);
1121
989
  const format = outputFormat(parsed.values.get("format"));
1122
990
  const color = colorMode(parsed.values.get("color"), format);
1123
991
  const maxDiagnostics = boundedInteger(parsed.values.get("max-diagnostics"), "max-diagnostics", 100, 1, 1000);
@@ -1125,9 +993,9 @@ async function runMutation(resource, action, args) {
1125
993
  let sourceOperand;
1126
994
  let writeRequest;
1127
995
  let mutation;
1128
- if (resource === "mutation") {
996
+ if (resource === "batch") {
1129
997
  if (parsed.positionals.length !== 1) {
1130
- throw new UsageError("mutation apply requires exactly one <file>");
998
+ throw new UsageError("batch apply requires exactly one <file>");
1131
999
  }
1132
1000
  sourceOperand = parsed.positionals[0];
1133
1001
  writeRequest = editingWriteRequest(parsed, sourceOperand);
@@ -1152,9 +1020,11 @@ async function runMutation(resource, action, args) {
1152
1020
  ? projectMutationFromOptions(parsed)
1153
1021
  : resource === "task"
1154
1022
  ? taskMutationFromOptions(action, parsed)
1155
- : resource === "milestone"
1156
- ? milestoneMutationFromOptions(action, parsed)
1157
- : resourceMutationFromOptions(action, parsed);
1023
+ : resource === "gate"
1024
+ ? gateMutationFromOptions(action, parsed)
1025
+ : resource === "milestone"
1026
+ ? milestoneMutationFromOptions(action, parsed)
1027
+ : resourceMutationFromOptions(action, parsed);
1158
1028
  sourceOperand = parsed.positionals[0];
1159
1029
  writeRequest = editingWriteRequest(parsed, sourceOperand);
1160
1030
  }
@@ -1171,7 +1041,7 @@ async function runMutation(resource, action, args) {
1171
1041
  originalLabel: source,
1172
1042
  updatedLabel: "candidate",
1173
1043
  };
1174
- const result = resource === "mutation"
1044
+ const result = resource === "batch"
1175
1045
  ? planBatchMutation(input.text, mutation, mutationOptions)
1176
1046
  : planMutation(input.text, mutation, mutationOptions);
1177
1047
  const warningFailure = parsed.flags.has("warnings-as-errors") &&
@@ -1193,6 +1063,7 @@ async function runMutation(resource, action, args) {
1193
1063
  if (format === "json") {
1194
1064
  writeJson({
1195
1065
  schema_version: "Perttool.MutationResult.v1",
1066
+ cli_contract_version: 3,
1196
1067
  tool_version: TOOL_VERSION,
1197
1068
  operation,
1198
1069
  ok,
@@ -1247,7 +1118,7 @@ function renderAdvanceSummary(details) {
1247
1118
  ].join("\n");
1248
1119
  }
1249
1120
  async function runAdvance(args) {
1250
- const parsed = parseOptions(args, new Set(["format", "color", "max-diagnostics", "out", "expect-digest"]), new Set(["diff", "write", "warnings-as-errors"]));
1121
+ const parsed = parseCommandOptions("dag.advance", args);
1251
1122
  if (parsed.positionals.length !== 1) {
1252
1123
  throw new UsageError("dag advance requires exactly one <file>");
1253
1124
  }
@@ -1288,6 +1159,7 @@ async function runAdvance(args) {
1288
1159
  if (format === "json") {
1289
1160
  writeJson({
1290
1161
  schema_version: "Perttool.MutationResult.v1",
1162
+ cli_contract_version: 3,
1291
1163
  tool_version: TOOL_VERSION,
1292
1164
  operation: "dag.advance",
1293
1165
  ok,
@@ -1568,14 +1440,7 @@ function renderAnalysisText(result) {
1568
1440
  return `${lines.join("\n")}\n`;
1569
1441
  }
1570
1442
  async function runAnalyze(args) {
1571
- const parsed = parseOptions(args, new Set([
1572
- "schedule",
1573
- "max-paths",
1574
- "precision",
1575
- "max-diagnostics",
1576
- "format",
1577
- "color",
1578
- ]), new Set(["warnings-as-errors"]), new Set(["capacity"]));
1443
+ const parsed = parseCommandOptions("dag.analyze", args);
1579
1444
  if (parsed.positionals.length !== 1) {
1580
1445
  throw new UsageError("dag analyze requires exactly one <file>");
1581
1446
  }
@@ -1609,6 +1474,7 @@ async function runAnalyze(args) {
1609
1474
  if (format === "json") {
1610
1475
  writeJson({
1611
1476
  schema_version: "Perttool.AnalysisResult.v2",
1477
+ cli_contract_version: 3,
1612
1478
  tool_version: TOOL_VERSION,
1613
1479
  operation: "dag.analyze",
1614
1480
  ok,
@@ -1668,15 +1534,7 @@ function renderConversionLoss(loss, source, color) {
1668
1534
  }, source, color);
1669
1535
  }
1670
1536
  async function runRender(args) {
1671
- const parsed = parseOptions(args, new Set([
1672
- "to",
1673
- "profile",
1674
- "analysis",
1675
- "out",
1676
- "max-diagnostics",
1677
- "format",
1678
- "color",
1679
- ]), new Set(["strict-loss", "warnings-as-errors"]), new Set(["capacity"]));
1537
+ const parsed = parseCommandOptions("dag.render", args);
1680
1538
  if (parsed.positionals.length !== 1) {
1681
1539
  throw new UsageError("dag render requires exactly one <file>");
1682
1540
  }
@@ -1728,6 +1586,7 @@ async function runRender(args) {
1728
1586
  if (format === "json") {
1729
1587
  writeJson({
1730
1588
  schema_version: "Perttool.ExportResult.v1",
1589
+ cli_contract_version: 3,
1731
1590
  tool_version: TOOL_VERSION,
1732
1591
  operation: "dag.render",
1733
1592
  ok,
@@ -1778,7 +1637,7 @@ async function runRender(args) {
1778
1637
  return strictFailure ? 4 : ok ? 0 : 1;
1779
1638
  }
1780
1639
  async function runImport(args) {
1781
- const parsed = parseOptions(args, new Set(["from", "out", "max-diagnostics", "format", "color"]), new Set(["strict-loss", "warnings-as-errors"]));
1640
+ const parsed = parseCommandOptions("dag.import", args);
1782
1641
  if (parsed.positionals.length !== 1) {
1783
1642
  throw new UsageError("dag import requires exactly one <file>");
1784
1643
  }
@@ -1819,6 +1678,7 @@ async function runImport(args) {
1819
1678
  if (format === "json") {
1820
1679
  writeJson({
1821
1680
  schema_version: "Perttool.ImportResult.v1",
1681
+ cli_contract_version: 3,
1822
1682
  tool_version: TOOL_VERSION,
1823
1683
  operation: "dag.import",
1824
1684
  ok,
@@ -2077,7 +1937,7 @@ function renderNextText(result) {
2077
1937
  return `${lines.join("\n")}\n`;
2078
1938
  }
2079
1939
  async function runNext(args) {
2080
- const parsed = parseOptions(args, new Set(["explain-depth", "precision", "max-diagnostics", "format", "color"]), new Set(["warnings-as-errors"]), new Set(["capacity"]));
1940
+ const parsed = parseCommandOptions("dag.next", args);
2081
1941
  if (parsed.positionals.length !== 1) {
2082
1942
  throw new UsageError("dag next requires exactly one <file>");
2083
1943
  }
@@ -2108,6 +1968,7 @@ async function runNext(args) {
2108
1968
  if (format === "json") {
2109
1969
  writeJson({
2110
1970
  schema_version: "Perttool.CliError.v1",
1971
+ cli_contract_version: 3,
2111
1972
  tool_version: TOOL_VERSION,
2112
1973
  operation: "dag.next",
2113
1974
  ok: false,
@@ -2128,6 +1989,7 @@ async function runNext(args) {
2128
1989
  if (format === "json") {
2129
1990
  writeJson({
2130
1991
  schema_version: "Perttool.NextResult.v3",
1992
+ cli_contract_version: 3,
2131
1993
  recommendation_interface_version: 1,
2132
1994
  tool_version: TOOL_VERSION,
2133
1995
  operation: "dag.next",
@@ -2152,65 +2014,56 @@ async function runNext(args) {
2152
2014
  }
2153
2015
  return ok ? 0 : 1;
2154
2016
  }
2155
- function renderHelpText(result) {
2156
- const lines = [result.title, "", result.summary];
2157
- if (result.topics.length > 0) {
2158
- lines.push("", "Topics:");
2159
- for (const topic of result.topics)
2160
- lines.push(` ${topic.id.padEnd(12)} ${topic.summary}`);
2161
- }
2162
- for (const section of result.sections) {
2163
- lines.push("", section.title, section.body);
2164
- }
2165
- if (result.syntax.length > 0)
2166
- lines.push("", "Syntax:", ...result.syntax.map((line) => ` ${line}`));
2167
- if (result.examples.length > 0) {
2168
- lines.push("", "Examples:", ...result.examples.map((example) => ` ${example.id}: ${example.text}`));
2169
- }
2170
- if (result.related.length > 0)
2171
- lines.push("", `Related: ${result.related.join(", ")}`);
2172
- return `${lines.join("\n")}\n`;
2173
- }
2174
- function runHelp(args) {
2175
- const parsed = parseOptions(args, new Set(["level", "format", "color"]), new Set());
2017
+ function runGuide(args) {
2018
+ const parsed = parseCommandOptions("guide", args);
2176
2019
  if (parsed.positionals.length > 2) {
2177
- throw new UsageError("dsl help accepts at most <topic> <subtopic>");
2020
+ throw new UsageError("guide accepts at most <topic> <subtopic>");
2178
2021
  }
2179
2022
  const format = outputFormat(parsed.values.get("format"));
2180
2023
  colorMode(parsed.values.get("color"), format);
2181
2024
  const topicId = parsed.positionals.length === 0 ? null : parsed.positionals.join(".");
2182
2025
  const level = helpLevel(parsed.values.get("level"), topicId !== null);
2183
- const result = getHelp(topicId, level);
2026
+ const result = getGuide(topicId, level);
2184
2027
  if (format === "json") {
2185
- writeJson({
2186
- schema_version: "Perttool.HelpResult.v1",
2187
- tool_version: TOOL_VERSION,
2188
- operation: "dsl.help",
2189
- ok: result.ok,
2190
- diagnostics: result.diagnostics.map(jsonDiagnostic),
2191
- topic_id: result.topicId,
2192
- level: result.level,
2193
- title: result.title,
2194
- summary: result.summary,
2195
- sections: result.sections,
2196
- syntax: result.syntax,
2197
- examples: result.examples,
2198
- related: result.related,
2199
- topics: result.topics,
2200
- });
2028
+ process.stdout.write(serializeGuideResult(result));
2201
2029
  }
2202
- else if (result.ok) {
2203
- process.stdout.write(renderHelpText(result));
2030
+ else {
2031
+ const rendered = renderGuideResult(result);
2032
+ if (result.ok) {
2033
+ process.stdout.write(rendered);
2034
+ }
2035
+ else {
2036
+ process.stderr.write(rendered);
2037
+ }
2038
+ }
2039
+ return result.ok ? 0 : 1;
2040
+ }
2041
+ function runCommandHelp(args) {
2042
+ const parsed = parseCommandOptions("help", args);
2043
+ if (parsed.positionals.length > 2) {
2044
+ throw new UsageError("help accepts at most <resource> <action>");
2045
+ }
2046
+ const format = outputFormat(parsed.values.get("format"));
2047
+ const result = getCommandDiscovery({
2048
+ resource: parsed.positionals[0] ?? null,
2049
+ action: parsed.positionals[1] ?? null,
2050
+ });
2051
+ if (format === "json") {
2052
+ process.stdout.write(serializeCommandHelpResult(result));
2204
2053
  }
2205
2054
  else {
2206
- for (const diagnostic of result.diagnostics) {
2207
- process.stderr.write(`${renderDiagnostic(diagnostic, "<help>", "never")}\n`);
2055
+ const rendered = renderCommandHelpResult(result);
2056
+ if (result.ok) {
2057
+ process.stdout.write(rendered);
2058
+ }
2059
+ else {
2060
+ process.stderr.write(rendered);
2208
2061
  }
2209
2062
  }
2210
2063
  return result.ok ? 0 : 1;
2211
2064
  }
2212
2065
  function runAgentHelp(args) {
2213
- const parsed = parseOptions(args, new Set(["level", "format", "color"]), new Set());
2066
+ const parsed = parseCommandOptions("agent.help", args);
2214
2067
  if (parsed.positionals.length > 2) {
2215
2068
  throw new UsageError("agent help accepts at most <provider> <surface>");
2216
2069
  }
@@ -2225,7 +2078,13 @@ function runAgentHelp(args) {
2225
2078
  level,
2226
2079
  });
2227
2080
  if (format === "json") {
2228
- process.stdout.write(serializeAgentGuidanceResult(result));
2081
+ const projected = agentGuidanceResultToJson(result);
2082
+ const { schema_version: schemaVersion, ...payload } = projected;
2083
+ writeJson({
2084
+ schema_version: schemaVersion,
2085
+ cli_contract_version: 3,
2086
+ ...payload,
2087
+ });
2229
2088
  }
2230
2089
  else {
2231
2090
  if (result.ok) {
@@ -2245,74 +2104,88 @@ function runAgentHelp(args) {
2245
2104
  }
2246
2105
  return agentGuidanceExitCode(result.diagnostics);
2247
2106
  }
2107
+ async function dispatchCommand(descriptor, args) {
2108
+ switch (descriptor.operation) {
2109
+ case "help":
2110
+ return runCommandHelp(args);
2111
+ case "guide":
2112
+ return runGuide(args);
2113
+ case "document.check":
2114
+ return runCheck(args);
2115
+ case "document.format":
2116
+ return runFormat(args);
2117
+ case "agent.help":
2118
+ return runAgentHelp(args);
2119
+ case "project.init":
2120
+ return runProjectInit(args);
2121
+ case "project.show":
2122
+ return runProjectShow(args);
2123
+ case "dag.analyze":
2124
+ return runAnalyze(args);
2125
+ case "dag.next":
2126
+ return runNext(args);
2127
+ case "dag.advance":
2128
+ return runAdvance(args);
2129
+ case "dag.render":
2130
+ return runRender(args);
2131
+ case "dag.import":
2132
+ return runImport(args);
2133
+ }
2134
+ if (descriptor.path.length === 2
2135
+ && (descriptor.operation === "project.set"
2136
+ || descriptor.operation === "batch.apply"
2137
+ || /^(?:task|gate|milestone|resource)\.(?:add|set|remove|finish)$/.test(descriptor.operation))) {
2138
+ const [resource, action] = descriptor.path;
2139
+ return runMutation(resource, action, args);
2140
+ }
2141
+ throw new Error(`no Contract 3 handler for ${descriptor.operation}`);
2142
+ }
2143
+ function emitCommandUsage(error, json) {
2144
+ if (json) {
2145
+ process.stdout.write(serializeCommandUsageError(error));
2146
+ }
2147
+ else {
2148
+ process.stderr.write(renderCommandUsageError(error));
2149
+ }
2150
+ return 2;
2151
+ }
2248
2152
  async function main(argv) {
2249
2153
  if (argv.length === 1 && argv[0] === "--version") {
2250
2154
  process.stdout.write(`perttool ${TOOL_VERSION}\n`);
2251
2155
  return 0;
2252
2156
  }
2253
2157
  if (argv.length === 1 && argv[0] === "--help") {
2254
- process.stdout.write(`${topLevelHelp()}\n`);
2255
- return 0;
2158
+ return runCommandHelp([]);
2256
2159
  }
2257
- if (argv.length < 2)
2258
- throw new UsageError("expected <resource> <action>");
2259
- const resource = argv[0];
2260
- const action = argv[1];
2261
- const entityActions = new Map([
2262
- ["project", new Set(["set"])],
2263
- ["task", new Set(["add", "set", "remove", "finish"])],
2264
- ["milestone", new Set(["add", "set", "remove"])],
2265
- ["resource", new Set(["add", "set", "remove"])],
2266
- ["mutation", new Set(["apply"])],
2267
- ]);
2268
- const isMutationCommand = entityActions.get(resource)?.has(action) === true;
2269
- if (argv.length === 3 &&
2270
- argv[2] === "--help" &&
2271
- ((resource === "agent" && action === "help") ||
2272
- (resource === "dsl" && ["check", "format", "help"].includes(action)) ||
2273
- (resource === "project" && action === "show") ||
2274
- (resource === "dag" && ["analyze", "next", "advance", "render", "import"].includes(action)) ||
2275
- isMutationCommand)) {
2276
- process.stdout.write(`${commandHelp(resource, action)}\n`);
2277
- return 0;
2278
- }
2279
- if (resource === "dag" && action === "analyze") {
2280
- return runAnalyze(argv.slice(2));
2281
- }
2282
- if (resource === "dag" && action === "next") {
2283
- return runNext(argv.slice(2));
2284
- }
2285
- if (resource === "dag" && action === "advance") {
2286
- return runAdvance(argv.slice(2));
2287
- }
2288
- if (resource === "dag" && action === "render") {
2289
- return runRender(argv.slice(2));
2290
- }
2291
- if (resource === "dag" && action === "import") {
2292
- return runImport(argv.slice(2));
2293
- }
2294
- if (resource === "agent" && action === "help") {
2295
- return runAgentHelp(argv.slice(2));
2296
- }
2297
- if (resource === "project" && action === "show") {
2298
- return runProjectShow(argv.slice(2));
2160
+ const validation = validateCommandInvocation(argv);
2161
+ if (!validation.ok) {
2162
+ if (jsonRequested(argv)) {
2163
+ process.stdout.write(serializeCommandUsageError(validation.error));
2164
+ }
2165
+ else {
2166
+ process.stderr.write(renderCommandUsageError(validation.error));
2167
+ }
2168
+ return 2;
2299
2169
  }
2300
- if (resource === "dsl" && action === "format") {
2301
- return runFormat(argv.slice(2));
2170
+ const descriptor = validation.descriptor;
2171
+ if (validation.helpAlias) {
2172
+ return runCommandHelp([...descriptor.path]);
2302
2173
  }
2303
- if (isMutationCommand) {
2304
- return runMutation(resource, action, argv.slice(2));
2174
+ try {
2175
+ return await dispatchCommand(descriptor, argv.slice(descriptor.path.length));
2305
2176
  }
2306
- if (resource !== "dsl" || (action !== "check" && action !== "help")) {
2307
- throw new UsageError(`unknown or not-yet-implemented command: ${resource} ${action}`);
2177
+ catch (error) {
2178
+ if (error instanceof UsageError) {
2179
+ return emitCommandUsage(handlerCommandUsageError(descriptor, error.message), jsonRequested(argv));
2180
+ }
2181
+ throw error;
2308
2182
  }
2309
- return action === "check" ? runCheck(argv.slice(2)) : runHelp(argv.slice(2));
2310
2183
  }
2311
2184
  const args = process.argv.slice(2);
2312
2185
  try {
2313
2186
  process.exitCode = await main(args);
2314
2187
  }
2315
2188
  catch (error) {
2316
- process.exitCode = cliError(error instanceof Error ? error : new Error(String(error)), error instanceof UsageError ? 2 : 70, args.length >= 2 ? `${args[0]}.${args[1]}` : null, jsonRequested(args));
2189
+ process.exitCode = cliError(error instanceof Error ? error : new Error(String(error)), 70, null, jsonRequested(args));
2317
2190
  }
2318
2191
  //# sourceMappingURL=cli.js.map