@andrei.fyi/picocli 0.1.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.
@@ -0,0 +1,502 @@
1
+ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
2
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
3
+ import { ListToolsRequestSchema, CallToolRequestSchema } from '@modelcontextprotocol/sdk/types.js';
4
+ import { z } from 'zod';
5
+ import { AsyncLocalStorage } from 'async_hooks';
6
+
7
+ // src/mcp/server.ts
8
+
9
+ // src/flags/tokenizer.ts
10
+ var isLongFlagToken = (token) => {
11
+ return token.startsWith("--") && token.length > 2;
12
+ };
13
+
14
+ // src/schemas/zod.ts
15
+ var getShape = (obj) => {
16
+ if (!obj) return void 0;
17
+ return obj.shape;
18
+ };
19
+ var getShapeKeys = (obj) => {
20
+ return Object.keys(getShape(obj) ?? {});
21
+ };
22
+
23
+ // src/schemas/object.ts
24
+ var overrideDateJsonSchema = (ctx) => {
25
+ if (ctx.zodSchema?._zod?.def?.type === "date") {
26
+ const jsonSchema = ctx.jsonSchema;
27
+ jsonSchema.type = "string";
28
+ jsonSchema.format = "date-time";
29
+ }
30
+ };
31
+ var mergeObjects = (parts) => {
32
+ const shapes = parts.map(getShape).filter((shape) => shape !== void 0);
33
+ if (shapes.length === 0) return void 0;
34
+ return z.object(Object.assign({}, ...shapes));
35
+ };
36
+ var getDuplicateKeys = (parts) => {
37
+ const seen = /* @__PURE__ */ new Set();
38
+ const duplicate = /* @__PURE__ */ new Set();
39
+ for (const part of parts) {
40
+ const shape = getShape(part);
41
+ for (const key of Object.keys(shape ?? {})) {
42
+ if (seen.has(key)) duplicate.add(key);
43
+ else seen.add(key);
44
+ }
45
+ }
46
+ return [...duplicate].sort();
47
+ };
48
+ var getDuplicateKeyMessage = (keys) => {
49
+ return `schema fields must be unique across merged inputs: ${keys.join(", ")}`;
50
+ };
51
+ var toJsonSchema = (schema) => {
52
+ if (!schema) return { type: "object", properties: {}, additionalProperties: false };
53
+ return z.toJSONSchema(schema, {
54
+ unrepresentable: "any",
55
+ override: overrideDateJsonSchema
56
+ });
57
+ };
58
+
59
+ // src/command/tree.ts
60
+ var isValidCommandName = (name) => name.length > 0 && !isLongFlagToken(name) && name !== "--";
61
+ var commandTreeIssueCache = /* @__PURE__ */ new WeakMap();
62
+ var commandChildrenMap = /* @__PURE__ */ new WeakMap();
63
+ var emptyCommandChildren = /* @__PURE__ */ new Map();
64
+ var getCommandAliases = (def) => typeof def.alias === "string" ? [def.alias] : def.alias ?? [];
65
+ var getCommandChildren = (node) => {
66
+ return commandChildrenMap.get(node) ?? emptyCommandChildren;
67
+ };
68
+ var findCommandTreeIssue = (root) => {
69
+ if (commandTreeIssueCache.has(root)) return commandTreeIssueCache.get(root);
70
+ const walk = (node) => {
71
+ const owner = node.name;
72
+ const seen = /* @__PURE__ */ new Map();
73
+ const children = getCommandChildren(node);
74
+ for (const [name, child] of children) {
75
+ if (!isValidCommandName(name)) return `invalid command name "${name}" under "${owner}"`;
76
+ const existing = seen.get(name);
77
+ if (existing) return `command name "${name}" for "${name}" conflicts with ${existing}`;
78
+ seen.set(name, `command "${name}"`);
79
+ for (const alias of getCommandAliases(child.def)) {
80
+ if (!isValidCommandName(alias)) return `invalid alias "${alias}" for command "${name}"`;
81
+ const conflict = seen.get(alias);
82
+ if (conflict) return `alias "${alias}" for command "${name}" conflicts with ${conflict}`;
83
+ seen.set(alias, `command "${name}"`);
84
+ }
85
+ }
86
+ for (const child of children.values()) {
87
+ const issue2 = walk(child);
88
+ if (issue2) return issue2;
89
+ }
90
+ return void 0;
91
+ };
92
+ const issue = walk(root);
93
+ commandTreeIssueCache.set(root, issue);
94
+ return issue;
95
+ };
96
+ var getEffectiveCommandDefinition = (chain) => {
97
+ const node = chain[chain.length - 1];
98
+ if (!node) return {};
99
+ return {
100
+ ...node.def,
101
+ options: mergeObjects(chain.map((n) => n.def.options)),
102
+ env: mergeObjects(chain.map((n) => n.def.env))
103
+ };
104
+ };
105
+ var collectCommandEntries = (root) => {
106
+ const entries = [];
107
+ const walk = (node, commandPath, ancestors) => {
108
+ if (node.def.hidden) return;
109
+ const chain = [...ancestors, node];
110
+ entries.push({ commandPath, node, chain, def: getEffectiveCommandDefinition(chain) });
111
+ for (const [name, child] of getCommandChildren(node)) walk(child, [...commandPath, name], chain);
112
+ };
113
+ walk(root, [], []);
114
+ return entries;
115
+ };
116
+
117
+ // src/errors.ts
118
+ var PicocliError = class extends Error {
119
+ code;
120
+ constructor(code, message) {
121
+ super(message);
122
+ this.name = "PicocliError";
123
+ this.code = code;
124
+ }
125
+ };
126
+ var isPicocliError = (e) => e instanceof PicocliError || typeof e === "object" && e !== null && e.name === "PicocliError";
127
+ var getExitCodeForError = (code) => code === "UNKNOWN" ? 1 : 2;
128
+
129
+ // src/render/result.ts
130
+ var createSuccessResult = (data) => {
131
+ return {
132
+ ok: true,
133
+ data: data === void 0 ? null : data
134
+ };
135
+ };
136
+ var createErrorResult = (code, message) => {
137
+ return { ok: false, error: { code, message } };
138
+ };
139
+
140
+ // src/schemas/validate.ts
141
+ var parseSchema = (schema, input, kind) => {
142
+ const result = schema.safeParse(input);
143
+ if (result.success) return result.data;
144
+ const issue = result.error.issues[0] ?? {};
145
+ const field = issue.path?.join(".") || "(input)";
146
+ const expected = "expected" in issue ? String(issue.expected) : void 0;
147
+ const coercible = expected === "number" || expected === "int" || expected === "bigint";
148
+ const hint = coercible ? ` (CLI values arrive as strings \u2014 use z.coerce.${expected}() for non-string ${kind}s)` : "";
149
+ const message = `invalid ${kind} "${field}": ${issue.message}${hint}`;
150
+ throw new PicocliError("VALIDATION", message);
151
+ };
152
+ var parseOutputSchema = (schema, data) => {
153
+ const result = schema.safeParse(data);
154
+ if (result.success) return result.data;
155
+ const issue = result.error.issues[0] ?? {};
156
+ const field = issue.path?.join(".") || "(output)";
157
+ const message = `invalid output "${field}": ${issue.message}`;
158
+ throw new PicocliError("VALIDATION", message);
159
+ };
160
+ var validateAll = (params) => {
161
+ const { args, options, env, argsInput, optionsInput, envInput } = params;
162
+ return {
163
+ args: args ? parseSchema(args, argsInput, "argument") : {},
164
+ options: options ? parseSchema(options, optionsInput, "option") : {},
165
+ env: env ? parseSchema(env, envInput, "environment variable") : {}
166
+ };
167
+ };
168
+ var METHODS = ["log", "info", "debug", "warn", "error"];
169
+ var consoleCaptureStorage = new AsyncLocalStorage();
170
+ var depth = 0;
171
+ var original;
172
+ var createConsoleRouter = (method) => (...args) => {
173
+ const capture = consoleCaptureStorage.getStore();
174
+ const handler = capture?.[method];
175
+ if (handler) handler(args);
176
+ else original?.[method](...args);
177
+ };
178
+ var installConsoleCapture = () => {
179
+ if (depth++ > 0) return;
180
+ original = Object.fromEntries(METHODS.map((method) => [method, console[method].bind(console)]));
181
+ for (const method of METHODS) {
182
+ console[method] = createConsoleRouter(method);
183
+ }
184
+ };
185
+ var uninstallConsoleCapture = () => {
186
+ depth--;
187
+ if (depth > 0 || !original) return;
188
+ for (const method of METHODS) console[method] = original[method];
189
+ original = void 0;
190
+ };
191
+ var withConsoleCapture = async (capture, runCaptured) => {
192
+ installConsoleCapture();
193
+ try {
194
+ return await consoleCaptureStorage.run(capture, runCaptured);
195
+ } finally {
196
+ uninstallConsoleCapture();
197
+ }
198
+ };
199
+ var suppressedConsole = Object.fromEntries(
200
+ METHODS.map((method) => [method, () => {
201
+ }])
202
+ );
203
+
204
+ // src/runtime/run.ts
205
+ var shouldValidateOutput = (mode, nodeEnv) => {
206
+ const resolved = mode ?? "development";
207
+ if (resolved === true) return true;
208
+ if (resolved === false) return false;
209
+ return nodeEnv === "development";
210
+ };
211
+ var createUnknownErrorResult = (error, debug) => {
212
+ debug?.(`${error.stack ?? String(error)}
213
+ `);
214
+ return {
215
+ ok: false,
216
+ error: { code: "UNKNOWN", message: error.message ?? String(error) },
217
+ exitCode: 1
218
+ };
219
+ };
220
+ var createThrownErrorResult = (error, debug) => {
221
+ if (isPicocliError(error)) {
222
+ return {
223
+ ok: false,
224
+ error: { code: error.code, message: error.message },
225
+ exitCode: getExitCodeForError(error.code)
226
+ };
227
+ }
228
+ return createUnknownErrorResult(error, debug);
229
+ };
230
+ var runCommand = async (def, baseContext, opts = {}) => {
231
+ const run = async () => {
232
+ try {
233
+ const retval = await def.run(baseContext);
234
+ const returnedData = retval === void 0 ? null : retval;
235
+ const data = def.outputSchema && shouldValidateOutput(def.validateOutput, opts.nodeEnv) ? parseOutputSchema(def.outputSchema, returnedData) : returnedData;
236
+ return { ok: true, data };
237
+ } catch (error) {
238
+ return createThrownErrorResult(error, opts.debug);
239
+ }
240
+ };
241
+ return opts.suppressConsole ? withConsoleCapture(suppressedConsole, run) : run();
242
+ };
243
+
244
+ // src/runtime/invoke.ts
245
+ var validateCommandInput = (input, values) => {
246
+ try {
247
+ return validateAll({
248
+ args: input.args,
249
+ options: input.options,
250
+ env: input.env,
251
+ argsInput: values.argsInput,
252
+ optionsInput: values.optionsInput,
253
+ envInput: values.envInput
254
+ });
255
+ } catch (error) {
256
+ if (!isPicocliError(error)) throw error;
257
+ return error;
258
+ }
259
+ };
260
+ var createValidationResult = (error) => ({
261
+ ok: false,
262
+ result: createErrorResult(error.code, error.message),
263
+ error: { code: error.code, message: error.message },
264
+ exitCode: getExitCodeForError(error.code)
265
+ });
266
+ var createInvocationResult = (result) => {
267
+ if (result.ok) {
268
+ return {
269
+ ok: true,
270
+ result: createSuccessResult(result.data),
271
+ exitCode: 0
272
+ };
273
+ }
274
+ return {
275
+ ok: false,
276
+ result: createErrorResult(result.error.code, result.error.message),
277
+ error: result.error,
278
+ exitCode: result.exitCode
279
+ };
280
+ };
281
+ var invokeCommand = async (params) => {
282
+ const { def, input, name, inputs, isTTY, isJSON, rest, readStdin, suppressConsole, debug, nodeEnv } = params;
283
+ const parsed = validateCommandInput(input, inputs);
284
+ if (isPicocliError(parsed)) return createValidationResult(parsed);
285
+ const result = await runCommand(
286
+ def,
287
+ {
288
+ name,
289
+ args: parsed.args,
290
+ options: parsed.options,
291
+ env: parsed.env,
292
+ isTTY,
293
+ isJSON,
294
+ rest,
295
+ readStdin
296
+ },
297
+ { suppressConsole, debug, nodeEnv }
298
+ );
299
+ return createInvocationResult(result);
300
+ };
301
+
302
+ // src/schemas/input-model.ts
303
+ var buildInputModel = (def) => {
304
+ return {
305
+ args: def.args,
306
+ options: def.options,
307
+ env: def.env,
308
+ argKeys: getShapeKeys(def.args),
309
+ optionKeys: getShapeKeys(def.options),
310
+ envKeys: getShapeKeys(def.env)
311
+ };
312
+ };
313
+ var getInputSchemas = (model, parts) => {
314
+ return parts.map((part) => model[part]);
315
+ };
316
+ var assertUniqueInputKeys = (model, parts) => {
317
+ const conflicts = getDuplicateKeys(getInputSchemas(model, parts));
318
+ if (conflicts.length > 0) throw new PicocliError("VALIDATION", getDuplicateKeyMessage(conflicts));
319
+ };
320
+ var getInputJsonSchema = (model, parts) => {
321
+ return toJsonSchema(mergeObjects(getInputSchemas(model, parts)));
322
+ };
323
+ var splitNamedInput = (model, rawInput) => {
324
+ const argKeys = new Set(model.argKeys);
325
+ const optionKeys = new Set(model.optionKeys);
326
+ const argsInput = {};
327
+ const optionsInput = {};
328
+ let unknownKey;
329
+ for (const [key, value] of Object.entries(rawInput)) {
330
+ if (argKeys.has(key)) argsInput[key] = value;
331
+ else if (optionKeys.has(key)) optionsInput[key] = value;
332
+ else unknownKey ??= key;
333
+ }
334
+ return { argsInput, optionsInput, unknownKey };
335
+ };
336
+ var getEnvInputForKeys = (envKeys, processEnv) => {
337
+ const input = {};
338
+ for (const key of envKeys) {
339
+ const value = processEnv[key];
340
+ if (value !== void 0) input[key] = value;
341
+ }
342
+ return input;
343
+ };
344
+ var getEnvInput = (model, processEnv) => {
345
+ return getEnvInputForKeys(model.envKeys, processEnv);
346
+ };
347
+
348
+ // src/mcp/tools.ts
349
+ var createToolResult = (result) => {
350
+ const structuredContent = result;
351
+ return {
352
+ content: [{ type: "text", text: JSON.stringify(structuredContent) }],
353
+ structuredContent,
354
+ isError: !structuredContent.ok
355
+ };
356
+ };
357
+ var createToolErrorResult = (code, message) => createToolResult(createErrorResult(code, message));
358
+ var createUnknownToolResult = (toolName) => createToolErrorResult("COMMAND_NOT_FOUND", `unknown tool: ${toolName}`);
359
+ var getToolInputSchema = (entry) => {
360
+ const model = buildInputModel(entry.def);
361
+ assertUniqueInputKeys(model, ["args", "options"]);
362
+ return getInputJsonSchema(model, ["args", "options"]);
363
+ };
364
+ var getToolOutputSchema = (entry) => {
365
+ if (!entry.def.outputSchema) return void 0;
366
+ return {
367
+ type: "object",
368
+ anyOf: [
369
+ {
370
+ type: "object",
371
+ properties: {
372
+ ok: { const: true },
373
+ data: toJsonSchema(entry.def.outputSchema)
374
+ },
375
+ required: ["ok", "data"],
376
+ additionalProperties: false
377
+ },
378
+ {
379
+ type: "object",
380
+ properties: {
381
+ ok: { const: false },
382
+ error: {
383
+ type: "object",
384
+ properties: {
385
+ code: { type: "string" },
386
+ message: { type: "string" }
387
+ },
388
+ required: ["code", "message"],
389
+ additionalProperties: false
390
+ }
391
+ },
392
+ required: ["ok", "error"],
393
+ additionalProperties: false
394
+ }
395
+ ]
396
+ };
397
+ };
398
+ var getToolEntries = (root) => {
399
+ const treeIssue = findCommandTreeIssue(root);
400
+ if (treeIssue) throw new Error(treeIssue);
401
+ const tools = [];
402
+ const names = /* @__PURE__ */ new Set();
403
+ for (const entry of collectCommandEntries(root)) {
404
+ if (!entry.node.def.run) continue;
405
+ const name = entry.commandPath.length > 0 ? entry.commandPath.join("_") : root.name;
406
+ if (names.has(name)) throw new Error(`duplicate MCP tool name: ${name}`);
407
+ names.add(name);
408
+ tools.push({
409
+ name,
410
+ description: entry.node.def.description ?? "",
411
+ node: entry.node,
412
+ commandPath: entry.commandPath,
413
+ def: entry.def
414
+ });
415
+ }
416
+ return tools;
417
+ };
418
+ var listTools = (root) => {
419
+ return getToolEntries(root).map((entry) => ({
420
+ name: entry.name,
421
+ description: entry.description,
422
+ inputSchema: getToolInputSchema(entry),
423
+ ...entry.def.outputSchema ? { outputSchema: getToolOutputSchema(entry) } : {}
424
+ }));
425
+ };
426
+ var invokeToolCommand = async (root, entry, rawArgs, opts) => {
427
+ const def = entry.def;
428
+ const model = buildInputModel(def);
429
+ const namedInput = splitNamedInput(model, rawArgs);
430
+ assertUniqueInputKeys(model, ["args", "options"]);
431
+ if (namedInput.unknownKey) {
432
+ throw new PicocliError("VALIDATION", `unknown tool argument "${namedInput.unknownKey}"`);
433
+ }
434
+ const result = await invokeCommand({
435
+ def,
436
+ input: model,
437
+ name: [root.name, ...entry.commandPath].join(" "),
438
+ inputs: {
439
+ argsInput: namedInput.argsInput,
440
+ optionsInput: namedInput.optionsInput,
441
+ envInput: getEnvInput(model, opts.env)
442
+ },
443
+ isTTY: false,
444
+ isJSON: true,
445
+ rest: [],
446
+ readStdin: async () => "",
447
+ suppressConsole: true,
448
+ nodeEnv: opts.env.NODE_ENV
449
+ });
450
+ return result.result;
451
+ };
452
+ var invokeToolEntry = async (root, entry, rawArgs, opts) => {
453
+ try {
454
+ return createToolResult(await invokeToolCommand(root, entry, rawArgs, opts));
455
+ } catch (error) {
456
+ const message = isPicocliError(error) ? error.message : error.message ?? String(error);
457
+ const code = isPicocliError(error) ? error.code : "UNKNOWN";
458
+ return createToolErrorResult(code, message);
459
+ }
460
+ };
461
+ var invokeTool = async (root, toolName, args = {}, opts = {}) => {
462
+ const runtimeOptions = { env: opts.env ?? process.env };
463
+ const entry = getToolEntries(root).find((tool) => tool.name === toolName);
464
+ if (!entry) return createUnknownToolResult(toolName);
465
+ return invokeToolEntry(root, entry, args, runtimeOptions);
466
+ };
467
+
468
+ // src/mcp/server.ts
469
+ var buildServer = (root, opts = {}) => {
470
+ const runtimeOptions = { env: opts.env ?? process.env };
471
+ const tools = getToolEntries(root);
472
+ const byName = new Map(tools.map((tool) => [tool.name, tool]));
473
+ const toolDefinitions = tools.map((entry) => ({
474
+ name: entry.name,
475
+ description: entry.description,
476
+ inputSchema: getToolInputSchema(entry),
477
+ ...entry.def.outputSchema ? { outputSchema: getToolOutputSchema(entry) } : {}
478
+ }));
479
+ const server = new Server(
480
+ { name: root.name, version: root.def.version ?? "0.0.0" },
481
+ { capabilities: { tools: {} } }
482
+ );
483
+ server.setRequestHandler(ListToolsRequestSchema, async () => ({
484
+ tools: toolDefinitions
485
+ }));
486
+ server.setRequestHandler(CallToolRequestSchema, async (req) => {
487
+ const entry = byName.get(req.params.name);
488
+ if (!entry) return createUnknownToolResult(req.params.name);
489
+ return invokeToolEntry(
490
+ root,
491
+ entry,
492
+ req.params.arguments ?? {},
493
+ runtimeOptions
494
+ );
495
+ });
496
+ return server;
497
+ };
498
+ var serveMcp = async (root, opts = {}) => {
499
+ await buildServer(root, opts).connect(new StdioServerTransport());
500
+ };
501
+
502
+ export { buildServer, invokeTool, listTools, serveMcp };
@@ -0,0 +1,115 @@
1
+ 'use strict';
2
+
3
+ var util = require('util');
4
+ var async_hooks = require('async_hooks');
5
+
6
+ // src/testing/testkit.ts
7
+ var METHODS = ["log", "info", "debug", "warn", "error"];
8
+ var consoleCaptureStorage = new async_hooks.AsyncLocalStorage();
9
+ var depth = 0;
10
+ var original;
11
+ var createConsoleRouter = (method) => (...args) => {
12
+ const capture = consoleCaptureStorage.getStore();
13
+ const handler = capture?.[method];
14
+ if (handler) handler(args);
15
+ else original?.[method](...args);
16
+ };
17
+ var installConsoleCapture = () => {
18
+ if (depth++ > 0) return;
19
+ original = Object.fromEntries(METHODS.map((method) => [method, console[method].bind(console)]));
20
+ for (const method of METHODS) {
21
+ console[method] = createConsoleRouter(method);
22
+ }
23
+ };
24
+ var uninstallConsoleCapture = () => {
25
+ depth--;
26
+ if (depth > 0 || !original) return;
27
+ for (const method of METHODS) console[method] = original[method];
28
+ original = void 0;
29
+ };
30
+ var withConsoleCapture = async (capture, runCaptured) => {
31
+ installConsoleCapture();
32
+ try {
33
+ return await consoleCaptureStorage.run(capture, runCaptured);
34
+ } finally {
35
+ uninstallConsoleCapture();
36
+ }
37
+ };
38
+ Object.fromEntries(
39
+ METHODS.map((method) => [method, () => {
40
+ }])
41
+ );
42
+
43
+ // src/testing/testkit.ts
44
+ var formatConsoleArgs = (args) => `${util.format(...args)}
45
+ `;
46
+ var createConsoleCapture = (output) => ({
47
+ log: (args) => void output.stdout.push(formatConsoleArgs(args)),
48
+ info: (args) => void output.stdout.push(formatConsoleArgs(args)),
49
+ debug: (args) => void output.stdout.push(formatConsoleArgs(args)),
50
+ error: (args) => void output.stderr.push(formatConsoleArgs(args)),
51
+ warn: (args) => void output.stderr.push(formatConsoleArgs(args))
52
+ });
53
+ var parseJsonResult = (stdout) => {
54
+ try {
55
+ const json = JSON.parse(stdout);
56
+ return { stdout: `${JSON.stringify(json)}
57
+ `, json, hasJson: true };
58
+ } catch {
59
+ return { stdout, json: void 0, hasJson: false };
60
+ }
61
+ };
62
+ var runCliWithOutputFormat = async (app, argv, opts, outputFormat) => {
63
+ const output = {
64
+ stdout: [],
65
+ stderr: [],
66
+ exitCode: 0,
67
+ wroteFrameworkStdout: false
68
+ };
69
+ const stdin = opts.stdin;
70
+ const readStdin = stdin === void 0 ? void 0 : async () => stdin;
71
+ await withConsoleCapture(createConsoleCapture(output), async () => {
72
+ await app.serve(argv, {
73
+ stdout: (s) => {
74
+ output.wroteFrameworkStdout = true;
75
+ output.stdout.push(s);
76
+ },
77
+ stderr: (s) => {
78
+ output.stderr.push(s);
79
+ },
80
+ exit: (code) => {
81
+ output.exitCode = code;
82
+ },
83
+ env: opts.env ?? {},
84
+ isTTY: opts.isTTY ?? false,
85
+ stdin: readStdin,
86
+ format: outputFormat
87
+ });
88
+ });
89
+ const stdout = output.stdout.join("");
90
+ const stderr = output.stderr.join("");
91
+ if (outputFormat !== "json" && !output.wroteFrameworkStdout) {
92
+ return { stdout, stderr, exitCode: output.exitCode, json: void 0, hasJson: false };
93
+ }
94
+ const parsed = parseJsonResult(stdout);
95
+ return {
96
+ stdout: parsed.stdout,
97
+ stderr,
98
+ exitCode: output.exitCode,
99
+ json: parsed.json,
100
+ hasJson: parsed.hasJson
101
+ };
102
+ };
103
+ var runCli = async (app, argv, opts = {}) => {
104
+ const { hasJson: _, ...result } = await runCliWithOutputFormat(app, argv, opts, void 0);
105
+ return result;
106
+ };
107
+ var runJson = async (app, argv, opts = {}) => {
108
+ const result = await runCliWithOutputFormat(app, argv, opts, "json");
109
+ if (!result.hasJson) throw new Error("runJson expected JSON output");
110
+ const { hasJson: _, ...publicResult } = result;
111
+ return publicResult;
112
+ };
113
+
114
+ exports.runCli = runCli;
115
+ exports.runJson = runJson;
@@ -0,0 +1,23 @@
1
+ import { e as CommandErrorResult, b as Cli } from '../create-eQnnIhZu.cjs';
2
+ import 'zod';
3
+
4
+ type TestJsonValue<T = unknown> = CommandErrorResult | T;
5
+ interface TestRunResult<T = unknown> {
6
+ stdout: string;
7
+ stderr: string;
8
+ exitCode: number;
9
+ json: TestJsonValue<T> | undefined;
10
+ }
11
+ interface TestJsonRunResult<T = unknown> extends TestRunResult<T> {
12
+ json: TestJsonValue<T>;
13
+ }
14
+ interface TestRunOptions {
15
+ env?: Record<string, string | undefined>;
16
+ isTTY?: boolean;
17
+ stdin?: string;
18
+ }
19
+
20
+ declare const runCli: <T = unknown>(app: Cli, argv: string[], opts?: TestRunOptions) => Promise<TestRunResult<T>>;
21
+ declare const runJson: <T = unknown>(app: Cli, argv: string[], opts?: TestRunOptions) => Promise<TestJsonRunResult<T>>;
22
+
23
+ export { type TestJsonRunResult, type TestJsonValue, type TestRunOptions, type TestRunResult, runCli, runJson };
@@ -0,0 +1,23 @@
1
+ import { e as CommandErrorResult, b as Cli } from '../create-eQnnIhZu.js';
2
+ import 'zod';
3
+
4
+ type TestJsonValue<T = unknown> = CommandErrorResult | T;
5
+ interface TestRunResult<T = unknown> {
6
+ stdout: string;
7
+ stderr: string;
8
+ exitCode: number;
9
+ json: TestJsonValue<T> | undefined;
10
+ }
11
+ interface TestJsonRunResult<T = unknown> extends TestRunResult<T> {
12
+ json: TestJsonValue<T>;
13
+ }
14
+ interface TestRunOptions {
15
+ env?: Record<string, string | undefined>;
16
+ isTTY?: boolean;
17
+ stdin?: string;
18
+ }
19
+
20
+ declare const runCli: <T = unknown>(app: Cli, argv: string[], opts?: TestRunOptions) => Promise<TestRunResult<T>>;
21
+ declare const runJson: <T = unknown>(app: Cli, argv: string[], opts?: TestRunOptions) => Promise<TestJsonRunResult<T>>;
22
+
23
+ export { type TestJsonRunResult, type TestJsonValue, type TestRunOptions, type TestRunResult, runCli, runJson };