argsbarg 6.1.0 → 6.1.2
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.
- package/CHANGELOG.md +24 -2
- package/README.md +5 -2
- package/docs/api-server.md +1 -1
- package/docs/cli-program.md +35 -8
- package/docs/output-schema.md +1 -1
- package/index.d.ts +47 -8
- package/package.json +1 -1
- package/src/cli.ts +54 -1
- package/src/context.ts +40 -57
- package/src/help.ts +51 -15
- package/src/index.ts +10 -1
- package/src/json-leaf.test.ts +156 -0
- package/src/leaf-inputs.test.ts +118 -9
- package/src/leaf-inputs.ts +143 -70
- package/src/mcp/tools.ts +9 -0
- package/src/parse.ts +50 -0
- package/src/types.ts +13 -0
- package/src/validate.ts +12 -0
package/src/parse.ts
CHANGED
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
CliOptionKind,
|
|
17
17
|
isCliLeaf,
|
|
18
18
|
isCliRouter,
|
|
19
|
+
isJsonLeaf,
|
|
19
20
|
} from "./types.ts";
|
|
20
21
|
import { fullStringIsDouble } from "./utils.ts";
|
|
21
22
|
|
|
@@ -237,6 +238,48 @@ export function collectOptionDefs(root: CliNode, path: string[]): CliOption[] {
|
|
|
237
238
|
return defs;
|
|
238
239
|
}
|
|
239
240
|
|
|
241
|
+
/** Fills `args` for a json leaf from `startIdx` (0 or 1 JSON string positional). */
|
|
242
|
+
function finishJsonLeaf(
|
|
243
|
+
_node: CliLeaf,
|
|
244
|
+
startIdx: number,
|
|
245
|
+
argv: string[],
|
|
246
|
+
path: string[],
|
|
247
|
+
opts: Record<string, string>,
|
|
248
|
+
): ParseResult {
|
|
249
|
+
let idx = startIdx;
|
|
250
|
+
const args: string[] = [];
|
|
251
|
+
|
|
252
|
+
if (idx < argv.length) {
|
|
253
|
+
const tok = argv[idx];
|
|
254
|
+
if (isHelpTok(tok)) {
|
|
255
|
+
return helpResult(path, true);
|
|
256
|
+
}
|
|
257
|
+
if (tok === "--") {
|
|
258
|
+
return errorResult("Unexpected extra arguments", path, []);
|
|
259
|
+
}
|
|
260
|
+
if (tok.startsWith("-")) {
|
|
261
|
+
return errorResult(`JSON commands do not accept options: ${tok}`, path, []);
|
|
262
|
+
}
|
|
263
|
+
args.push(tok);
|
|
264
|
+
idx += 1;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
if (idx < argv.length) {
|
|
268
|
+
return errorResult("Unexpected extra arguments", path, []);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
return {
|
|
272
|
+
kind: ParseKind.Ok,
|
|
273
|
+
path,
|
|
274
|
+
opts,
|
|
275
|
+
args,
|
|
276
|
+
helpExplicit: false,
|
|
277
|
+
helpPath: [],
|
|
278
|
+
errorMsg: "",
|
|
279
|
+
errorHelpPath: [],
|
|
280
|
+
};
|
|
281
|
+
}
|
|
282
|
+
|
|
240
283
|
/** Fills `args` for a leaf from `startIdx` according to `node.positionals`. */
|
|
241
284
|
function finishLeaf(
|
|
242
285
|
node: CliLeaf,
|
|
@@ -412,6 +455,9 @@ export function parse(root: CliNode, argv: string[]): ParseResult {
|
|
|
412
455
|
let node: CliNode | undefined;
|
|
413
456
|
|
|
414
457
|
if (isCliLeaf(root)) {
|
|
458
|
+
if (isJsonLeaf(root)) {
|
|
459
|
+
return finishJsonLeaf(root, i, argv, path, opts);
|
|
460
|
+
}
|
|
415
461
|
return finishLeaf(root, i, argv, path, opts, root.options ?? [], forcePositionals);
|
|
416
462
|
}
|
|
417
463
|
|
|
@@ -473,6 +519,10 @@ export function parse(root: CliNode, argv: string[]): ParseResult {
|
|
|
473
519
|
|
|
474
520
|
// Walk the command tree
|
|
475
521
|
while (true) {
|
|
522
|
+
if (isCliLeaf(current) && isJsonLeaf(current)) {
|
|
523
|
+
return finishJsonLeaf(current, i, argv, path, opts);
|
|
524
|
+
}
|
|
525
|
+
|
|
476
526
|
if (!forcePositionals) {
|
|
477
527
|
const orep = consumeOptions(collectOptionDefs(root, path), false, argv, i, opts);
|
|
478
528
|
if (orep.report.err) {
|
package/src/types.ts
CHANGED
|
@@ -418,10 +418,18 @@ export interface CliNodeBase {
|
|
|
418
418
|
options?: CliOption[];
|
|
419
419
|
}
|
|
420
420
|
|
|
421
|
+
/** Leaf input mode: `json` = pure JSON body (no CLI flags). */
|
|
422
|
+
export type CliLeafKind = "json";
|
|
423
|
+
|
|
421
424
|
/**
|
|
422
425
|
* A leaf command node with a handler and optional positionals.
|
|
423
426
|
*/
|
|
424
427
|
export type CliLeaf = CliNodeBase & {
|
|
428
|
+
/**
|
|
429
|
+
* When `"json"`, the leaf accepts a single JSON document (CLI positional or piped stdin;
|
|
430
|
+
* MCP/HTTP tool args = body). Requires `inputSchema`; forbids `options` and `positionals`.
|
|
431
|
+
*/
|
|
432
|
+
kind?: CliLeafKind;
|
|
425
433
|
/** Handler function for leaf commands. */
|
|
426
434
|
handler: CliHandler;
|
|
427
435
|
/** Positional argument definitions. */
|
|
@@ -482,6 +490,11 @@ export function isCliLeaf(node: CliNode): node is CliLeaf {
|
|
|
482
490
|
return "handler" in node && typeof node.handler === "function";
|
|
483
491
|
}
|
|
484
492
|
|
|
493
|
+
/** True when the leaf accepts a pure JSON body (no CLI flags). */
|
|
494
|
+
export function isJsonLeaf(leaf: CliLeaf): boolean {
|
|
495
|
+
return leaf.kind === "json";
|
|
496
|
+
}
|
|
497
|
+
|
|
485
498
|
/** True when the node is a router (has subcommands). */
|
|
486
499
|
export function isCliRouter(node: CliNode): node is CliRouter {
|
|
487
500
|
return "commands" in node && Array.isArray(node.commands);
|
package/src/validate.ts
CHANGED
|
@@ -19,6 +19,7 @@ import {
|
|
|
19
19
|
type InstallTargetSpec,
|
|
20
20
|
isCliLeaf,
|
|
21
21
|
isCliRouter,
|
|
22
|
+
isJsonLeaf,
|
|
22
23
|
} from "./types.ts";
|
|
23
24
|
|
|
24
25
|
/** Validates `docs` configuration on the program root. */
|
|
@@ -238,6 +239,17 @@ function walkNode(node: CliNode, program: CliProgram, isRoot: boolean): void {
|
|
|
238
239
|
if (isRoot && node.mcpTool !== undefined) {
|
|
239
240
|
throw new CliSchemaValidationError("mcpTool is only supported on leaf commands");
|
|
240
241
|
}
|
|
242
|
+
if (isJsonLeaf(node)) {
|
|
243
|
+
if (node.inputSchema === undefined) {
|
|
244
|
+
throw new CliSchemaValidationError(`kind: "json" requires inputSchema on ${node.key}`);
|
|
245
|
+
}
|
|
246
|
+
if ((node.options ?? []).length > 0) {
|
|
247
|
+
throw new CliSchemaValidationError(`kind: "json" forbids options on ${node.key}`);
|
|
248
|
+
}
|
|
249
|
+
if ((node.positionals ?? []).length > 0) {
|
|
250
|
+
throw new CliSchemaValidationError(`kind: "json" forbids positionals on ${node.key}`);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
241
253
|
const outputSchema = node.outputSchema;
|
|
242
254
|
const legacyOutputSchema = node.mcpTool?.outputSchema;
|
|
243
255
|
if (outputSchema !== undefined && legacyOutputSchema !== undefined) {
|