@outfitter/cli 0.5.2 → 1.0.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 (110) hide show
  1. package/README.md +179 -60
  2. package/dist/actions.d.ts +5 -2
  3. package/dist/actions.js +2 -2
  4. package/dist/cli.d.ts +1 -1
  5. package/dist/cli.js +8 -1
  6. package/dist/colors/index.js +1 -17
  7. package/dist/command.d.ts +3 -43
  8. package/dist/command.js +241 -13
  9. package/dist/envelope.d.ts +5 -0
  10. package/dist/envelope.js +160 -0
  11. package/dist/flags.d.ts +5 -189
  12. package/dist/flags.js +5 -1
  13. package/dist/hints.d.ts +34 -0
  14. package/dist/hints.js +26 -0
  15. package/dist/index.d.ts +3 -2
  16. package/dist/index.js +2 -17
  17. package/dist/input.d.ts +3 -124
  18. package/dist/input.js +14 -359
  19. package/dist/internal/envelope-helpers.d.ts +4 -0
  20. package/dist/internal/envelope-helpers.js +24 -0
  21. package/dist/internal/envelope-types.d.ts +3 -0
  22. package/dist/internal/flag-builders.d.ts +3 -0
  23. package/dist/internal/flag-builders.js +155 -0
  24. package/dist/internal/flag-types.d.ts +3 -0
  25. package/dist/internal/flag-types.js +13 -0
  26. package/dist/internal/hint-action-graph.d.ts +5 -0
  27. package/dist/internal/hint-action-graph.js +11 -0
  28. package/dist/internal/hint-command-tree.d.ts +5 -0
  29. package/dist/internal/hint-command-tree.js +9 -0
  30. package/dist/internal/hint-error-recovery.d.ts +2 -0
  31. package/dist/internal/hint-error-recovery.js +7 -0
  32. package/dist/internal/hint-types.d.ts +4 -0
  33. package/dist/internal/hint-types.js +1 -0
  34. package/dist/internal/input-helpers.d.ts +18 -0
  35. package/dist/internal/input-helpers.js +11 -0
  36. package/dist/internal/input-normalization.d.ts +3 -0
  37. package/dist/internal/input-normalization.js +9 -0
  38. package/dist/internal/input-parsers.d.ts +3 -0
  39. package/dist/internal/input-parsers.js +19 -0
  40. package/dist/internal/input-security.d.ts +22 -0
  41. package/dist/internal/input-security.js +11 -0
  42. package/dist/internal/output-formatting.d.ts +3 -0
  43. package/dist/internal/output-formatting.js +21 -0
  44. package/dist/internal/presets.d.ts +3 -0
  45. package/dist/{shared/@outfitter/cli-pdb7znbq.js → internal/presets.js} +49 -223
  46. package/dist/internal/schema-commands.d.ts +3 -0
  47. package/dist/{shared/@outfitter/cli-0cjts94k.js → internal/schema-commands.js} +12 -100
  48. package/dist/internal/schema-formatting.d.ts +2 -0
  49. package/dist/internal/schema-formatting.js +7 -0
  50. package/dist/internal/schema-types.d.ts +2 -0
  51. package/dist/internal/schema-types.js +1 -0
  52. package/dist/output.d.ts +4 -3
  53. package/dist/output.js +10 -2
  54. package/dist/pagination.d.ts +1 -1
  55. package/dist/query.d.ts +84 -2
  56. package/dist/query.js +8 -45
  57. package/dist/schema-input.d.ts +80 -0
  58. package/dist/schema-input.js +15 -0
  59. package/dist/schema.d.ts +4 -1
  60. package/dist/schema.js +1 -1
  61. package/dist/shared/@outfitter/cli-10wxfc78.d.ts +45 -0
  62. package/dist/shared/@outfitter/cli-16wg5mka.d.ts +71 -0
  63. package/dist/shared/@outfitter/cli-1q5redaj.js +267 -0
  64. package/dist/shared/@outfitter/cli-2dfxs239.js +98 -0
  65. package/dist/shared/@outfitter/cli-30mt7c5w.d.ts +112 -0
  66. package/dist/shared/@outfitter/cli-3jta1h1h.js +134 -0
  67. package/dist/shared/@outfitter/cli-4h85mpth.js +76 -0
  68. package/dist/shared/@outfitter/cli-6shkwxdc.js +28 -0
  69. package/dist/shared/@outfitter/cli-89335n9a.js +16 -0
  70. package/dist/shared/@outfitter/cli-8999qjdd.js +3 -0
  71. package/dist/shared/@outfitter/cli-8cfxdady.js +60 -0
  72. package/dist/shared/@outfitter/cli-bcajqy33.d.ts +25 -0
  73. package/dist/shared/@outfitter/cli-c09332vm.d.ts +39 -0
  74. package/dist/shared/@outfitter/cli-cgha038c.d.ts +3 -0
  75. package/dist/shared/@outfitter/{cli-zahqsaby.js → cli-d40m2x1d.js} +19 -3
  76. package/dist/shared/@outfitter/{cli-7wp5nj0s.js → cli-dg0cz7rw.js} +39 -81
  77. package/dist/shared/@outfitter/cli-dv8kk4jw.d.ts +24 -0
  78. package/dist/shared/@outfitter/cli-g43887b7.js +20 -0
  79. package/dist/shared/@outfitter/cli-gqtkhgw4.js +52 -0
  80. package/dist/shared/@outfitter/cli-h4ejpmjs.d.ts +104 -0
  81. package/dist/shared/@outfitter/cli-htzez8v2.js +70 -0
  82. package/dist/shared/@outfitter/cli-hvg2m5gf.js +79 -0
  83. package/dist/shared/@outfitter/cli-n54zs151.d.ts +78 -0
  84. package/dist/shared/@outfitter/cli-nbpgw7z7.d.ts +15 -0
  85. package/dist/shared/@outfitter/cli-nkt399zf.d.ts +94 -0
  86. package/dist/shared/@outfitter/cli-pmd04gtv.d.ts +60 -0
  87. package/dist/shared/@outfitter/{cli-xy3gs50c.d.ts → cli-q6csxmeh.d.ts} +19 -12
  88. package/dist/shared/@outfitter/cli-qcskd96y.d.ts +11 -0
  89. package/dist/shared/@outfitter/cli-ry7btmy4.js +118 -0
  90. package/dist/shared/@outfitter/cli-sy99pjyj.js +32 -0
  91. package/dist/shared/@outfitter/cli-tm2fzngs.d.ts +23 -0
  92. package/dist/shared/@outfitter/cli-vvvhjwks.js +106 -0
  93. package/dist/shared/@outfitter/cli-wjv7g1aq.d.ts +16 -0
  94. package/dist/shared/@outfitter/{cli-98aa9104.d.ts → cli-x6qr7bnd.d.ts} +338 -16
  95. package/dist/shared/@outfitter/cli-xde45xcc.d.ts +53 -0
  96. package/dist/shared/@outfitter/cli-xw8ys1je.d.ts +123 -0
  97. package/dist/shared/@outfitter/cli-yfewnyc2.d.ts +43 -0
  98. package/dist/shared/@outfitter/cli-zkzj0q4q.js +99 -0
  99. package/dist/shared/@outfitter/cli-zv3ah6f0.js +3 -0
  100. package/dist/streaming.d.ts +47 -0
  101. package/dist/streaming.js +13 -0
  102. package/dist/terminal/index.js +1 -19
  103. package/dist/truncation.d.ts +104 -0
  104. package/dist/truncation.js +111 -0
  105. package/dist/types.d.ts +2 -2
  106. package/dist/types.js +0 -5
  107. package/dist/verbs.d.ts +1 -1
  108. package/package.json +66 -36
  109. package/dist/shared/@outfitter/cli-n1k0d23k.d.ts +0 -33
  110. /package/dist/{shared/@outfitter/cli-zw75pdk8.js → internal/envelope-types.js} +0 -0
package/dist/command.js CHANGED
@@ -1,10 +1,87 @@
1
1
  // @bun
2
2
  import {
3
3
  createCLI
4
- } from "./shared/@outfitter/cli-zahqsaby.js";
4
+ } from "./shared/@outfitter/cli-d40m2x1d.js";
5
+ import {
6
+ resolveOutputMode
7
+ } from "./shared/@outfitter/cli-vvvhjwks.js";
8
+ import {
9
+ isSchemaPreset
10
+ } from "./shared/@outfitter/cli-8999qjdd.js";
11
+ import"./shared/@outfitter/cli-89335n9a.js";
12
+ import"./shared/@outfitter/cli-htzez8v2.js";
13
+ import"./shared/@outfitter/cli-hvg2m5gf.js";
14
+ import"./shared/@outfitter/cli-2dfxs239.js";
15
+ import {
16
+ exitWithError
17
+ } from "./shared/@outfitter/cli-4h85mpth.js";
18
+ import"./shared/@outfitter/cli-dg0cz7rw.js";
19
+ import {
20
+ createCommanderOption,
21
+ deriveFlags,
22
+ validateInput
23
+ } from "./shared/@outfitter/cli-3jta1h1h.js";
5
24
 
6
25
  // packages/cli/src/command.ts
7
26
  import { Command } from "commander";
27
+ import { z } from "zod";
28
+ function buildMergedSchema(inputSchema, schemaPresets) {
29
+ if (!inputSchema && schemaPresets.length === 0)
30
+ return;
31
+ if (schemaPresets.length === 0)
32
+ return inputSchema;
33
+ if (!inputSchema && schemaPresets.length === 1) {
34
+ return schemaPresets[0].schema;
35
+ }
36
+ const inputKeys = new Set(Object.keys(inputSchema?.shape ?? {}));
37
+ const omitOverriddenPresetFields = (schema) => {
38
+ if (inputKeys.size === 0) {
39
+ return schema;
40
+ }
41
+ const filteredEntries = Object.entries(schema.shape).filter(([key]) => !inputKeys.has(key));
42
+ if (filteredEntries.length === 0) {
43
+ return;
44
+ }
45
+ const filteredShape = Object.fromEntries(filteredEntries);
46
+ return z.object(filteredShape);
47
+ };
48
+ const mergedShape = {};
49
+ const allSchemas = [];
50
+ for (const preset of schemaPresets) {
51
+ const filteredPresetSchema = omitOverriddenPresetFields(preset.schema);
52
+ if (!filteredPresetSchema) {
53
+ continue;
54
+ }
55
+ Object.assign(mergedShape, filteredPresetSchema.shape);
56
+ allSchemas.push(filteredPresetSchema);
57
+ }
58
+ if (inputSchema) {
59
+ Object.assign(mergedShape, inputSchema.shape);
60
+ allSchemas.push(inputSchema);
61
+ }
62
+ return {
63
+ shape: mergedShape,
64
+ safeParse(data) {
65
+ let merged = {};
66
+ for (const schema of allSchemas) {
67
+ const schemaData = {};
68
+ if (data && typeof data === "object") {
69
+ for (const key of Object.keys(schema.shape)) {
70
+ if (key in data) {
71
+ schemaData[key] = data[key];
72
+ }
73
+ }
74
+ }
75
+ const result = schema.safeParse(schemaData);
76
+ if (!result.success) {
77
+ return result;
78
+ }
79
+ merged = { ...merged, ...result.data };
80
+ }
81
+ return { success: true, data: merged };
82
+ }
83
+ };
84
+ }
8
85
  function parseCommandSignature(signature) {
9
86
  const trimmed = signature.trim();
10
87
  const firstWhitespace = trimmed.search(/\s/);
@@ -23,51 +100,202 @@ function createCLI2(config) {
23
100
  }
24
101
 
25
102
  class CommandBuilderImpl {
26
- command;
103
+ cmd;
104
+ inputSchema;
105
+ ctxFactory;
106
+ successHintFn;
107
+ errorHintsFn;
108
+ explicitLongFlags = new Set;
109
+ schemaPresets = [];
110
+ schemaFlagsApplied = false;
111
+ _destructive = false;
112
+ _readOnly = false;
113
+ _idempotent = false;
114
+ _relatedTo = [];
27
115
  constructor(signature) {
28
116
  const { name, argumentsSpec } = parseCommandSignature(signature);
29
- this.command = new Command(name);
117
+ this.cmd = new Command(name);
30
118
  if (argumentsSpec) {
31
- this.command.arguments(argumentsSpec);
119
+ this.cmd.arguments(argumentsSpec);
32
120
  }
33
121
  }
34
122
  description(text) {
35
- this.command.description(text);
123
+ this.cmd.description(text);
36
124
  return this;
37
125
  }
38
126
  option(flags, description, defaultValue) {
39
- this.command.option(flags, description, defaultValue);
127
+ const longMatch = flags.match(/--([a-z][a-z0-9-]*)/i);
128
+ if (longMatch) {
129
+ this.explicitLongFlags.add(`--${longMatch[1]}`);
130
+ }
131
+ this.cmd.option(flags, description, defaultValue);
40
132
  return this;
41
133
  }
42
134
  requiredOption(flags, description, defaultValue) {
43
- this.command.requiredOption(flags, description, defaultValue);
135
+ const longMatch = flags.match(/--([a-z][a-z0-9-]*)/i);
136
+ if (longMatch) {
137
+ this.explicitLongFlags.add(`--${longMatch[1]}`);
138
+ }
139
+ this.cmd.requiredOption(flags, description, defaultValue);
44
140
  return this;
45
141
  }
46
142
  alias(alias) {
47
- this.command.alias(alias);
143
+ this.cmd.alias(alias);
144
+ return this;
145
+ }
146
+ input(schema) {
147
+ this.inputSchema = schema;
148
+ return this;
149
+ }
150
+ context(factory) {
151
+ this.ctxFactory = factory;
152
+ return this;
153
+ }
154
+ hints(fn) {
155
+ this.successHintFn = fn;
156
+ return this;
157
+ }
158
+ onError(fn) {
159
+ this.errorHintsFn = fn;
160
+ return this;
161
+ }
162
+ destructive(isDest) {
163
+ this._destructive = isDest;
164
+ return this;
165
+ }
166
+ readOnly(isReadOnly) {
167
+ this._readOnly = isReadOnly;
168
+ return this;
169
+ }
170
+ idempotent(isIdempotent) {
171
+ this._idempotent = isIdempotent;
172
+ return this;
173
+ }
174
+ relatedTo(target, options) {
175
+ this._relatedTo.push({
176
+ target,
177
+ ...options?.description ? { description: options.description } : {}
178
+ });
48
179
  return this;
49
180
  }
50
181
  preset(preset) {
182
+ if (isSchemaPreset(preset)) {
183
+ this.schemaPresets.push(preset);
184
+ return this;
185
+ }
51
186
  for (const opt of preset.options) {
187
+ const longMatch = opt.flags.match(/--([a-z][a-z0-9-]*)/i);
188
+ if (longMatch) {
189
+ this.explicitLongFlags.add(`--${longMatch[1]}`);
190
+ }
52
191
  if (opt.required) {
53
- this.command.requiredOption(opt.flags, opt.description, opt.defaultValue);
192
+ this.cmd.requiredOption(opt.flags, opt.description, opt.defaultValue);
54
193
  } else {
55
- this.command.option(opt.flags, opt.description, opt.defaultValue);
194
+ this.cmd.option(opt.flags, opt.description, opt.defaultValue);
56
195
  }
57
196
  }
58
197
  return this;
59
198
  }
60
199
  action(handler) {
61
- this.command.action(async (...args) => {
200
+ const schema = this.inputSchema;
201
+ const contextFactory = this.ctxFactory;
202
+ const presets = [...this.schemaPresets];
203
+ this.applySchemaFlags();
204
+ const mergedSchema = buildMergedSchema(schema, presets);
205
+ this.cmd.action(async (...args) => {
62
206
  const command = args.at(-1);
63
207
  const flags = command.optsWithGlobals?.() ?? command.opts();
64
208
  const positional = command.args;
65
- await handler({ args: positional, flags, command });
209
+ let input;
210
+ let ctx;
211
+ try {
212
+ input = mergedSchema ? validateInput(flags, mergedSchema) : undefined;
213
+ if (input !== undefined && presets.length > 0) {
214
+ for (const preset of presets) {
215
+ const resolved = preset.resolve(flags);
216
+ Object.assign(input, resolved);
217
+ }
218
+ }
219
+ if (contextFactory) {
220
+ const factoryArg = input !== undefined ? input : flags;
221
+ ctx = await contextFactory(factoryArg);
222
+ }
223
+ } catch (err) {
224
+ const error = err instanceof Error ? err : new Error(String(err));
225
+ const { mode } = resolveOutputMode(flags);
226
+ exitWithError(error, mode);
227
+ return;
228
+ }
229
+ await handler({
230
+ args: positional,
231
+ flags,
232
+ command,
233
+ input,
234
+ ctx
235
+ });
66
236
  });
67
237
  return this;
68
238
  }
69
239
  build() {
70
- return this.command;
240
+ this.applySchemaFlags();
241
+ this.applyDestructiveFlag();
242
+ if (this.successHintFn) {
243
+ this.cmd.__successHintFn = this.successHintFn;
244
+ }
245
+ if (this.errorHintsFn) {
246
+ this.cmd.__errorHintFn = this.errorHintsFn;
247
+ }
248
+ const metadata = {};
249
+ if (this._readOnly) {
250
+ metadata.readOnly = true;
251
+ }
252
+ if (this._idempotent) {
253
+ metadata.idempotent = true;
254
+ }
255
+ if (metadata.readOnly !== undefined || metadata.idempotent !== undefined) {
256
+ this.cmd.__metadata = metadata;
257
+ }
258
+ if (this._relatedTo.length > 0) {
259
+ this.cmd.__relatedTo = [...this._relatedTo];
260
+ }
261
+ return this.cmd;
262
+ }
263
+ applySchemaFlags() {
264
+ if (this.schemaFlagsApplied)
265
+ return;
266
+ if (!this.inputSchema && this.schemaPresets.length === 0)
267
+ return;
268
+ this.schemaFlagsApplied = true;
269
+ const existingLongs = new Set(this.explicitLongFlags);
270
+ for (const opt of this.cmd.options) {
271
+ if (opt.long) {
272
+ existingLongs.add(opt.long);
273
+ }
274
+ }
275
+ if (this.inputSchema) {
276
+ const derived = deriveFlags(this.inputSchema, existingLongs);
277
+ for (const flag of derived) {
278
+ const option = createCommanderOption(flag, this.inputSchema);
279
+ this.cmd.addOption(option);
280
+ existingLongs.add(flag.longFlag);
281
+ }
282
+ }
283
+ for (const schemaPreset of this.schemaPresets) {
284
+ const derived = deriveFlags(schemaPreset.schema, existingLongs);
285
+ for (const flag of derived) {
286
+ const option = createCommanderOption(flag, schemaPreset.schema);
287
+ this.cmd.addOption(option);
288
+ existingLongs.add(flag.longFlag);
289
+ }
290
+ }
291
+ }
292
+ applyDestructiveFlag() {
293
+ if (!this._destructive)
294
+ return;
295
+ const hasDryRun = this.cmd.options.some((o) => o.long === "--dry-run");
296
+ if (hasDryRun)
297
+ return;
298
+ this.cmd.option("--dry-run", "Preview changes without applying (destructive command safety)", false);
71
299
  }
72
300
  }
73
301
  function command(name) {
@@ -0,0 +1,5 @@
1
+ import { runHandler } from "./shared/@outfitter/cli-c09332vm.js";
2
+ import { createErrorEnvelope, createSuccessEnvelope } from "./shared/@outfitter/cli-nkt399zf.js";
3
+ import { CommandEnvelope, ErrorEnvelope, RunHandlerOptions, SuccessEnvelope } from "./shared/@outfitter/cli-30mt7c5w.js";
4
+ import "./shared/@outfitter/cli-x6qr7bnd.js";
5
+ export { runHandler, createSuccessEnvelope, createErrorEnvelope, SuccessEnvelope, RunHandlerOptions, ErrorEnvelope, CommandEnvelope };
@@ -0,0 +1,160 @@
1
+ // @bun
2
+ import {
3
+ buildDryRunHint,
4
+ createErrorEnvelope,
5
+ createSuccessEnvelope,
6
+ extractCategory,
7
+ extractMessage,
8
+ extractRetryAfterSeconds,
9
+ formatEnvelopeHuman,
10
+ getExitCode,
11
+ safeCallHintFn
12
+ } from "./shared/@outfitter/cli-ry7btmy4.js";
13
+ import {
14
+ createNdjsonProgress,
15
+ writeNdjsonLine,
16
+ writeStreamEnvelope
17
+ } from "./shared/@outfitter/cli-g43887b7.js";
18
+ import {
19
+ output
20
+ } from "./shared/@outfitter/cli-4h85mpth.js";
21
+ import {
22
+ detectMode
23
+ } from "./shared/@outfitter/cli-dg0cz7rw.js";
24
+
25
+ // packages/cli/src/envelope.ts
26
+ import { safeStringify } from "@outfitter/contracts";
27
+ async function runHandler(options) {
28
+ const {
29
+ command: commandName,
30
+ handler,
31
+ input,
32
+ format,
33
+ contextFactory,
34
+ hints: hintsFn,
35
+ onError: onErrorFn,
36
+ stream: isStreaming = false,
37
+ dryRun: isDryRun = false
38
+ } = options;
39
+ const inputValue = input;
40
+ const resolvedFormat = format ?? detectMode();
41
+ const isJsonMode = resolvedFormat === "json" || resolvedFormat === "jsonl";
42
+ let progressCallback;
43
+ if (isStreaming) {
44
+ const startEvent = {
45
+ type: "start",
46
+ command: commandName,
47
+ ts: new Date().toISOString()
48
+ };
49
+ writeNdjsonLine(startEvent);
50
+ const writeProgress = createNdjsonProgress(commandName);
51
+ progressCallback = (event) => {
52
+ if (event.type === "start") {
53
+ return;
54
+ }
55
+ writeProgress(event);
56
+ };
57
+ }
58
+ let context;
59
+ if (contextFactory) {
60
+ try {
61
+ const rawContext = await contextFactory(inputValue);
62
+ if (isStreaming && rawContext && typeof rawContext === "object") {
63
+ context = Object.assign(Object.create(Object.getPrototypeOf(rawContext)), rawContext, { progress: progressCallback });
64
+ } else {
65
+ context = rawContext;
66
+ }
67
+ } catch (err) {
68
+ const error = err instanceof Error ? err : new Error(String(err));
69
+ const category = extractCategory(error);
70
+ const message = extractMessage(error);
71
+ const retryAfter = extractRetryAfterSeconds(error);
72
+ const errorHints = onErrorFn ? safeCallHintFn(() => onErrorFn(error, inputValue)) : undefined;
73
+ const envelope = createErrorEnvelope(commandName, category, message, errorHints, retryAfter);
74
+ if (isStreaming) {
75
+ writeStreamEnvelope(envelope);
76
+ const exitCode = getExitCode(category);
77
+ process.exit(exitCode);
78
+ }
79
+ outputErrorEnvelope(envelope, isJsonMode);
80
+ return;
81
+ }
82
+ } else if (isStreaming) {
83
+ context = { progress: progressCallback };
84
+ } else {
85
+ context = undefined;
86
+ }
87
+ let result;
88
+ try {
89
+ result = await handler(inputValue, context);
90
+ } catch (err) {
91
+ const error = err instanceof Error ? err : new Error(String(err));
92
+ const category = extractCategory(error);
93
+ const message = extractMessage(error);
94
+ const retryAfter = extractRetryAfterSeconds(error);
95
+ const errorHints = onErrorFn ? safeCallHintFn(() => onErrorFn(error, inputValue)) : undefined;
96
+ const envelope = createErrorEnvelope(commandName, category, message, errorHints, retryAfter);
97
+ if (isStreaming) {
98
+ writeStreamEnvelope(envelope);
99
+ const exitCode = getExitCode(category);
100
+ process.exit(exitCode);
101
+ }
102
+ outputErrorEnvelope(envelope, isJsonMode);
103
+ return;
104
+ }
105
+ if (result.isOk()) {
106
+ let successHints = hintsFn ? safeCallHintFn(() => hintsFn(result.value, inputValue)) : undefined;
107
+ if (isDryRun) {
108
+ const dryRunHint = buildDryRunHint(options.argv);
109
+ if (dryRunHint) {
110
+ successHints = successHints ? [...successHints, dryRunHint] : [dryRunHint];
111
+ }
112
+ }
113
+ const envelope = createSuccessEnvelope(commandName, result.value, successHints);
114
+ if (isStreaming) {
115
+ writeStreamEnvelope(envelope);
116
+ return;
117
+ }
118
+ if (isJsonMode) {
119
+ await output(envelope, resolvedFormat);
120
+ } else {
121
+ const formatted = formatEnvelopeHuman(envelope);
122
+ if (formatted.stdout) {
123
+ process.stdout.write(`${formatted.stdout}
124
+ `);
125
+ }
126
+ }
127
+ } else {
128
+ const error = result.error;
129
+ const category = extractCategory(error);
130
+ const message = extractMessage(error);
131
+ const retryAfter = extractRetryAfterSeconds(error);
132
+ const errorHints = onErrorFn ? safeCallHintFn(() => onErrorFn(error, inputValue)) : undefined;
133
+ const envelope = createErrorEnvelope(commandName, category, message, errorHints, retryAfter);
134
+ if (isStreaming) {
135
+ writeStreamEnvelope(envelope);
136
+ const exitCode = getExitCode(category);
137
+ process.exit(exitCode);
138
+ }
139
+ outputErrorEnvelope(envelope, isJsonMode);
140
+ }
141
+ }
142
+ function outputErrorEnvelope(envelope, isJsonMode) {
143
+ const exitCode = getExitCode(envelope.error.category);
144
+ if (isJsonMode) {
145
+ process.stderr.write(`${safeStringify(envelope)}
146
+ `);
147
+ } else {
148
+ const formatted = formatEnvelopeHuman(envelope);
149
+ if (formatted.stderr) {
150
+ process.stderr.write(`${formatted.stderr}
151
+ `);
152
+ }
153
+ }
154
+ process.exit(exitCode);
155
+ }
156
+ export {
157
+ runHandler,
158
+ createSuccessEnvelope,
159
+ createErrorEnvelope
160
+ };
package/dist/flags.d.ts CHANGED
@@ -1,189 +1,5 @@
1
- import { BooleanFlagPresetConfig, ColorFlags, ColorMode, ComposedPreset, EnumFlagPresetConfig, ExecutionFlags, ExecutionPresetConfig, FlagPreset, FlagPresetConfig, InteractionFlags, NumberFlagPresetConfig, PaginationFlags, PaginationPresetConfig, ProjectionFlags, StrictFlags, StringListFlagPresetConfig, TimeWindowFlags, TimeWindowPresetConfig } from "./shared/@outfitter/cli-98aa9104.js";
2
- /**
3
- * Create a typed flag preset.
4
- *
5
- * @param config - Preset configuration with id, options, and resolver
6
- * @returns A flag preset that can be applied to commands or composed
7
- *
8
- * @example
9
- * ```typescript
10
- * const myPreset = createPreset({
11
- * id: "output-format",
12
- * options: [{ flags: "--format <type>", description: "Output format" }],
13
- * resolve: (flags) => ({
14
- * format: String(flags["format"] ?? "text"),
15
- * }),
16
- * });
17
- * ```
18
- */
19
- declare function createPreset<TResolved extends Record<string, unknown>>(config: FlagPresetConfig<TResolved>): FlagPreset<TResolved>;
20
- type ResolvedType<T> = T extends FlagPreset<infer R> ? R : never;
21
- type UnionToIntersection<U> = (U extends unknown ? (k: U) => void : never) extends (k: infer I) => void ? I : never;
22
- /**
23
- * Resolves the merged type from a tuple of presets.
24
- * Falls back to Record<string, unknown> when the tuple is empty
25
- * (since UnionToIntersection<never> produces unknown).
26
- */
27
- type MergedPresetResult<TPresets extends readonly FlagPreset<Record<string, unknown>>[]> = UnionToIntersection<ResolvedType<TPresets[number]>> extends Record<string, unknown> ? UnionToIntersection<ResolvedType<TPresets[number]>> : Record<string, unknown>;
28
- /**
29
- * Compose multiple presets into one, deduplicating by id (first wins).
30
- *
31
- * @param presets - Presets to compose together
32
- * @returns A single preset merging all options and resolvers
33
- *
34
- * @example
35
- * ```typescript
36
- * const composed = composePresets(
37
- * verbosePreset(),
38
- * cwdPreset(),
39
- * forcePreset(),
40
- * );
41
- * // composed.resolve({ verbose: true, cwd: "/tmp", force: false })
42
- * // => { verbose: true, cwd: "/tmp", force: false }
43
- * ```
44
- */
45
- declare function composePresets<TPresets extends readonly FlagPreset<Record<string, unknown>>[]>(...presets: TPresets): ComposedPreset<MergedPresetResult<TPresets>>;
46
- /**
47
- * Generic boolean custom-flag builder.
48
- *
49
- * Supports normal sources and negated sources so `--no-foo` patterns can
50
- * resolve consistently across Commander flag-shape differences.
51
- */
52
- declare function booleanFlagPreset<TKey extends string>(config: BooleanFlagPresetConfig<TKey>): FlagPreset<{ [K in TKey] : boolean }>;
53
- /**
54
- * Generic enum custom-flag builder.
55
- */
56
- declare function enumFlagPreset<
57
- TKey extends string,
58
- TValue extends string
59
- >(config: EnumFlagPresetConfig<TKey, TValue>): FlagPreset<{ [K in TKey] : TValue }>;
60
- /**
61
- * Generic number custom-flag builder.
62
- */
63
- declare function numberFlagPreset<TKey extends string>(config: NumberFlagPresetConfig<TKey>): FlagPreset<{ [K in TKey] : number }>;
64
- /**
65
- * Generic string-list custom-flag builder.
66
- */
67
- declare function stringListFlagPreset<TKey extends string>(config: StringListFlagPresetConfig<TKey>): FlagPreset<{ [K in TKey] : string[] | undefined }>;
68
- /**
69
- * Verbose output flag preset.
70
- *
71
- * Adds: `-v, --verbose`
72
- * Resolves: `{ verbose: boolean }`
73
- */
74
- declare function verbosePreset(): FlagPreset<{
75
- verbose: boolean;
76
- }>;
77
- /**
78
- * Working directory flag preset.
79
- *
80
- * Adds: `--cwd <path>`
81
- * Resolves: `{ cwd: string }` (defaults to `process.cwd()`)
82
- */
83
- declare function cwdPreset(): FlagPreset<{
84
- cwd: string;
85
- }>;
86
- /**
87
- * Dry-run flag preset.
88
- *
89
- * Adds: `--dry-run`
90
- * Resolves: `{ dryRun: boolean }`
91
- */
92
- declare function dryRunPreset(): FlagPreset<{
93
- dryRun: boolean;
94
- }>;
95
- /**
96
- * Force flag preset.
97
- *
98
- * Adds: `-f, --force`
99
- * Resolves: `{ force: boolean }`
100
- */
101
- declare function forcePreset(): FlagPreset<{
102
- force: boolean;
103
- }>;
104
- /**
105
- * Interaction mode flag preset.
106
- *
107
- * Adds: `--non-interactive`, `--no-input`, `-y, --yes`
108
- * Resolves: `{ interactive: boolean, yes: boolean }`
109
- *
110
- * `interactive` defaults to `true` and is set to `false` when
111
- * `--non-interactive` or `--no-input` is passed. The two flags
112
- * are synonyms for user convenience.
113
- */
114
- declare function interactionPreset(): FlagPreset<InteractionFlags>;
115
- /**
116
- * Strict mode flag preset.
117
- *
118
- * Adds: `--strict`
119
- * Resolves: `{ strict: boolean }`
120
- */
121
- declare function strictPreset(): FlagPreset<StrictFlags>;
122
- /**
123
- * Color mode flag preset.
124
- *
125
- * Adds: `--color [mode]`, `--no-color`
126
- * Resolves: `{ color: "auto" | "always" | "never" }`
127
- *
128
- * Commander's `--no-color` negation sets `flags["color"]` to `false`,
129
- * which resolves to `"never"`. Invalid values default to `"auto"`.
130
- *
131
- * This preset resolves the user's *intent*. Consumers should compose
132
- * with terminal detection (`supportsColor()`, `resolveColorEnv()`)
133
- * to determine actual color output behavior.
134
- */
135
- declare function colorPreset(): FlagPreset<ColorFlags>;
136
- /**
137
- * Projection flag preset.
138
- *
139
- * Adds: `--fields <fields>`, `--exclude-fields <fields>`, `--count`
140
- * Resolves: `{ fields: string[] | undefined, excludeFields: string[] | undefined, count: boolean }`
141
- *
142
- * Fields are parsed as comma-separated strings with whitespace trimming.
143
- * `undefined` when not provided (not empty array) to distinguish
144
- * "not specified" from "empty".
145
- *
146
- * Conflict between `--fields` and `--exclude-fields` is a handler
147
- * concern (documented, not enforced).
148
- */
149
- declare function projectionPreset(): FlagPreset<ProjectionFlags>;
150
- /**
151
- * Time-window flag preset.
152
- *
153
- * Adds: `--since <date>`, `--until <date>`
154
- * Resolves: `{ since: Date | undefined, until: Date | undefined }`
155
- *
156
- * Accepts ISO 8601 dates (`2024-01-15`) or relative durations
157
- * (`7d`, `24h`, `30m`, `2w`). Durations are past-relative
158
- * (subtracted from now).
159
- *
160
- * Returns `undefined` for unparseable values (does not throw).
161
- * When `config.maxRange` is set and both bounds are provided,
162
- * ranges above the limit are treated as invalid.
163
- */
164
- declare function timeWindowPreset(config?: TimeWindowPresetConfig): FlagPreset<TimeWindowFlags>;
165
- /**
166
- * Execution flag preset.
167
- *
168
- * Adds: `--timeout <ms>`, `--retries <n>`, `--offline`
169
- * Resolves: `{ timeout: number | undefined, retries: number, offline: boolean }`
170
- *
171
- * Timeout is parsed as a positive integer in milliseconds.
172
- * Retries are parsed as a non-negative integer, clamped to maxRetries.
173
- */
174
- declare function executionPreset(config?: ExecutionPresetConfig): FlagPreset<ExecutionFlags>;
175
- /**
176
- * Pagination flag preset.
177
- *
178
- * Adds: `-l, --limit <n>`, `--next`, `--reset`
179
- * Resolves: `{ limit: number, next: boolean, reset: boolean }`
180
- *
181
- * Limit is parsed as an integer, clamped to maxLimit, and defaults
182
- * to defaultLimit on invalid input. Mutual exclusivity of --next
183
- * and --reset is a handler concern (not enforced here).
184
- *
185
- * Integrates with loadCursor/saveCursor/clearCursor from
186
- * `@outfitter/cli/pagination`.
187
- */
188
- declare function paginationPreset(config?: PaginationPresetConfig): FlagPreset<PaginationFlags>;
189
- export { verbosePreset, timeWindowPreset, stringListFlagPreset, strictPreset, projectionPreset, paginationPreset, numberFlagPreset, interactionPreset, forcePreset, executionPreset, enumFlagPreset, dryRunPreset, cwdPreset, createPreset, composePresets, colorPreset, booleanFlagPreset, TimeWindowPresetConfig, TimeWindowFlags, StringListFlagPresetConfig, StrictFlags, ProjectionFlags, PaginationPresetConfig, PaginationFlags, NumberFlagPresetConfig, InteractionFlags, FlagPresetConfig, FlagPreset, ExecutionPresetConfig, ExecutionFlags, EnumFlagPresetConfig, ComposedPreset, ColorMode, ColorFlags, BooleanFlagPresetConfig };
1
+ import { colorPreset, cwdPreset, dryRunPreset, executionPreset, forcePreset, interactionPreset, paginationPreset, projectionPreset, strictPreset, timeWindowPreset, verbosePreset } from "./shared/@outfitter/cli-xw8ys1je.js";
2
+ import { composePresets, createPreset, createSchemaPreset, isSchemaPreset } from "./shared/@outfitter/cli-n54zs151.js";
3
+ import { booleanFlagPreset, enumFlagPreset, numberFlagPreset, stringListFlagPreset } from "./shared/@outfitter/cli-dv8kk4jw.js";
4
+ import { AnyPreset, BooleanFlagPresetConfig, ColorFlags, ColorMode, ComposedPreset, EnumFlagPresetConfig, ExecutionFlags, ExecutionPresetConfig, FlagPreset, FlagPresetConfig, InteractionFlags, NumberFlagPresetConfig, PaginationFlags, PaginationPresetConfig, ProjectionFlags, SchemaPreset, SchemaPresetConfig, StrictFlags, StringListFlagPresetConfig, TimeWindowFlags, TimeWindowPresetConfig } from "./shared/@outfitter/cli-x6qr7bnd.js";
5
+ export { verbosePreset, timeWindowPreset, stringListFlagPreset, strictPreset, projectionPreset, paginationPreset, numberFlagPreset, isSchemaPreset, interactionPreset, forcePreset, executionPreset, enumFlagPreset, dryRunPreset, cwdPreset, createSchemaPreset, createPreset, composePresets, colorPreset, booleanFlagPreset, TimeWindowPresetConfig, TimeWindowFlags, StringListFlagPresetConfig, StrictFlags, SchemaPresetConfig, SchemaPreset, ProjectionFlags, PaginationPresetConfig, PaginationFlags, NumberFlagPresetConfig, InteractionFlags, FlagPresetConfig, FlagPreset, ExecutionPresetConfig, ExecutionFlags, EnumFlagPresetConfig, ComposedPreset, ColorMode, ColorFlags, BooleanFlagPresetConfig, AnyPreset };