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/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) {