argsbarg 7.0.6 → 7.0.8
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 +22 -1
- package/README.md +4 -4
- package/docs/README.md +1 -1
- package/docs/ai-skills.md +14 -62
- package/docs/bundled-docs.md +9 -13
- package/docs/cli-program.md +10 -11
- package/docs/configure.md +9 -11
- package/docs/output-schema.md +1 -1
- package/examples/full-example/AGENTS.md +3 -3
- package/examples/full-example/docs/README.md +1 -1
- package/examples/full-example/justfile +0 -1
- package/examples/full-example/skills/full-example/SKILL.md +0 -2
- package/examples/full-example/src/program.ts +0 -1
- package/examples/full-example-json/AGENTS.md +3 -3
- package/examples/full-example-json/docs/README.md +1 -1
- package/examples/full-example-json/justfile +0 -1
- package/examples/full-example-json/skills/full-example-json/SKILL.md +0 -2
- package/examples/full-example-json/src/program.ts +0 -1
- package/index.d.ts +5 -3
- package/package.json +1 -1
- package/src/builtins/builtins.test.ts +1 -22
- package/src/builtins/configure-copy.ts +4 -11
- package/src/builtins/presentation.ts +2 -5
- package/src/configure/artifacts/status.test.ts +5 -5
- package/src/configure/artifacts/target-effective.ts +1 -2
- package/src/configure/artifacts/target-skill.ts +9 -15
- package/src/configure/artifacts/targets/skill.ts +8 -1
- package/src/configure/artifacts/targets.test.ts +5 -5
- package/src/configure/configure.test.ts +4 -4
- package/src/core/parse.test.ts +1 -112
- package/src/core/types.ts +5 -3
- package/src/core/validate.ts +4 -2
- package/src/docs/builtin.ts +5 -3
- package/src/docs/cli-guide.ts +3 -3
- package/src/docs/docs.test.ts +3 -47
- package/src/docs/resolve.ts +5 -5
- package/src/docs/save.ts +9 -20
- package/src/help.test.ts +250 -8
- package/src/help.ts +397 -46
- package/src/skill/generate.ts +30 -156
- package/src/skill/hint.ts +2 -15
- package/src/skill/install.ts +3 -35
package/src/help.ts
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
/*
|
|
2
|
-
This module renders CLI help with wrapping, boxes, tables, and TTY color
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
This module renders CLI help with wrapping, boxes, tables, and TTY color for interactive
|
|
3
|
+
terminal sessions, as well as clean unboxed plain text with in-band YAML input and output
|
|
4
|
+
schemas for non-TTY agent discovery and piping.
|
|
5
5
|
|
|
6
6
|
It keeps help formatting shared across help and error paths so users see one consistent
|
|
7
7
|
style no matter how help is reached.
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
import {
|
|
11
|
+
type CliLeaf,
|
|
11
12
|
type CliNode,
|
|
12
13
|
type CliOption,
|
|
13
14
|
CliOptionKind,
|
|
@@ -73,9 +74,9 @@ function getHelpWidth(): number {
|
|
|
73
74
|
return Math.max(40, process.stdout.columns || 80);
|
|
74
75
|
}
|
|
75
76
|
|
|
76
|
-
/** True when stdout is a TTY (used to decide on color). */
|
|
77
|
-
function
|
|
78
|
-
return !!process.stdout.isTTY;
|
|
77
|
+
/** True when stdout/stderr is a TTY (used to decide on boxes and color). */
|
|
78
|
+
function isOutputTTY(useStderr: boolean): boolean {
|
|
79
|
+
return useStderr ? !!process.stderr.isTTY : !!process.stdout.isTTY;
|
|
79
80
|
}
|
|
80
81
|
|
|
81
82
|
// ── Width Helpers ─────────────────────────────────────────────────────────────
|
|
@@ -321,6 +322,52 @@ function renderTableBox(title: string, rows: HelpRow[], hw: number, color: boole
|
|
|
321
322
|
return out;
|
|
322
323
|
}
|
|
323
324
|
|
|
325
|
+
/** Renders a plain-text section with a header and 2-space indented lines (non-TTY). */
|
|
326
|
+
function renderPlainSection(
|
|
327
|
+
/** Section header title (e.g. "Usage" or "Notes"). */
|
|
328
|
+
title: string,
|
|
329
|
+
/** Content lines to indent under the header. */
|
|
330
|
+
lines: string[],
|
|
331
|
+
): string[] {
|
|
332
|
+
if (lines.length === 0) return [];
|
|
333
|
+
const out: string[] = [`${title}:`];
|
|
334
|
+
for (const line of lines) {
|
|
335
|
+
out.push(line.length > 0 ? ` ${line}` : "");
|
|
336
|
+
}
|
|
337
|
+
return out;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
/** Renders a plain-text two-column table without box borders (non-TTY). */
|
|
341
|
+
function renderPlainTable(
|
|
342
|
+
/** Section header title (e.g. "Options" or "Subcommands"). */
|
|
343
|
+
title: string,
|
|
344
|
+
/** Rows with label and description to format. */
|
|
345
|
+
rows: HelpRow[],
|
|
346
|
+
/** Available terminal width. */
|
|
347
|
+
hw: number,
|
|
348
|
+
): string[] {
|
|
349
|
+
if (rows.length === 0) return [];
|
|
350
|
+
let labelWidth = 0;
|
|
351
|
+
for (const row of rows) {
|
|
352
|
+
labelWidth = Math.max(labelWidth, visibleWidth(row.label));
|
|
353
|
+
}
|
|
354
|
+
const descWidth = Math.max(20, hw - labelWidth - 4);
|
|
355
|
+
const out: string[] = [`${title}:`];
|
|
356
|
+
for (const row of rows) {
|
|
357
|
+
const wrapped = wrapText(row.description, descWidth);
|
|
358
|
+
const paddedLabel = padVisible(row.label, labelWidth);
|
|
359
|
+
if (wrapped.length === 0 || wrapped[0].length === 0) {
|
|
360
|
+
out.push(` ${row.label}`);
|
|
361
|
+
} else {
|
|
362
|
+
out.push(` ${paddedLabel} ${wrapped[0]}`);
|
|
363
|
+
for (let idx = 1; idx < wrapped.length; idx++) {
|
|
364
|
+
out.push(` ${spaces(labelWidth)} ${wrapped[idx]}`);
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
return out;
|
|
369
|
+
}
|
|
370
|
+
|
|
324
371
|
// ── Usage & Rows ──────────────────────────────────────────────────────────────
|
|
325
372
|
|
|
326
373
|
/** Builds one or two usage line strings (OPTIONS / COMMAND / ARGS) for the help header. */
|
|
@@ -404,24 +451,287 @@ function rowsForSubcommands(cmds: CliNode[]): HelpRow[] {
|
|
|
404
451
|
.map((c) => ({ label: c.key, description: c.description }));
|
|
405
452
|
}
|
|
406
453
|
|
|
454
|
+
// ── Schema YAML Formatting ───────────────────────────────────────────────────
|
|
455
|
+
|
|
456
|
+
/**
|
|
457
|
+
* Resolves a JSON Schema $ref pointer from definitions or $defs.
|
|
458
|
+
*/
|
|
459
|
+
function resolveRef(
|
|
460
|
+
/** Reference URI string (e.g. `#/definitions/Foo` or `#/$defs/Foo`). */
|
|
461
|
+
ref: string,
|
|
462
|
+
/** Definitions dictionary from the root schema. */
|
|
463
|
+
defs: Record<string, unknown>,
|
|
464
|
+
): Record<string, unknown> | null {
|
|
465
|
+
const name = ref.replace(/^#\/(definitions|\$defs)\//, "");
|
|
466
|
+
const target = defs[name];
|
|
467
|
+
if (typeof target === "object" && target !== null) {
|
|
468
|
+
return target as Record<string, unknown>;
|
|
469
|
+
}
|
|
470
|
+
return null;
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
/**
|
|
474
|
+
* Formats a single-line type representation from a JSON Schema fragment.
|
|
475
|
+
* Returns null if the type is complex and requires multiline YAML formatting.
|
|
476
|
+
*/
|
|
477
|
+
function formatType(
|
|
478
|
+
/** Schema fragment to inspect. */
|
|
479
|
+
schema: Record<string, unknown>,
|
|
480
|
+
/** Schema definitions for reference lookup. */
|
|
481
|
+
defs: Record<string, unknown>,
|
|
482
|
+
/** Ancestor reference names visited in the current descent. */
|
|
483
|
+
seen: Set<string>,
|
|
484
|
+
): string | null {
|
|
485
|
+
if (typeof schema.$ref === "string") {
|
|
486
|
+
const name = schema.$ref.replace(/^#\/(definitions|\$defs)\//, "");
|
|
487
|
+
if (seen.has(name)) {
|
|
488
|
+
return name;
|
|
489
|
+
}
|
|
490
|
+
seen.add(name);
|
|
491
|
+
const resolved = resolveRef(schema.$ref, defs);
|
|
492
|
+
const res = resolved ? formatType(resolved, defs, seen) : name;
|
|
493
|
+
seen.delete(name);
|
|
494
|
+
return res;
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
if (Array.isArray(schema.enum) && schema.enum.length > 0) {
|
|
498
|
+
return schema.enum.map((v) => (typeof v === "string" ? JSON.stringify(v) : String(v))).join(" | ");
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
const union = (schema.anyOf ?? schema.oneOf) as unknown[];
|
|
502
|
+
if (Array.isArray(union) && union.length > 0) {
|
|
503
|
+
const parts: string[] = [];
|
|
504
|
+
let allSimple = true;
|
|
505
|
+
for (const variant of union) {
|
|
506
|
+
if (typeof variant === "object" && variant !== null) {
|
|
507
|
+
const formatted = formatType(variant as Record<string, unknown>, defs, seen);
|
|
508
|
+
if (formatted !== null) {
|
|
509
|
+
parts.push(formatted);
|
|
510
|
+
} else {
|
|
511
|
+
allSimple = false;
|
|
512
|
+
break;
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
if (allSimple && parts.length > 0) {
|
|
517
|
+
return parts.join(" | ");
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
if (Array.isArray(schema.type)) {
|
|
522
|
+
return schema.type.join(" | ");
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
if (schema.type === "string") {
|
|
526
|
+
if (typeof schema.format === "string") {
|
|
527
|
+
return `string (${schema.format})`;
|
|
528
|
+
}
|
|
529
|
+
return "string";
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
if (schema.type === "number") return "number";
|
|
533
|
+
if (schema.type === "integer") return "integer";
|
|
534
|
+
if (schema.type === "boolean") return "boolean";
|
|
535
|
+
if (schema.type === "null") return "null";
|
|
536
|
+
|
|
537
|
+
if (schema.type === "array" && schema.items && typeof schema.items === "object") {
|
|
538
|
+
const itemType = formatType(schema.items as Record<string, unknown>, defs, seen);
|
|
539
|
+
if (itemType !== null) {
|
|
540
|
+
if (itemType.includes(" | ")) {
|
|
541
|
+
return `(${itemType})[]`;
|
|
542
|
+
}
|
|
543
|
+
return `${itemType}[]`;
|
|
544
|
+
}
|
|
545
|
+
return null;
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
if (schema.type === "object" || schema.properties !== undefined) {
|
|
549
|
+
if (schema.properties && typeof schema.properties === "object" && Object.keys(schema.properties).length > 0) {
|
|
550
|
+
return null;
|
|
551
|
+
}
|
|
552
|
+
if (schema.additionalProperties && typeof schema.additionalProperties === "object") {
|
|
553
|
+
const valType = formatType(schema.additionalProperties as Record<string, unknown>, defs, seen) ?? "object";
|
|
554
|
+
return `{ [key: string]: ${valType} }`;
|
|
555
|
+
}
|
|
556
|
+
return "object";
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
return null;
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
/**
|
|
563
|
+
* Formats a JSON Schema node into multiline YAML lines with JSDoc comments.
|
|
564
|
+
*/
|
|
565
|
+
function formatSchemaLines(
|
|
566
|
+
/** Schema object to format. */
|
|
567
|
+
schema: Record<string, unknown>,
|
|
568
|
+
/** Schema definitions dictionary. */
|
|
569
|
+
defs: Record<string, unknown>,
|
|
570
|
+
/** Indentation level in spaces. */
|
|
571
|
+
indent: number,
|
|
572
|
+
/** Ancestor reference names visited in the current descent. */
|
|
573
|
+
seen: Set<string>,
|
|
574
|
+
): string[] {
|
|
575
|
+
if (typeof schema.$ref === "string") {
|
|
576
|
+
const name = schema.$ref.replace(/^#\/(definitions|\$defs)\//, "");
|
|
577
|
+
if (seen.has(name)) {
|
|
578
|
+
return [`${spaces(indent)}${name}`];
|
|
579
|
+
}
|
|
580
|
+
seen.add(name);
|
|
581
|
+
const resolved = resolveRef(schema.$ref, defs);
|
|
582
|
+
const res = resolved ? formatSchemaLines(resolved, defs, indent, seen) : [`${spaces(indent)}${name}`];
|
|
583
|
+
seen.delete(name);
|
|
584
|
+
return res;
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
if (schema.type === "object" || schema.properties !== undefined) {
|
|
588
|
+
const props = (schema.properties as Record<string, Record<string, unknown>>) ?? {};
|
|
589
|
+
const required = new Set(Array.isArray(schema.required) ? schema.required.map((k) => String(k)) : []);
|
|
590
|
+
const propEntries = Object.entries(props);
|
|
591
|
+
if (propEntries.length === 0) {
|
|
592
|
+
const simple = formatType(schema, defs, seen);
|
|
593
|
+
return simple ? [`${spaces(indent)}${simple}`] : [`${spaces(indent)}{}`];
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
const lines: string[] = [];
|
|
597
|
+
for (const [key, prop] of propEntries) {
|
|
598
|
+
if (typeof prop !== "object" || prop === null) continue;
|
|
599
|
+
const desc = typeof prop.description === "string" ? prop.description.trim() : "";
|
|
600
|
+
if (desc.length > 0) {
|
|
601
|
+
for (const dLine of desc.split("\n")) {
|
|
602
|
+
lines.push(`${spaces(indent)}# ${dLine.trim()}`);
|
|
603
|
+
}
|
|
604
|
+
}
|
|
605
|
+
const isReq = required.has(key);
|
|
606
|
+
const keyStr = isReq ? key : `${key}?`;
|
|
607
|
+
const simple = formatType(prop, defs, seen);
|
|
608
|
+
if (simple !== null) {
|
|
609
|
+
lines.push(`${spaces(indent)}${keyStr}: ${simple}`);
|
|
610
|
+
} else {
|
|
611
|
+
if (prop.type === "array" && prop.items && typeof prop.items === "object") {
|
|
612
|
+
lines.push(`${spaces(indent)}${keyStr}:`);
|
|
613
|
+
const itemSchema = prop.items as Record<string, unknown>;
|
|
614
|
+
const itemLines = formatSchemaLines(itemSchema, defs, 0, seen);
|
|
615
|
+
if (itemLines.length > 0) {
|
|
616
|
+
lines.push(`${spaces(indent + 2)}- ${itemLines[0]}`);
|
|
617
|
+
for (let i = 1; i < itemLines.length; i++) {
|
|
618
|
+
lines.push(`${spaces(indent + 4)}${itemLines[i]}`);
|
|
619
|
+
}
|
|
620
|
+
} else {
|
|
621
|
+
lines.push(`${spaces(indent + 2)}- {}`);
|
|
622
|
+
}
|
|
623
|
+
} else {
|
|
624
|
+
lines.push(`${spaces(indent)}${keyStr}:`);
|
|
625
|
+
const childLines = formatSchemaLines(prop, defs, indent + 2, seen);
|
|
626
|
+
lines.push(...childLines);
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
return lines;
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
if (schema.type === "array") {
|
|
634
|
+
if (schema.items && typeof schema.items === "object") {
|
|
635
|
+
const itemSchema = schema.items as Record<string, unknown>;
|
|
636
|
+
const simple = formatType(itemSchema, defs, seen);
|
|
637
|
+
if (simple !== null) {
|
|
638
|
+
return [`${spaces(indent)}- ${simple}`];
|
|
639
|
+
}
|
|
640
|
+
const itemLines = formatSchemaLines(itemSchema, defs, 0, seen);
|
|
641
|
+
if (itemLines.length > 0) {
|
|
642
|
+
const out: string[] = [`${spaces(indent)}- ${itemLines[0]}`];
|
|
643
|
+
for (let i = 1; i < itemLines.length; i++) {
|
|
644
|
+
out.push(`${spaces(indent + 2)}${itemLines[i]}`);
|
|
645
|
+
}
|
|
646
|
+
return out;
|
|
647
|
+
}
|
|
648
|
+
return [`${spaces(indent)}- {}`];
|
|
649
|
+
}
|
|
650
|
+
return [`${spaces(indent)}array`];
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
const fallback = formatType(schema, defs, seen);
|
|
654
|
+
return fallback ? [`${spaces(indent)}${fallback}`] : [`${spaces(indent)}object`];
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
/**
|
|
658
|
+
* Converts a JSON Schema object into human-readable, agent-friendly YAML lines.
|
|
659
|
+
*/
|
|
660
|
+
export function schemaToYamlLines(
|
|
661
|
+
/** JSON Schema object to format. */
|
|
662
|
+
schema: Record<string, unknown>,
|
|
663
|
+
/** Starting indentation column in spaces (default 0). */
|
|
664
|
+
indent = 0,
|
|
665
|
+
): string[] {
|
|
666
|
+
const defs = ((schema.definitions ?? schema.$defs) as Record<string, unknown>) ?? {};
|
|
667
|
+
const lines: string[] = [];
|
|
668
|
+
if (typeof schema.description === "string" && schema.description.trim().length > 0) {
|
|
669
|
+
for (const dLine of schema.description.trim().split("\n")) {
|
|
670
|
+
lines.push(`${spaces(indent)}# ${dLine.trim()}`);
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
lines.push(...formatSchemaLines(schema, defs, indent, new Set<string>()));
|
|
674
|
+
return lines;
|
|
675
|
+
}
|
|
676
|
+
|
|
407
677
|
// ── Main Help Render ──────────────────────────────────────────────────────────
|
|
408
678
|
|
|
409
|
-
|
|
679
|
+
/**
|
|
680
|
+
* Optional rendering options for CLI help output.
|
|
681
|
+
*/
|
|
682
|
+
export interface CliHelpRenderOptions {
|
|
683
|
+
/** Override TTY detection for testing or headless environments. */
|
|
684
|
+
isTTY?: boolean;
|
|
685
|
+
/** Force schema display in TTY mode (always included by default in non-TTY). */
|
|
686
|
+
showSchema?: boolean;
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
/** Appends notes section to lines, using boxes in TTY mode and clean indentation in non-TTY mode. */
|
|
690
|
+
function appendNotesBox(
|
|
691
|
+
/** Accumulator lines for help output. */
|
|
692
|
+
lines: string[],
|
|
693
|
+
/** Raw notes text from schema. */
|
|
694
|
+
notes: string | undefined,
|
|
695
|
+
/** Program key for placeholder resolution. */
|
|
696
|
+
appKey: string,
|
|
697
|
+
/** Available terminal width. */
|
|
698
|
+
hw: number,
|
|
699
|
+
/** Whether ANSI color styling is enabled. */
|
|
700
|
+
color: boolean,
|
|
701
|
+
/** Whether output is targeting a TTY terminal. */
|
|
702
|
+
isTTY: boolean,
|
|
703
|
+
): void {
|
|
410
704
|
if ((notes ?? "").length === 0) {
|
|
411
705
|
return;
|
|
412
706
|
}
|
|
413
707
|
const resolved = cliResolveNotes(notes ?? "", appKey);
|
|
414
708
|
lines.push("");
|
|
415
|
-
|
|
709
|
+
if (isTTY) {
|
|
710
|
+
lines.push(renderTextBox("Notes", wrapText(resolved, hw - 4), hw, color).join("\n"));
|
|
711
|
+
} else {
|
|
712
|
+
lines.push(renderPlainSection("Notes", wrapText(resolved, hw - 4)).join("\n"));
|
|
713
|
+
}
|
|
416
714
|
}
|
|
417
715
|
|
|
418
716
|
/**
|
|
419
717
|
* Renders full help for the app root or a nested command, following `helpPath` from the root key.
|
|
420
|
-
*
|
|
718
|
+
* In TTY mode, renders rounded UTF-8 boxes with ANSI color.
|
|
719
|
+
* In non-TTY mode, strips boxes and borders, and renders full untruncated YAML schemas by default.
|
|
421
720
|
*/
|
|
422
|
-
export function cliHelpRender(
|
|
721
|
+
export function cliHelpRender(
|
|
722
|
+
/** Root command presentation schema. */
|
|
723
|
+
schema: CliRouter,
|
|
724
|
+
/** Segment path to the target command node. */
|
|
725
|
+
helpPath: string[],
|
|
726
|
+
/** Whether output will be directed to stderr. */
|
|
727
|
+
useStderr: boolean,
|
|
728
|
+
/** Optional rendering overrides. */
|
|
729
|
+
opts?: CliHelpRenderOptions,
|
|
730
|
+
): string {
|
|
423
731
|
const hw = getHelpWidth();
|
|
424
|
-
const
|
|
732
|
+
const isTTY = opts?.isTTY ?? isOutputTTY(useStderr);
|
|
733
|
+
const color = isTTY;
|
|
734
|
+
const showSchema = opts?.showSchema ?? !isTTY;
|
|
425
735
|
|
|
426
736
|
if (helpPath.length === 0) {
|
|
427
737
|
const lines: string[] = [];
|
|
@@ -430,25 +740,43 @@ export function cliHelpRender(schema: CliRouter, helpPath: string[], _useStderr:
|
|
|
430
740
|
lines.push(color ? style.white(schema.description) : schema.description);
|
|
431
741
|
lines.push("");
|
|
432
742
|
}
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
).join("\n"),
|
|
440
|
-
);
|
|
743
|
+
const usage = usageLines(schema.key, helpPath, (schema.commands ?? []).length > 0, false, false, color);
|
|
744
|
+
if (isTTY) {
|
|
745
|
+
lines.push(renderTextBox("Usage", usage, hw, color).join("\n"));
|
|
746
|
+
} else {
|
|
747
|
+
lines.push(renderPlainSection("Usage", usage).join("\n"));
|
|
748
|
+
}
|
|
441
749
|
|
|
442
|
-
const
|
|
750
|
+
const optRows = rowsForOptions(visibleOptions(schema.options), color);
|
|
751
|
+
const optBox = isTTY ? renderTableBox("Options", optRows, hw, color) : renderPlainTable("Options", optRows, hw);
|
|
443
752
|
if (optBox.length > 0) {
|
|
444
753
|
lines.push("");
|
|
445
754
|
lines.push(optBox.join("\n"));
|
|
446
755
|
}
|
|
447
756
|
if ((schema.commands ?? []).length > 0) {
|
|
757
|
+
const subRows = rowsForSubcommands(schema.commands ?? []);
|
|
758
|
+
const subBox = isTTY ? renderTableBox("Commands", subRows, hw, color) : renderPlainTable("Commands", subRows, hw);
|
|
448
759
|
lines.push("");
|
|
449
|
-
lines.push(
|
|
760
|
+
lines.push(subBox.join("\n"));
|
|
450
761
|
}
|
|
451
|
-
|
|
762
|
+
|
|
763
|
+
if (isCliLeaf(schema as unknown as CliNode) && showSchema) {
|
|
764
|
+
const leaf = schema as unknown as CliLeaf;
|
|
765
|
+
if (leaf.outputSchema !== undefined) {
|
|
766
|
+
const title = isJsonLeaf(leaf) ? "Output Schema (JSON)" : "Output Schema (with --json)";
|
|
767
|
+
const yamlLines = schemaToYamlLines(leaf.outputSchema, 0);
|
|
768
|
+
if (yamlLines.length > 0) {
|
|
769
|
+
lines.push("");
|
|
770
|
+
if (isTTY) {
|
|
771
|
+
lines.push(renderTextBox(title, yamlLines, hw, color).join("\n"));
|
|
772
|
+
} else {
|
|
773
|
+
lines.push(renderPlainSection(title, yamlLines).join("\n"));
|
|
774
|
+
}
|
|
775
|
+
}
|
|
776
|
+
}
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
appendNotesBox(lines, schema.notes, schema.key, hw, color, isTTY);
|
|
452
780
|
return `${lines.join("\n")}\n\n`;
|
|
453
781
|
}
|
|
454
782
|
|
|
@@ -473,41 +801,48 @@ export function cliHelpRender(schema: CliRouter, helpPath: string[], _useStderr:
|
|
|
473
801
|
lines.push("");
|
|
474
802
|
}
|
|
475
803
|
const nodeIsJsonLeaf = isCliLeaf(node) && isJsonLeaf(node);
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
isCliLeaf(node) && (node.positionals ?? []).length > 0,
|
|
484
|
-
nodeIsJsonLeaf,
|
|
485
|
-
color,
|
|
486
|
-
),
|
|
487
|
-
hw,
|
|
488
|
-
color,
|
|
489
|
-
).join("\n"),
|
|
804
|
+
const usage = usageLines(
|
|
805
|
+
schema.key,
|
|
806
|
+
helpPath,
|
|
807
|
+
isCliRouter(node) && node.commands.length > 0,
|
|
808
|
+
isCliLeaf(node) && (node.positionals ?? []).length > 0,
|
|
809
|
+
nodeIsJsonLeaf,
|
|
810
|
+
color,
|
|
490
811
|
);
|
|
812
|
+
if (isTTY) {
|
|
813
|
+
lines.push(renderTextBox("Usage", usage, hw, color).join("\n"));
|
|
814
|
+
} else {
|
|
815
|
+
lines.push(renderPlainSection("Usage", usage).join("\n"));
|
|
816
|
+
}
|
|
491
817
|
|
|
492
818
|
if (nodeIsJsonLeaf && isCliLeaf(node)) {
|
|
493
|
-
const
|
|
819
|
+
const inputRows = rowsForJsonInput(node.inputSchema);
|
|
820
|
+
const inputBox = isTTY ? renderTableBox("Input", inputRows, hw, color) : renderPlainTable("Input", inputRows, hw);
|
|
494
821
|
if (inputBox.length > 0) {
|
|
495
822
|
lines.push("");
|
|
496
823
|
lines.push(inputBox.join("\n"));
|
|
497
824
|
}
|
|
825
|
+
if (showSchema && node.inputSchema !== undefined) {
|
|
826
|
+
const yamlLines = schemaToYamlLines(node.inputSchema, 0);
|
|
827
|
+
if (yamlLines.length > 0) {
|
|
828
|
+
lines.push("");
|
|
829
|
+
if (isTTY) {
|
|
830
|
+
lines.push(renderTextBox("Input Schema", yamlLines, hw, color).join("\n"));
|
|
831
|
+
} else {
|
|
832
|
+
lines.push(renderPlainSection("Input Schema", yamlLines).join("\n"));
|
|
833
|
+
}
|
|
834
|
+
}
|
|
835
|
+
}
|
|
498
836
|
} else {
|
|
499
|
-
const
|
|
837
|
+
const optRows = rowsForOptions(visibleOptions(node.options), color);
|
|
838
|
+
const optBox = isTTY ? renderTableBox("Options", optRows, hw, color) : renderPlainTable("Options", optRows, hw);
|
|
500
839
|
if (optBox.length > 0) {
|
|
501
840
|
lines.push("");
|
|
502
841
|
lines.push(optBox.join("\n"));
|
|
503
842
|
}
|
|
504
843
|
|
|
505
|
-
const
|
|
506
|
-
|
|
507
|
-
rowsForPositionals(isCliLeaf(node) ? (node.positionals ?? []) : [], color),
|
|
508
|
-
hw,
|
|
509
|
-
color,
|
|
510
|
-
);
|
|
844
|
+
const posRows = rowsForPositionals(isCliLeaf(node) ? (node.positionals ?? []) : [], color);
|
|
845
|
+
const posBox = isTTY ? renderTableBox("Arguments", posRows, hw, color) : renderPlainTable("Arguments", posRows, hw);
|
|
511
846
|
if (posBox.length > 0) {
|
|
512
847
|
lines.push("");
|
|
513
848
|
lines.push(posBox.join("\n"));
|
|
@@ -515,14 +850,30 @@ export function cliHelpRender(schema: CliRouter, helpPath: string[], _useStderr:
|
|
|
515
850
|
}
|
|
516
851
|
|
|
517
852
|
const subcmds = isCliRouter(node) ? node.commands : [];
|
|
518
|
-
const
|
|
853
|
+
const subRows = rowsForSubcommands(subcmds);
|
|
854
|
+
const subBox = isTTY
|
|
855
|
+
? renderTableBox("Subcommands", subRows, hw, color)
|
|
856
|
+
: renderPlainTable("Subcommands", subRows, hw);
|
|
519
857
|
if (subBox.length > 0) {
|
|
520
858
|
lines.push("");
|
|
521
859
|
lines.push(subBox.join("\n"));
|
|
522
860
|
}
|
|
523
861
|
|
|
862
|
+
if (isCliLeaf(node) && node.outputSchema !== undefined && showSchema) {
|
|
863
|
+
const title = nodeIsJsonLeaf ? "Output Schema (JSON)" : "Output Schema (with --json)";
|
|
864
|
+
const yamlLines = schemaToYamlLines(node.outputSchema, 0);
|
|
865
|
+
if (yamlLines.length > 0) {
|
|
866
|
+
lines.push("");
|
|
867
|
+
if (isTTY) {
|
|
868
|
+
lines.push(renderTextBox(title, yamlLines, hw, color).join("\n"));
|
|
869
|
+
} else {
|
|
870
|
+
lines.push(renderPlainSection(title, yamlLines).join("\n"));
|
|
871
|
+
}
|
|
872
|
+
}
|
|
873
|
+
}
|
|
874
|
+
|
|
524
875
|
if ((node.notes ?? "").length > 0) {
|
|
525
|
-
appendNotesBox(lines, node.notes, schema.key, hw, color);
|
|
876
|
+
appendNotesBox(lines, node.notes, schema.key, hw, color, isTTY);
|
|
526
877
|
}
|
|
527
878
|
|
|
528
879
|
return `${lines.join("\n")}\n\n`;
|