@duyquangnvx/agent-cli 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 (63) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/README.md +11 -0
  3. package/dist/command-spec.d.ts +28 -0
  4. package/dist/command-spec.js +31 -0
  5. package/dist/command-spec.js.map +1 -0
  6. package/dist/confirm.d.ts +0 -1
  7. package/dist/confirm.js +4 -4
  8. package/dist/confirm.js.map +1 -1
  9. package/dist/define.d.ts +30 -6
  10. package/dist/define.js +2 -0
  11. package/dist/define.js.map +1 -1
  12. package/dist/execute.d.ts +12 -3
  13. package/dist/execute.js +10 -2
  14. package/dist/execute.js.map +1 -1
  15. package/dist/flags.d.ts +44 -6
  16. package/dist/flags.js +53 -16
  17. package/dist/flags.js.map +1 -1
  18. package/dist/global-install.d.ts +2 -0
  19. package/dist/global-install.js +5 -4
  20. package/dist/global-install.js.map +1 -1
  21. package/dist/help-json.d.ts +4 -4
  22. package/dist/help-json.js +26 -42
  23. package/dist/help-json.js.map +1 -1
  24. package/dist/help.d.ts +4 -5
  25. package/dist/help.js +15 -12
  26. package/dist/help.js.map +1 -1
  27. package/dist/index.d.ts +5 -4
  28. package/dist/index.js +1 -1
  29. package/dist/index.js.map +1 -1
  30. package/dist/input.d.ts +8 -8
  31. package/dist/input.js +9 -16
  32. package/dist/input.js.map +1 -1
  33. package/dist/list.d.ts +44 -0
  34. package/dist/list.js +126 -0
  35. package/dist/list.js.map +1 -0
  36. package/dist/output.d.ts +33 -0
  37. package/dist/output.js +65 -0
  38. package/dist/output.js.map +1 -0
  39. package/dist/parse-input.d.ts +18 -4
  40. package/dist/parse-input.js +82 -49
  41. package/dist/parse-input.js.map +1 -1
  42. package/dist/route.d.ts +25 -0
  43. package/dist/route.js +75 -0
  44. package/dist/route.js.map +1 -0
  45. package/dist/run-cli.d.ts +2 -6
  46. package/dist/run-cli.js +53 -179
  47. package/dist/run-cli.js.map +1 -1
  48. package/dist/suggest.d.ts +4 -0
  49. package/dist/suggest.js +19 -11
  50. package/dist/suggest.js.map +1 -1
  51. package/dist/tokenize.d.ts +20 -0
  52. package/dist/tokenize.js +79 -0
  53. package/dist/tokenize.js.map +1 -0
  54. package/dist/usage.d.ts +3 -11
  55. package/dist/usage.js +20 -55
  56. package/dist/usage.js.map +1 -1
  57. package/package.json +1 -4
  58. package/dist/fields.d.ts +0 -14
  59. package/dist/fields.js +0 -71
  60. package/dist/fields.js.map +0 -1
  61. package/dist/page.d.ts +0 -26
  62. package/dist/page.js +0 -49
  63. package/dist/page.js.map +0 -1
@@ -1,39 +1,36 @@
1
1
  import * as z from "zod";
2
2
  import { UsageError } from "./errors.js";
3
- import { commandLineRenaming, END_OF_OPTIONS } from "./invocation.js";
3
+ import { CONFIRM_FLAG, DRY_RUN_FLAG, HELP_FLAG, VERSION_FLAG } from "./flags.js";
4
+ import { commandLineRenaming } from "./invocation.js";
5
+ import { PAGE_INPUT, selectedFields } from "./list.js";
4
6
  import { closestFlag } from "./suggest.js";
5
- import { commandLine, unknownOptionError } from "./usage.js";
6
- const HELP_FLAG = "--help";
7
- const NEGATIVE_NUMBER = /^-(\d+|\d*\.\d+)(e[+-]?\d+)?$/;
8
- function isOptionLike(token) {
9
- return (token !== undefined && token.length > 1 && token[0] === "-" && !NEGATIVE_NUMBER.test(token));
10
- }
11
- // Commander keeps `--` only after an unknown option, so the words after it are counted from the
12
- // caller's own command line.
13
- function leftoversOf(tokens, argv) {
14
- const end = argv.indexOf(END_OF_OPTIONS);
15
- const split = end === -1 ? tokens.length : Math.max(0, tokens.length - (argv.length - end - 1));
16
- const head = tokens.slice(0, split);
17
- const parsed = end !== -1 && head.at(-1) === END_OF_OPTIONS ? head.slice(0, -1) : head;
18
- const literal = tokens.slice(split).map((value) => ({ value, afterUnknownOption: false }));
19
- return {
20
- operands: [
21
- ...parsed.flatMap((value, index) => isOptionLike(value) ? [] : [{ value, afterUnknownOption: isOptionLike(parsed[index - 1]) }]),
22
- ...literal,
23
- ],
24
- unknownOptions: parsed.filter(isOptionLike),
25
- };
7
+ import { tokenize } from "./tokenize.js";
8
+ import { invalidInputError, unknownOptionError } from "./usage.js";
9
+ const NO_INPUT = z.object({});
10
+ function knownFlags(spec) {
11
+ return [
12
+ ...spec.options.map((field) => ({
13
+ flag: field.label,
14
+ takes: field.type === "boolean" ? "nothing" : "optional value",
15
+ })),
16
+ ...spec.standardFlags.map(({ flag, takes }) => ({ flag, takes })),
17
+ ];
26
18
  }
27
- function flagsOf(cmd) {
28
- const own = cmd.options.flatMap((option) => (option.long === undefined ? [] : [option.long]));
29
- return cmd.parent === null ? [...own, HELP_FLAG] : [...own, ...flagsOf(cmd.parent)];
19
+ function candidateFlags(known) {
20
+ return [...known.map(({ flag }) => flag), VERSION_FLAG, HELP_FLAG];
30
21
  }
31
- function unknownOptionsOf(tokens, sub) {
32
- return tokens.map((token) => {
33
- const flag = token.split("=")[0] ?? token;
34
- return { flag, suggestion: closestFlag(flag, flagsOf(sub)) };
22
+ function unknownOptionsOf(words, candidates) {
23
+ return words.map((word) => {
24
+ const flag = word.split("=")[0] ?? word;
25
+ return { flag, suggestion: closestFlag(flag, candidates) };
35
26
  });
36
27
  }
28
+ // A `--no-` switch turns its option off.
29
+ function optionValue(field, raw) {
30
+ return field.type === "boolean" && raw === true && field.label === `--no-${field.name}`
31
+ ? false
32
+ : raw;
33
+ }
37
34
  // Strings that read as numbers are converted so authors can write `z.number()`; anything else
38
35
  // stays a string for Zod to reject with the caller's own value.
39
36
  function converted(field, raw) {
@@ -47,7 +44,7 @@ function parse(schema, values) {
47
44
  const input = Object.fromEntries([...values]
48
45
  .filter(([, raw]) => raw !== undefined)
49
46
  .map(([field, raw]) => [field.key, converted(field, raw)]));
50
- return (schema ?? z.object({})).safeParse(input);
47
+ return schema.safeParse(input);
51
48
  }
52
49
  function issueLines(result, values, howToPass, reported) {
53
50
  if (result.success) {
@@ -70,45 +67,81 @@ function issueLines(result, values, howToPass, reported) {
70
67
  function unknownLine({ flag, suggestion }) {
71
68
  return ` unknown option '${flag}'${suggestion === undefined ? "" : ` (did you mean ${suggestion}?)`}`;
72
69
  }
73
- function invalidInput(line, invocation, unknown, otherLines) {
70
+ function invalidInput(commandLine, invocation, unknown, otherLines) {
74
71
  const renames = new Map(unknown.flatMap(({ flag, suggestion }) => suggestion === undefined ? [] : [[flag, suggestion]]));
75
72
  const correctable = otherLines.length === 0 && renames.size === unknown.length;
76
73
  return new UsageError({
77
74
  code: "INVALID_INPUT",
78
- message: [`invalid input for \`${line}\``, ...unknown.map(unknownLine), ...otherLines].join("\n"),
75
+ message: [
76
+ `invalid input for \`${commandLine}\``,
77
+ ...unknown.map(unknownLine),
78
+ ...otherLines,
79
+ ].join("\n"),
79
80
  hint: correctable
80
81
  ? `did you mean \`${commandLineRenaming(invocation, renames)}\`?`
81
- : `run \`${line} --help\` to see the expected input`,
82
+ : `run \`${commandLine} --help\` to see the expected input`,
82
83
  });
83
84
  }
84
- export function parseInput(command, sub, fields, invocation) {
85
- const { operands, unknownOptions } = leftoversOf(sub.args, invocation.argv);
86
- const opts = sub.opts();
85
+ function parseInput(spec, words, invocation) {
86
+ const { command, args: argFields, options: optionFields } = spec;
87
+ const pageFields = spec.list?.pageFields ?? [];
88
+ const known = knownFlags(spec);
89
+ const { operands, unknownOptions, values } = tokenize(words, known);
90
+ if (values.get(CONFIRM_FLAG.flag) === true) {
91
+ throw invalidInputError(spec.commandLine, `option '${CONFIRM_FLAG.usage}' argument missing`);
92
+ }
87
93
  // A value option given without a value is collected as `true`.
88
- const missing = fields.options.filter((field) => field.type !== "boolean" && opts[field.key] === true);
89
- const argValues = new Map(fields.args.map((field, index) => [field, operands[index]?.value]));
90
- const optionValues = new Map(fields.options.map((field) => [field, missing.includes(field) ? undefined : opts[field.key]]));
91
- const args = parse(command.args, argValues);
92
- const options = parse(command.options, optionValues);
93
- const unknown = unknownOptionsOf(unknownOptions, sub);
94
+ const missing = [...optionFields, ...pageFields].filter((field) => field.type !== "boolean" && values.get(field.label) === true);
95
+ const argValues = new Map(argFields.map((field, index) => [field, operands[index]?.value]));
96
+ const valuesOf = (fields) => new Map(fields.map((field) => [
97
+ field,
98
+ missing.includes(field) ? undefined : optionValue(field, values.get(field.label)),
99
+ ]));
100
+ const optionValues = valuesOf(optionFields);
101
+ const pageValues = valuesOf(pageFields);
102
+ const args = parse(command.args ?? NO_INPUT, argValues);
103
+ const options = parse(command.options ?? NO_INPUT, optionValues);
104
+ const page = parse(PAGE_INPUT, pageValues);
105
+ const unknown = unknownOptionsOf(unknownOptions, candidateFlags(known));
94
106
  const otherLines = [
95
107
  ...missing.map((field) => ` ${field.label}: missing value, pass ${field.usage}`),
96
108
  ...operands
97
- .slice(fields.args.length)
109
+ .slice(argFields.length)
98
110
  // A word right after an unknown flag may be its value, so it isn't an extra arg.
99
111
  .filter((operand) => !operand.afterUnknownOption)
100
112
  .map((operand) => ` unexpected argument ${JSON.stringify(operand.value)}`),
101
- ...issueLines(args, argValues, (field) => `pass it as argument ${fields.args.indexOf(field) + 1}`, []),
113
+ ...issueLines(args, argValues, (field) => `pass it as argument ${argFields.indexOf(field) + 1}`, []),
102
114
  ...issueLines(options, optionValues, (field) => `pass ${field.usage}`, missing),
115
+ ...issueLines(page, pageValues, (field) => `pass ${field.usage}`, missing),
103
116
  ];
104
- if (unknown.length === 0 && otherLines.length === 0 && args.success && options.success) {
105
- return { ...args.data, ...options.data };
117
+ if (unknown.length === 0 &&
118
+ otherLines.length === 0 &&
119
+ args.success &&
120
+ options.success &&
121
+ page.success) {
122
+ return { input: { ...args.data, ...options.data }, page: page.data, values };
106
123
  }
107
- const line = commandLine(sub);
108
124
  const [only] = unknown;
109
125
  if (only !== undefined && unknown.length === 1 && otherLines.length === 0) {
110
- throw unknownOptionError(line, invocation, only.flag, only.suggestion === undefined ? [] : [only.suggestion]);
126
+ throw unknownOptionError(spec.commandLine, invocation, only.flag, only.suggestion === undefined ? [] : [only.suggestion]);
111
127
  }
112
- throw invalidInput(line, invocation, unknown, otherLines);
128
+ throw invalidInput(spec.commandLine, invocation, unknown, otherLines);
129
+ }
130
+ /** The validated input and Standard flag values of the routed Command, or one usage error. */
131
+ export function parseCommand({ spec, words, json }, invocation) {
132
+ const { input, page, values } = parseInput(spec, words, invocation);
133
+ const confirm = values.get(CONFIRM_FLAG.flag);
134
+ return {
135
+ input,
136
+ flags: {
137
+ json,
138
+ dryRun: values.get(DRY_RUN_FLAG.flag) === true,
139
+ confirm: typeof confirm === "string" ? confirm : undefined,
140
+ page,
141
+ fields: spec.list === undefined
142
+ ? undefined
143
+ : selectedFields(values, spec.list.rowFields, spec.commandLine),
144
+ },
145
+ };
113
146
  }
114
147
  //# sourceMappingURL=parse-input.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"parse-input.js","sourceRoot":"","sources":["../src/parse-input.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,CAAC,MAAM,KAAK,CAAC;AAEzB,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,OAAO,EAAE,mBAAmB,EAAE,cAAc,EAAmB,MAAM,iBAAiB,CAAC;AACvF,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAE7D,MAAM,SAAS,GAAG,QAAQ,CAAC;AAC3B,MAAM,eAAe,GAAG,+BAA+B,CAAC;AAmBxD,SAAS,YAAY,CAAC,KAAyB;IAC7C,OAAO,CACL,KAAK,KAAK,SAAS,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,GAAG,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,KAAK,CAAC,CAC5F,CAAC;AACJ,CAAC;AAED,gGAAgG;AAChG,6BAA6B;AAC7B,SAAS,WAAW,CAAC,MAAyB,EAAE,IAAuB;IACrE,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC;IACzC,MAAM,KAAK,GAAG,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,MAAM,GAAG,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;IAChG,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;IACpC,MAAM,MAAM,GAAG,GAAG,KAAK,CAAC,CAAC,IAAI,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,cAAc,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IACvF,MAAM,OAAO,GAAG,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,kBAAkB,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC;IAC3F,OAAO;QACL,QAAQ,EAAE;YACR,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,CACjC,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,kBAAkB,EAAE,YAAY,CAAC,MAAM,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAC5F;YACD,GAAG,OAAO;SACX;QACD,cAAc,EAAE,MAAM,CAAC,MAAM,CAAC,YAAY,CAAC;KAC5C,CAAC;AACJ,CAAC;AAED,SAAS,OAAO,CAAC,GAAc;IAC7B,MAAM,GAAG,GAAG,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC9F,OAAO,GAAG,CAAC,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,EAAE,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC;AACtF,CAAC;AAED,SAAS,gBAAgB,CAAC,MAAyB,EAAE,GAAc;IACjE,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE;QAC1B,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC;QAC1C,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,WAAW,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;IAC/D,CAAC,CAAC,CAAC;AACL,CAAC;AAED,8FAA8F;AAC9F,gEAAgE;AAChE,SAAS,SAAS,CAAC,KAAiB,EAAE,GAAa;IACjD,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;QAC5E,OAAO,GAAG,CAAC;IACb,CAAC;IACD,MAAM,MAAM,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;IAC3B,OAAO,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC;AAC7C,CAAC;AAED,SAAS,KAAK,CAAC,MAA+B,EAAE,MAAyC;IACvF,MAAM,KAAK,GAAG,MAAM,CAAC,WAAW,CAC9B,CAAC,GAAG,MAAM,CAAC;SACR,MAAM,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,EAAE,CAAC,GAAG,KAAK,SAAS,CAAC;SACtC,GAAG,CAAC,CAAC,CAAC,KAAK,EAAE,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,SAAS,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,CAAC,CAC7D,CAAC;IACF,OAAO,CAAC,MAAM,IAAI,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;AACnD,CAAC;AAED,SAAS,UAAU,CACjB,MAAgC,EAChC,MAAyC,EACzC,SAAwC,EACxC,QAA+B;IAE/B,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;QACnB,OAAO,EAAE,CAAC;IACZ,CAAC;IACD,OAAO,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE;QAC3C,MAAM,KAAK,GAAG,CAAC,GAAG,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,GAAG,KAAK,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;QACtF,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YACxB,OAAO,CAAC,KAAK,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;QAChC,CAAC;QACD,IAAI,QAAQ,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;YAC7B,OAAO,EAAE,CAAC;QACZ,CAAC;QACD,MAAM,GAAG,GAAG,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QAC9B,OAAO,GAAG,KAAK,SAAS;YACtB,CAAC,CAAC,CAAC,KAAK,KAAK,CAAC,KAAK,eAAe,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC;YACrD,CAAC,CAAC,CAAC,KAAK,KAAK,CAAC,KAAK,IAAI,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;IACpE,CAAC,CAAC,CAAC;AACL,CAAC;AAED,SAAS,WAAW,CAAC,EAAE,IAAI,EAAE,UAAU,EAAiB;IACtD,OAAO,qBAAqB,IAAI,IAAI,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,kBAAkB,UAAU,IAAI,EAAE,CAAC;AACzG,CAAC;AAED,SAAS,YAAY,CACnB,IAAY,EACZ,UAAsB,EACtB,OAAiC,EACjC,UAA6B;IAE7B,MAAM,OAAO,GAAG,IAAI,GAAG,CACrB,OAAO,CAAC,OAAO,CAAC,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,EAAE,EAAE,CACvC,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC,CACrD,CACF,CAAC;IACF,MAAM,WAAW,GAAG,UAAU,CAAC,MAAM,KAAK,CAAC,IAAI,OAAO,CAAC,IAAI,KAAK,OAAO,CAAC,MAAM,CAAC;IAC/E,OAAO,IAAI,UAAU,CAAC;QACpB,IAAI,EAAE,eAAe;QACrB,OAAO,EAAE,CAAC,uBAAuB,IAAI,IAAI,EAAE,GAAG,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,GAAG,UAAU,CAAC,CAAC,IAAI,CACzF,IAAI,CACL;QACD,IAAI,EAAE,WAAW;YACf,CAAC,CAAC,kBAAkB,mBAAmB,CAAC,UAAU,EAAE,OAAO,CAAC,KAAK;YACjE,CAAC,CAAC,SAAS,IAAI,qCAAqC;KACvD,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,UAAU,CACxB,OAAgB,EAChB,GAAc,EACd,MAAmB,EACnB,UAAsB;IAEtB,MAAM,EAAE,QAAQ,EAAE,cAAc,EAAE,GAAG,WAAW,CAAC,GAAG,CAAC,IAAI,EAAE,UAAU,CAAC,IAAI,CAAC,CAAC;IAC5E,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,EAA4B,CAAC;IAClD,+DAA+D;IAC/D,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,MAAM,CACnC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,SAAS,IAAI,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,IAAI,CAChE,CAAC;IACF,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC,KAAK,EAAE,QAAQ,CAAC,KAAK,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC;IAC9F,MAAM,YAAY,GAAG,IAAI,GAAG,CAC1B,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,KAAK,EAAE,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAC9F,CAAC;IACF,MAAM,IAAI,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;IAC5C,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC;IACrD,MAAM,OAAO,GAAG,gBAAgB,CAAC,cAAc,EAAE,GAAG,CAAC,CAAC;IACtD,MAAM,UAAU,GAAG;QACjB,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,KAAK,CAAC,KAAK,yBAAyB,KAAK,CAAC,KAAK,EAAE,CAAC;QACjF,GAAG,QAAQ;aACR,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC;YAC1B,iFAAiF;aAChF,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,kBAAkB,CAAC;aAChD,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,yBAAyB,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QAC7E,GAAG,UAAU,CACX,IAAI,EACJ,SAAS,EACT,CAAC,KAAK,EAAE,EAAE,CAAC,uBAAuB,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,EAClE,EAAE,CACH;QACD,GAAG,UAAU,CAAC,OAAO,EAAE,YAAY,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,QAAQ,KAAK,CAAC,KAAK,EAAE,EAAE,OAAO,CAAC;KAChF,CAAC;IACF,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,IAAI,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;QACvF,OAAO,EAAE,GAAG,IAAI,CAAC,IAAI,EAAE,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC;IAC3C,CAAC;IACD,MAAM,IAAI,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC;IAC9B,MAAM,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC;IACvB,IAAI,IAAI,KAAK,SAAS,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1E,MAAM,kBAAkB,CACtB,IAAI,EACJ,UAAU,EACV,IAAI,CAAC,IAAI,EACT,IAAI,CAAC,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CACvD,CAAC;IACJ,CAAC;IACD,MAAM,YAAY,CAAC,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC;AAC5D,CAAC"}
1
+ {"version":3,"file":"parse-input.js","sourceRoot":"","sources":["../src/parse-input.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ import type { CommandSpec, SpecNode } from "./command-spec.js";
2
+ import type { UsageError } from "./errors.js";
3
+ import { type Invocation } from "./invocation.js";
4
+ /** Where the command line leads; `json` is set when the caller passed `--json` before any `--`. */
5
+ export type Route = {
6
+ readonly kind: "version";
7
+ readonly json: boolean;
8
+ } | {
9
+ readonly kind: "help";
10
+ readonly node: SpecNode;
11
+ readonly json: boolean;
12
+ } | {
13
+ readonly kind: "usage error";
14
+ readonly error: UsageError;
15
+ readonly json: boolean;
16
+ } | CommandRoute;
17
+ export interface CommandRoute {
18
+ readonly kind: "command";
19
+ readonly spec: CommandSpec;
20
+ /** The words after the Command's name, without `--json`. */
21
+ readonly words: readonly string[];
22
+ readonly json: boolean;
23
+ }
24
+ /** Walks the caller's command line through the Commands to the one it names, or to a stop. */
25
+ export declare function route(root: SpecNode, invocation: Invocation): Route;
package/dist/route.js ADDED
@@ -0,0 +1,75 @@
1
+ import { HELP_FLAG, HELP_SHORT, JSON_FLAG, VERSION_FLAG } from "./flags.js";
2
+ import { END_OF_OPTIONS } from "./invocation.js";
3
+ import { closestFlags, closestNames } from "./suggest.js";
4
+ import { unknownCommandError, unknownOptionError } from "./usage.js";
5
+ // The flags a group accepts: `--json` and `--version` count anywhere before `--`.
6
+ const GROUP_FLAGS = [HELP_FLAG, VERSION_FLAG, JSON_FLAG.flag];
7
+ function beforeEnd(words) {
8
+ const end = words.indexOf(END_OF_OPTIONS);
9
+ return end === -1 ? words : words.slice(0, end);
10
+ }
11
+ function wantsHelp(words) {
12
+ return beforeEnd(words).some((word) => word === HELP_FLAG || word === HELP_SHORT);
13
+ }
14
+ function childOf(group, name) {
15
+ return Object.hasOwn(group.commands, name) ? group.commands[name] : undefined;
16
+ }
17
+ // At a group a negative number is an option too: no group takes an operand.
18
+ function isFlagLike(word) {
19
+ return word.length > 1 && word[0] === "-";
20
+ }
21
+ function walk(node, words, json, invocation) {
22
+ const help = { kind: "help", node, json };
23
+ if (node.kind === "command") {
24
+ return wantsHelp(words) ? help : { kind: "command", spec: node, words, json };
25
+ }
26
+ const [first, ...rest] = words;
27
+ if (first === undefined) {
28
+ return help;
29
+ }
30
+ const child = childOf(node, first);
31
+ if (child !== undefined) {
32
+ return walk(child, rest, json, invocation);
33
+ }
34
+ // After `--` every word is an operand, the next Command's name included.
35
+ if (first === END_OF_OPTIONS) {
36
+ const [name, ...after] = rest;
37
+ if (name === undefined) {
38
+ return help;
39
+ }
40
+ const named = childOf(node, name);
41
+ if (named !== undefined) {
42
+ return walk(named, [END_OF_OPTIONS, ...after], json, invocation);
43
+ }
44
+ return unknownCommand(node, name, json);
45
+ }
46
+ if (wantsHelp(words)) {
47
+ return help;
48
+ }
49
+ if (isFlagLike(first)) {
50
+ const suggestions = closestFlags(first, GROUP_FLAGS);
51
+ const error = unknownOptionError(node.commandLine, invocation, first, suggestions);
52
+ return { kind: "usage error", error, json };
53
+ }
54
+ return unknownCommand(node, first, json);
55
+ }
56
+ function unknownCommand(group, name, json) {
57
+ const suggestions = closestNames(name, Object.keys(group.commands));
58
+ return {
59
+ kind: "usage error",
60
+ error: unknownCommandError(group.commandLine, name, suggestions),
61
+ json,
62
+ };
63
+ }
64
+ /** Walks the caller's command line through the Commands to the one it names, or to a stop. */
65
+ export function route(root, invocation) {
66
+ const { argv } = invocation;
67
+ const options = beforeEnd(argv);
68
+ const json = options.includes(JSON_FLAG.flag);
69
+ if (options.includes(VERSION_FLAG)) {
70
+ return { kind: "version", json };
71
+ }
72
+ const words = argv.filter((word, index) => !(index < options.length && word === JSON_FLAG.flag));
73
+ return walk(root, words, json, invocation);
74
+ }
75
+ //# sourceMappingURL=route.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"route.js","sourceRoot":"","sources":["../src/route.ts"],"names":[],"mappings":"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"}
package/dist/run-cli.d.ts CHANGED
@@ -1,4 +1,5 @@
1
- import { type Cli, type Env } from "./define.js";
1
+ import type { Cli, Env } from "./define.js";
2
+ import { type RunResult } from "./output.js";
2
3
  export interface RunOptions {
3
4
  readonly env: Env;
4
5
  readonly cwd: string;
@@ -11,10 +12,5 @@ export interface RunOptions {
11
12
  */
12
13
  readonly bin?: string;
13
14
  }
14
- export interface RunResult {
15
- readonly stdout: string;
16
- readonly stderr: string;
17
- readonly exitCode: number;
18
- }
19
15
  export declare function runCli(cli: Cli, argv: readonly string[], options: RunOptions): Promise<RunResult>;
20
16
  export declare function runWithProgress(cli: Cli, argv: readonly string[], options: RunOptions, writeProgress: (line: string) => void): Promise<RunResult>;
package/dist/run-cli.js CHANGED
@@ -1,154 +1,49 @@
1
- import { Command as Commander } from "commander";
2
1
  import { builtInCommands } from "./built-ins.js";
3
- import { isCommand, } from "./define.js";
4
- import { FailureWithData, formatRuntimeError, UsageError } from "./errors.js";
5
- import { execute } from "./execute.js";
6
- import { fieldsOption, projected, renderRows, rowFieldsOf, selectedFields } from "./fields.js";
7
- import { JSON_FLAG, runtimeFlagsFor } from "./flags.js";
8
- import { cliHelp, commandHelp, groupHelp } from "./help.js";
9
- import { cliHelpJson, commandHelpJson, groupHelpJson } from "./help-json.js";
10
- import { inputFields, registerInput } from "./input.js";
2
+ import { commandSpec, groupSpec } from "./command-spec.js";
3
+ import { execute, renderOf } from "./execute.js";
11
4
  import { RunControl } from "./interrupts.js";
12
- import { Page, pageFooter, printedPage } from "./page.js";
13
- import { parseInput } from "./parse-input.js";
5
+ import { commandResult, errorResult, helpResult, versionResult, } from "./output.js";
6
+ import { parseCommand } from "./parse-input.js";
7
+ import { route } from "./route.js";
14
8
  import { styleFor } from "./style.js";
15
- import { commandLine, ParseStop, stopAt, usageErrorOf } from "./usage.js";
16
- const RUNTIME_EXIT_CODE = 1;
17
- const USAGE_EXIT_CODE = 2;
18
- function withTrailingNewline(text) {
19
- return text === "" || text.endsWith("\n") ? text : `${text}\n`;
20
- }
21
- function isJson(cmd) {
22
- return cmd.optsWithGlobals().json === true;
23
- }
24
- function isDryRun(cmd) {
25
- return cmd.opts().dryRun === true;
26
- }
27
- function confirmOf(cmd) {
28
- return cmd.opts().confirm;
29
- }
30
- function printed(outcome, { json, invocation, style, fields }) {
31
- if (!(outcome.value instanceof Page)) {
32
- return json ? `${JSON.stringify(outcome.value)}\n` : withTrailingNewline(outcome.render(style));
33
- }
34
- const page = printedPage(outcome.value, invocation);
35
- if (fields === undefined) {
36
- return json
37
- ? `${JSON.stringify(page)}\n`
38
- : `${withTrailingNewline(outcome.render(style))}${pageFooter(page)}`;
39
- }
40
- const rows = projected(page.items, fields);
41
- // The author's render may read any field, so selected rows are rendered by the Runtime.
42
- return json
43
- ? `${JSON.stringify({ ...page, items: rows })}\n`
44
- : `${renderRows(rows, fields)}${pageFooter(page)}`;
45
- }
46
- function failure(error, format) {
47
- return {
48
- stdout: "",
49
- stderr: formatRuntimeError(error, format),
50
- exitCode: error instanceof UsageError ? USAGE_EXIT_CODE : RUNTIME_EXIT_CODE,
51
- };
52
- }
53
- async function runCommand(sub, command, fields, { base, signal, style, invocation, errorFormat }) {
54
- const json = isJson(sub);
55
- let input;
56
- let selected;
9
+ async function runCommand(routed, { base, signal, format: baseFormat }) {
10
+ const { command, commandLine } = routed.spec;
11
+ const format = { ...baseFormat, json: routed.json };
12
+ const { invocation } = format;
13
+ let parsed;
57
14
  try {
58
- input = parseInput(command, sub, fields, invocation);
59
- const rowFields = rowFieldsOf(command);
60
- selected =
61
- rowFields === undefined
62
- ? undefined
63
- : selectedFields(sub.opts().fields, rowFields, commandLine(sub));
15
+ parsed = parseCommand(routed, invocation);
64
16
  }
65
17
  catch (error) {
66
- return failure(error, { ...errorFormat, json });
18
+ return errorResult(error, format);
67
19
  }
68
- const control = new RunControl(commandLine(sub), signal);
20
+ const { input, flags } = parsed;
21
+ const control = new RunControl(commandLine, signal);
69
22
  const ctx = {
70
23
  ...base,
71
24
  signal: control.signal,
72
25
  deadline: (ms) => control.deadline(ms),
73
26
  runToEnd: (work) => control.runToEnd(work),
74
27
  };
28
+ let settled;
75
29
  try {
76
30
  const outcome = await control.settle(execute(command, input, ctx, {
77
- dryRun: isDryRun(sub),
78
- confirmation: { invocation, commandLine: commandLine(sub), given: confirmOf(sub) },
31
+ dryRun: flags.dryRun,
32
+ confirm: flags.confirm,
33
+ page: flags.page,
34
+ invocation,
35
+ commandLine,
79
36
  }));
80
- return {
81
- stdout: printed(outcome, { json, invocation, style, fields: selected }),
82
- stderr: "",
83
- exitCode: 0,
84
- };
37
+ settled = { ok: true, outcome };
85
38
  }
86
39
  catch (error) {
87
- const reported = control.errorAfter(error);
88
- const result = failure(reported, { ...errorFormat, json });
89
- if (!(reported instanceof FailureWithData)) {
90
- return result;
91
- }
92
- const outcome = {
93
- value: reported.data,
94
- render: (renderStyle) => command.render(reported.data, renderStyle),
40
+ settled = {
41
+ ok: false,
42
+ error: control.errorAfter(error),
43
+ render: renderOf(command),
95
44
  };
96
- return { ...result, stdout: printed(outcome, { json, invocation, style, fields: selected }) };
97
45
  }
98
- }
99
- // Commander parses every option before it prints help, so `--json` counts on either side of `--help`.
100
- function helpFor(cmd, text, json) {
101
- cmd.configureHelp({ formatHelp: () => (isJson(cmd) ? json() : text()) });
102
- }
103
- function configureCommand(sub, command, setup, json = () => commandHelpJson(commandLine(sub), command)) {
104
- const fields = inputFields(command);
105
- const rowFields = rowFieldsOf(command);
106
- const helpFields = rowFields === undefined
107
- ? fields
108
- : { ...fields, options: [...fields.options, fieldsOption(rowFields)] };
109
- helpFor(sub, () => commandHelp(commandLine(sub), command, helpFields, setup.style), json);
110
- registerInput(sub, helpFields.options);
111
- // The root already carries --json, for every Command.
112
- for (const flag of runtimeFlagsFor(command.effect).filter((flag) => flag !== JSON_FLAG)) {
113
- sub.option(flag.usage, flag.description);
114
- }
115
- sub.action(async () => {
116
- setup.finish(await runCommand(sub, command, fields, setup));
117
- });
118
- }
119
- function addCommand(parent, command, setup) {
120
- const sub = stopAt(parent.command(command.name).description(command.description));
121
- configureCommand(sub, command, setup);
122
- }
123
- function addCommands(parent, commands, setup) {
124
- for (const [key, node] of Object.entries(commands)) {
125
- if (isCommand(node)) {
126
- addCommand(parent, node, setup);
127
- }
128
- else {
129
- const group = stopAt(parent.command(key));
130
- helpFor(group, () => groupHelp(commandLine(group), node, setup.style), () => groupHelpJson(commandLine(group), node));
131
- addCommands(group, node, setup);
132
- }
133
- }
134
- }
135
- function stopped(error, { commanderOut, invocation, errorFormat }) {
136
- if (!(error instanceof ParseStop)) {
137
- return failure(error, errorFormat);
138
- }
139
- if (error.reason.exitCode === 0) {
140
- return { stdout: commanderOut, stderr: "", exitCode: 0 };
141
- }
142
- // A group called without a Command answers with its help, the same as its --help.
143
- if (error.reason.code === "commander.help") {
144
- return { stdout: error.command.helpInformation(), stderr: "", exitCode: 0 };
145
- }
146
- return failure(usageErrorOf(error, invocation), { ...errorFormat, json: isJson(error.command) });
147
- }
148
- function versionLine({ version, build }) {
149
- if (build === undefined)
150
- return version;
151
- return `${version} (${build.sha}${build.dirty ? "+dirty" : ""})`;
46
+ return commandResult(settled, { ...format, fields: flags.fields });
152
47
  }
153
48
  export async function runCli(cli, argv, options) {
154
49
  const progress = [];
@@ -157,55 +52,34 @@ export async function runCli(cli, argv, options) {
157
52
  }
158
53
  // Progress is written as it happens: an Agent harness kills a process that stays silent too long.
159
54
  export async function runWithProgress(cli, argv, options, writeProgress) {
160
- const style = styleFor(options.env, options.stdoutIsTTY === true);
161
- const errorFormat = { cliName: cli.name, json: false, env: options.env, style };
162
- const commanderOut = [];
163
- // Settings must be on the root before .command(): children copy them at creation.
164
- const root = stopAt(new Commander(cli.name))
165
- .configureOutput({
166
- writeOut: (text) => commanderOut.push(text),
167
- // Commander writes here only the help for a group called without a Command, answered below.
168
- writeErr: () => { },
169
- outputError: () => { },
170
- // The Runtime decides colour itself, so commander must not strip it by reading `process`.
171
- stripColor: (text) => text,
172
- })
173
- .helpCommand(false)
174
- .version(versionLine(cli), "--version")
175
- .option(JSON_FLAG.usage, JSON_FLAG.description);
176
- const invocation = { cliName: cli.name, argv };
177
- let commandResult;
178
- const setup = {
179
- base: {
180
- cwd: options.cwd,
181
- env: options.env,
182
- progress: (message) => writeProgress(`${message}\n`),
183
- },
184
- signal: options.signal,
185
- style,
186
- invocation,
187
- errorFormat,
188
- finish: (result) => {
189
- commandResult = result;
190
- },
55
+ const format = {
56
+ cliName: cli.name,
57
+ env: options.env,
58
+ style: styleFor(options.env, options.stdoutIsTTY === true),
59
+ invocation: { cliName: cli.name, argv },
60
+ json: false,
191
61
  };
192
- if (cli.commands === undefined) {
193
- configureCommand(root, cli.command, setup, () => cliHelpJson(cli.name, cli.version, cli.command));
194
- }
195
- else {
196
- const commands = { ...cli.commands, ...builtInCommands(cli, options.bin) };
197
- helpFor(root, () => cliHelp(cli.name, cli.version, commands, style), () => cliHelpJson(cli.name, cli.version, commands));
198
- addCommands(root, commands, setup);
199
- }
200
- try {
201
- await root.parseAsync([...argv], { from: "user" });
202
- }
203
- catch (error) {
204
- return stopped(error, { commanderOut: commanderOut.join(""), invocation, errorFormat });
205
- }
206
- if (commandResult === undefined) {
207
- throw new Error("commander finished parsing without running a Command");
62
+ const root = cli.commands === undefined
63
+ ? commandSpec(cli.name, cli.command)
64
+ : groupSpec(cli.name, { ...cli.commands, ...builtInCommands(cli, options.bin) });
65
+ const routed = route(root, format.invocation);
66
+ switch (routed.kind) {
67
+ case "version":
68
+ return versionResult(cli);
69
+ case "help":
70
+ return helpResult(routed.node, root, cli, { ...format, json: routed.json });
71
+ case "usage error":
72
+ return errorResult(routed.error, { ...format, json: routed.json });
73
+ case "command":
74
+ return runCommand(routed, {
75
+ base: {
76
+ cwd: options.cwd,
77
+ env: options.env,
78
+ progress: (message) => writeProgress(`${message}\n`),
79
+ },
80
+ signal: options.signal,
81
+ format,
82
+ });
208
83
  }
209
- return commandResult;
210
84
  }
211
85
  //# sourceMappingURL=run-cli.js.map