argsbarg 1.5.0 → 2.0.1
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/.cursor/plans/cliprogram_capabilities_refactor_081e1737.plan.md +224 -0
- package/CHANGELOG.md +31 -1
- package/README.md +12 -8
- package/docs/install.md +2 -2
- package/docs/mcp.md +3 -3
- package/examples/mcp-test.ts +3 -3
- package/examples/minimal.ts +3 -3
- package/examples/nested.ts +3 -3
- package/examples/option-required.ts +3 -3
- package/index.d.ts +38 -37
- package/package.json +1 -1
- package/src/builtins/builtins.test.ts +3 -3
- package/src/builtins/completion-bash.ts +3 -3
- package/src/builtins/completion-fish.ts +2 -2
- package/src/builtins/completion-group.ts +2 -2
- package/src/builtins/completion-zsh.ts +3 -3
- package/src/builtins/dispatch.ts +41 -26
- package/src/builtins/export.ts +15 -8
- package/src/builtins/install.ts +3 -3
- package/src/builtins/mcp.ts +2 -2
- package/src/builtins/presentation.ts +34 -23
- package/src/builtins/scopes.ts +9 -8
- package/src/capabilities.ts +32 -0
- package/src/context.ts +17 -7
- package/src/help.ts +21 -9
- package/src/index.test.ts +128 -121
- package/src/index.ts +1 -1
- package/src/install/binary.ts +3 -3
- package/src/install/completions.ts +2 -2
- package/src/install/detect-installed.ts +1 -1
- package/src/install/index.ts +4 -4
- package/src/install/install.test.ts +2 -2
- package/src/install/mcp-config.ts +2 -2
- package/src/install/paths.ts +3 -3
- package/src/install/plan.ts +4 -4
- package/src/install/status.ts +2 -2
- package/src/install/uninstall.ts +2 -2
- package/src/invoke.ts +14 -5
- package/src/mcp/server.ts +3 -3
- package/src/mcp/tools.ts +16 -16
- package/src/mcp.ts +2 -2
- package/src/parse.ts +55 -27
- package/src/runtime.ts +34 -25
- package/src/schema.ts +6 -6
- package/src/skill/generate.ts +6 -6
- package/src/skill/install.ts +2 -2
- package/src/types.test.ts +40 -0
- package/src/types.ts +54 -44
- package/src/validate.ts +87 -72
package/src/runtime.ts
CHANGED
|
@@ -2,26 +2,25 @@
|
|
|
2
2
|
This module runs parsed commands, help, errors, completion, and leaf handlers.
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
+
import { resolveCapabilities } from "./capabilities.ts";
|
|
5
6
|
import { builtinInterceptRoot, dispatchBuiltin } from "./builtins/dispatch.ts";
|
|
6
7
|
import { cliPresentationRoot } from "./builtins/presentation.ts";
|
|
8
|
+
import type { CliRouter } from "./types.ts";
|
|
9
|
+
import { type CliNode, type CliProgram, isCliLeaf, isCliRouter } from "./types.ts";
|
|
7
10
|
import { isCompiledExecutable } from "./install/compiled.ts";
|
|
8
11
|
import { CliContext } from "./context.ts";
|
|
9
12
|
import { cliHelpRender } from "./help.ts";
|
|
10
13
|
import { parse, postParseValidate, ParseKind } from "./parse.ts";
|
|
11
14
|
import { cliSchemaJson } from "./schema.ts";
|
|
12
|
-
import {
|
|
13
|
-
import { cliValidateRoot } from "./validate.ts";
|
|
15
|
+
import { cliValidateProgram } from "./validate.ts";
|
|
14
16
|
|
|
15
|
-
function cliRootMergedWithBuiltins(
|
|
16
|
-
|
|
17
|
-
return root;
|
|
18
|
-
}
|
|
19
|
-
return cliPresentationRoot(root);
|
|
17
|
+
function cliRootMergedWithBuiltins(program: CliProgram): CliRouter {
|
|
18
|
+
return cliPresentationRoot(program);
|
|
20
19
|
}
|
|
21
20
|
|
|
22
|
-
export async function cliRun(
|
|
21
|
+
export async function cliRun(program: CliProgram, argv: string[] = process.argv.slice(2)): Promise<never> {
|
|
23
22
|
try {
|
|
24
|
-
|
|
23
|
+
cliValidateProgram(program);
|
|
25
24
|
} catch (err) {
|
|
26
25
|
if (err instanceof Error) {
|
|
27
26
|
process.stderr.write(err.message + "\n");
|
|
@@ -31,7 +30,9 @@ export async function cliRun(root: CliCommand, argv: string[] = process.argv.sli
|
|
|
31
30
|
process.exit(1);
|
|
32
31
|
}
|
|
33
32
|
|
|
34
|
-
|
|
33
|
+
const caps = resolveCapabilities(program);
|
|
34
|
+
|
|
35
|
+
if (argv.length >= 1 && argv[0] === "mcp" && !caps.mcp) {
|
|
35
36
|
process.stderr.write("MCP is not enabled. Set mcpServer on the program root.\n");
|
|
36
37
|
process.exit(1);
|
|
37
38
|
}
|
|
@@ -41,31 +42,35 @@ export async function cliRun(root: CliCommand, argv: string[] = process.argv.sli
|
|
|
41
42
|
process.exit(1);
|
|
42
43
|
}
|
|
43
44
|
|
|
44
|
-
let parseRoot:
|
|
45
|
+
let parseRoot: CliNode;
|
|
46
|
+
let completionParseRoot: CliRouter = cliRootMergedWithBuiltins(program);
|
|
45
47
|
let isLeafCompletionIntercept = false;
|
|
46
48
|
|
|
47
|
-
if (
|
|
48
|
-
const intercept = builtinInterceptRoot(
|
|
49
|
-
if (intercept.isLeafCompletionIntercept || intercept.parseRoot !==
|
|
49
|
+
if (isCliLeaf(program)) {
|
|
50
|
+
const intercept = builtinInterceptRoot(program, argv);
|
|
51
|
+
if (intercept.isLeafCompletionIntercept || intercept.parseRoot !== program) {
|
|
50
52
|
parseRoot = intercept.parseRoot;
|
|
53
|
+
completionParseRoot = isCliRouter(intercept.parseRoot)
|
|
54
|
+
? intercept.parseRoot
|
|
55
|
+
: cliRootMergedWithBuiltins(program);
|
|
51
56
|
isLeafCompletionIntercept = intercept.isLeafCompletionIntercept;
|
|
52
57
|
} else {
|
|
53
|
-
parseRoot =
|
|
58
|
+
parseRoot = program;
|
|
54
59
|
}
|
|
55
60
|
} else {
|
|
56
|
-
parseRoot = cliRootMergedWithBuiltins(
|
|
61
|
+
parseRoot = cliRootMergedWithBuiltins(program);
|
|
57
62
|
}
|
|
58
63
|
|
|
59
64
|
let pr = parse(parseRoot, argv);
|
|
60
65
|
pr = postParseValidate(parseRoot, pr);
|
|
61
66
|
|
|
62
67
|
if (pr.kind === ParseKind.Help) {
|
|
63
|
-
process.stdout.write(cliHelpRender(cliPresentationRoot(
|
|
68
|
+
process.stdout.write(cliHelpRender(cliPresentationRoot(program), pr.helpPath, false));
|
|
64
69
|
process.exit(pr.helpExplicit ? 0 : 1);
|
|
65
70
|
}
|
|
66
71
|
|
|
67
72
|
if (pr.kind === ParseKind.Schema) {
|
|
68
|
-
process.stdout.write(cliSchemaJson(
|
|
73
|
+
process.stdout.write(cliSchemaJson(program));
|
|
69
74
|
process.exit(0);
|
|
70
75
|
}
|
|
71
76
|
|
|
@@ -73,17 +78,21 @@ export async function cliRun(root: CliCommand, argv: string[] = process.argv.sli
|
|
|
73
78
|
const color = process.stderr.isTTY;
|
|
74
79
|
const msg = color ? `\u001B[31m${pr.errorMsg}\u001B[0m` : pr.errorMsg;
|
|
75
80
|
process.stderr.write(msg + "\n");
|
|
76
|
-
process.stderr.write(cliHelpRender(cliPresentationRoot(
|
|
81
|
+
process.stderr.write(cliHelpRender(cliPresentationRoot(program), pr.errorHelpPath, true));
|
|
77
82
|
process.exit(1);
|
|
78
83
|
}
|
|
79
84
|
|
|
80
85
|
if (pr.kind === ParseKind.Ok) {
|
|
81
|
-
await dispatchBuiltin(
|
|
86
|
+
await dispatchBuiltin(program, pr, { isLeafCompletionIntercept, parseRoot: completionParseRoot });
|
|
82
87
|
}
|
|
83
88
|
|
|
84
|
-
let current = parseRoot;
|
|
89
|
+
let current: CliNode = parseRoot;
|
|
85
90
|
for (const seg of pr.path) {
|
|
86
|
-
|
|
91
|
+
if (!isCliRouter(current)) {
|
|
92
|
+
process.stderr.write("Internal error: missing handler for path.\n");
|
|
93
|
+
process.exit(1);
|
|
94
|
+
}
|
|
95
|
+
const ch = current.commands.find((candidate) => candidate.key === seg);
|
|
87
96
|
if (!ch) {
|
|
88
97
|
process.stderr.write("Internal error: missing handler for path.\n");
|
|
89
98
|
process.exit(1);
|
|
@@ -91,12 +100,12 @@ export async function cliRun(root: CliCommand, argv: string[] = process.argv.sli
|
|
|
91
100
|
current = ch;
|
|
92
101
|
}
|
|
93
102
|
|
|
94
|
-
if (!current.handler) {
|
|
103
|
+
if (!isCliLeaf(current) || !current.handler) {
|
|
95
104
|
process.stderr.write("Internal error: missing handler for path.\n");
|
|
96
105
|
process.exit(1);
|
|
97
106
|
}
|
|
98
107
|
|
|
99
|
-
const ctx = new CliContext(
|
|
108
|
+
const ctx = new CliContext(program.key, pr.path, pr.args, pr.opts, program, "cli");
|
|
100
109
|
try {
|
|
101
110
|
await Promise.resolve(current.handler(ctx));
|
|
102
111
|
process.exit(0);
|
|
@@ -112,6 +121,6 @@ export function cliErrWithHelp(ctx: CliContext, msg: string): never {
|
|
|
112
121
|
const color = process.stderr.isTTY;
|
|
113
122
|
const line = color ? `\u001B[31m${msg}\u001B[0m` : msg;
|
|
114
123
|
process.stderr.write(line + "\n");
|
|
115
|
-
process.stderr.write(cliHelpRender(cliPresentationRoot(ctx.
|
|
124
|
+
process.stderr.write(cliHelpRender(cliPresentationRoot(ctx.program), ctx.commandPath, true));
|
|
116
125
|
process.exit(1);
|
|
117
126
|
}
|
package/src/schema.ts
CHANGED
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
This module serializes the CLI schema tree to JSON for machine-readable introspection.
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import {
|
|
5
|
+
import { type CliNode, type CliProgram, isCliLeaf, isCliRouter } from "./types.ts";
|
|
6
6
|
import { exportPresentationBuiltins, type CliSchemaExport } from "./builtins/export.ts";
|
|
7
7
|
|
|
8
8
|
const RESERVED = new Set(["completion", "install", "mcp"]);
|
|
9
9
|
|
|
10
|
-
function exportCommand(cmd:
|
|
10
|
+
function exportCommand(cmd: CliNode): CliSchemaExport {
|
|
11
11
|
const out: CliSchemaExport = {
|
|
12
12
|
key: cmd.key,
|
|
13
13
|
description: cmd.description,
|
|
@@ -21,11 +21,11 @@ function exportCommand(cmd: CliCommand): CliSchemaExport {
|
|
|
21
21
|
out.options = cmd.options;
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
if (
|
|
24
|
+
if (isCliLeaf(cmd)) {
|
|
25
25
|
if ((cmd.positionals ?? []).length > 0) {
|
|
26
26
|
out.positionals = cmd.positionals;
|
|
27
27
|
}
|
|
28
|
-
out.commands = exportPresentationBuiltins(cmd);
|
|
28
|
+
out.commands = exportPresentationBuiltins(cmd as CliProgram);
|
|
29
29
|
return out;
|
|
30
30
|
}
|
|
31
31
|
|
|
@@ -36,7 +36,7 @@ function exportCommand(cmd: CliCommand): CliSchemaExport {
|
|
|
36
36
|
out.fallbackMode = cmd.fallbackMode;
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
-
const children = (cmd
|
|
39
|
+
const children = isCliRouter(cmd) ? cmd.commands.filter((ch) => !RESERVED.has(ch.key)) : [];
|
|
40
40
|
if (children.length > 0) {
|
|
41
41
|
out.commands = children.map(exportCommand);
|
|
42
42
|
}
|
|
@@ -44,7 +44,7 @@ function exportCommand(cmd: CliCommand): CliSchemaExport {
|
|
|
44
44
|
return out;
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
-
export function cliSchemaJson(root:
|
|
47
|
+
export function cliSchemaJson(root: CliProgram): string {
|
|
48
48
|
return JSON.stringify(exportCommand(root), null, 2) + "\n";
|
|
49
49
|
}
|
|
50
50
|
|
package/src/skill/generate.ts
CHANGED
|
@@ -5,7 +5,7 @@ This module generates Agent Skills content (SKILL.md + reference.md) from a CLI
|
|
|
5
5
|
import { collectOptionDefs } from "../parse.ts";
|
|
6
6
|
import { cliSchemaJson } from "../schema.ts";
|
|
7
7
|
import { collectMcpTools, sanitizeToolSegment } from "../mcp/tools.ts";
|
|
8
|
-
import {
|
|
8
|
+
import { CliProgram, CliOptionKind } from "../types.ts";
|
|
9
9
|
|
|
10
10
|
export type SkillTarget = "cursor" | "claude";
|
|
11
11
|
|
|
@@ -22,7 +22,7 @@ function truncate(text: string, maxLen: number): string {
|
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
/** Builds third-person skill description for YAML frontmatter. */
|
|
25
|
-
function skillDescription(root:
|
|
25
|
+
function skillDescription(root: CliProgram): string {
|
|
26
26
|
const tools = collectMcpTools(root);
|
|
27
27
|
const paths = tools.map((t) => (t.path.length > 0 ? t.path.join(" ") : root.key));
|
|
28
28
|
const sample = paths.slice(0, 5).join(", ");
|
|
@@ -32,7 +32,7 @@ function skillDescription(root: CliCommand): string {
|
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
/** Formats one command line for the catalog section. */
|
|
35
|
-
function formatCommandEntry(root:
|
|
35
|
+
function formatCommandEntry(root: CliProgram, tool: ReturnType<typeof collectMcpTools>[number]): string {
|
|
36
36
|
const cliPath = tool.path.length > 0 ? `${root.key} ${tool.path.join(" ")}` : root.key;
|
|
37
37
|
let line = `- **\`${cliPath}\`** — ${tool.description}`;
|
|
38
38
|
const opts = collectOptionDefs(root, tool.path);
|
|
@@ -52,7 +52,7 @@ function formatCommandEntry(root: CliCommand, tool: ReturnType<typeof collectMcp
|
|
|
52
52
|
}
|
|
53
53
|
|
|
54
54
|
/** Builds SKILL.md body for the given target. */
|
|
55
|
-
function buildSkillMd(root:
|
|
55
|
+
function buildSkillMd(root: CliProgram, target: SkillTarget, dirName: string): string {
|
|
56
56
|
const name = sanitizeToolSegment(root.key);
|
|
57
57
|
const description = skillDescription(root);
|
|
58
58
|
const tools = collectMcpTools(root);
|
|
@@ -159,7 +159,7 @@ function buildSkillMd(root: CliCommand, target: SkillTarget, dirName: string): s
|
|
|
159
159
|
}
|
|
160
160
|
|
|
161
161
|
/** Builds reference.md with pretty-printed schema JSON. */
|
|
162
|
-
function buildReferenceMd(root:
|
|
162
|
+
function buildReferenceMd(root: CliProgram): string {
|
|
163
163
|
return [
|
|
164
164
|
`# ${root.key} — CLI reference`,
|
|
165
165
|
"",
|
|
@@ -173,7 +173,7 @@ function buildReferenceMd(root: CliCommand): string {
|
|
|
173
173
|
}
|
|
174
174
|
|
|
175
175
|
/** Generates SKILL.md and reference.md for Cursor or Claude Code. */
|
|
176
|
-
export function generateSkillBundle(root:
|
|
176
|
+
export function generateSkillBundle(root: CliProgram, target: SkillTarget): SkillBundle {
|
|
177
177
|
const dirName = sanitizeToolSegment(root.key);
|
|
178
178
|
return {
|
|
179
179
|
dirName,
|
package/src/skill/install.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { existsSync, mkdirSync, rmSync, writeFileSync } from "node:fs";
|
|
2
2
|
import { homedir } from "node:os";
|
|
3
3
|
import { join } from "node:path";
|
|
4
|
-
import {
|
|
4
|
+
import { CliProgram } from "../types.ts";
|
|
5
5
|
import { generateSkillBundle, type SkillTarget } from "./generate.ts";
|
|
6
6
|
|
|
7
7
|
export interface SkillInstallOpts {
|
|
@@ -24,7 +24,7 @@ function resolveSkillDir(target: SkillTarget, dirName: string, global: boolean):
|
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
/** Writes SKILL.md and reference.md; returns changed file paths. */
|
|
27
|
-
export function cliSkillInstall(root:
|
|
27
|
+
export function cliSkillInstall(root: CliProgram, target: SkillTarget, opts: SkillInstallOpts): string[] {
|
|
28
28
|
const bundle = generateSkillBundle(root, target);
|
|
29
29
|
const dir = resolveSkillDir(target, bundle.dirName, opts.global ?? false);
|
|
30
30
|
const changed: string[] = [];
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Compile-only checks that invalid schema shapes fail type-checking.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import type { CliLeaf, CliNode, CliProgram, CliRouter } from "./types.ts";
|
|
6
|
+
|
|
7
|
+
const _routerOnly: CliRouter = {
|
|
8
|
+
key: "app",
|
|
9
|
+
description: "",
|
|
10
|
+
commands: [],
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
const _leafOnly: CliLeaf = {
|
|
14
|
+
key: "run",
|
|
15
|
+
description: "",
|
|
16
|
+
handler: () => {},
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
const _program: CliProgram = {
|
|
20
|
+
key: "app",
|
|
21
|
+
description: "",
|
|
22
|
+
mcpServer: {},
|
|
23
|
+
commands: [],
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
const _badMcpOnNode = {
|
|
27
|
+
key: "x",
|
|
28
|
+
description: "",
|
|
29
|
+
// @ts-expect-error mcpServer is program-root only
|
|
30
|
+
mcpServer: {},
|
|
31
|
+
commands: [],
|
|
32
|
+
} satisfies CliNode;
|
|
33
|
+
|
|
34
|
+
const _badInstallOnNode = {
|
|
35
|
+
key: "x",
|
|
36
|
+
description: "",
|
|
37
|
+
// @ts-expect-error install is program-root only
|
|
38
|
+
install: { enabled: false },
|
|
39
|
+
handler: () => {},
|
|
40
|
+
} satisfies CliNode;
|
package/src/types.ts
CHANGED
|
@@ -2,8 +2,6 @@
|
|
|
2
2
|
This module defines the CLI schema, option kinds, and fallback modes.
|
|
3
3
|
It is the shared declarative model that parsing, validation, help, and completion all
|
|
4
4
|
read from, so the package has one source of truth.
|
|
5
|
-
|
|
6
|
-
It gives the package one shared model for both library users and internal modules.
|
|
7
5
|
*/
|
|
8
6
|
|
|
9
7
|
import type { CliContext } from "./context.ts";
|
|
@@ -47,7 +45,7 @@ export enum CliFallbackMode {
|
|
|
47
45
|
}
|
|
48
46
|
|
|
49
47
|
/**
|
|
50
|
-
* A named flag or value option (`--long`, `-short`), listed on `
|
|
48
|
+
* A named flag or value option (`--long`, `-short`), listed on command `options`.
|
|
51
49
|
*/
|
|
52
50
|
export interface CliOption {
|
|
53
51
|
/** Option name (e.g., "name", "verbose"). */
|
|
@@ -68,7 +66,7 @@ export interface CliOption {
|
|
|
68
66
|
}
|
|
69
67
|
|
|
70
68
|
/**
|
|
71
|
-
* An ordered positional argument slot, listed on `
|
|
69
|
+
* An ordered positional argument slot, listed on leaf `positionals`.
|
|
72
70
|
*/
|
|
73
71
|
export interface CliPositional {
|
|
74
72
|
/** Positional name (used in help and error messages). */
|
|
@@ -90,7 +88,7 @@ export interface CliPositional {
|
|
|
90
88
|
}
|
|
91
89
|
|
|
92
90
|
/**
|
|
93
|
-
*
|
|
91
|
+
* Enables `myapp mcp` and MCP stdio server metadata (program root only).
|
|
94
92
|
*/
|
|
95
93
|
export interface CliMcpServerConfig {
|
|
96
94
|
/** `initialize` serverInfo.name (default: root `key`). */
|
|
@@ -154,7 +152,7 @@ export interface CliMcpToolConfig {
|
|
|
154
152
|
}
|
|
155
153
|
|
|
156
154
|
/**
|
|
157
|
-
*
|
|
155
|
+
* Opt-out and defaults for the `install` built-in (compiled binaries only; program root only).
|
|
158
156
|
*/
|
|
159
157
|
export interface CliInstallConfig {
|
|
160
158
|
/** When `false`, hide/disable `install` (default: enabled). */
|
|
@@ -164,9 +162,9 @@ export interface CliInstallConfig {
|
|
|
164
162
|
}
|
|
165
163
|
|
|
166
164
|
/**
|
|
167
|
-
* Base properties shared by all command
|
|
165
|
+
* Base properties shared by all nodes in the user command tree.
|
|
168
166
|
*/
|
|
169
|
-
export interface
|
|
167
|
+
export interface CliNodeBase {
|
|
170
168
|
/** Program or command key (e.g., "myapp", "stat", "owner"). */
|
|
171
169
|
key: string;
|
|
172
170
|
/** Short description shown in help. */
|
|
@@ -175,45 +173,57 @@ export interface CliCommandBase {
|
|
|
175
173
|
notes?: string;
|
|
176
174
|
/** Global or command-level flags/options. */
|
|
177
175
|
options?: CliOption[];
|
|
178
|
-
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* A leaf command node with a handler and optional positionals.
|
|
180
|
+
*/
|
|
181
|
+
export type CliLeaf = CliNodeBase & {
|
|
182
|
+
/** Handler function for leaf commands. */
|
|
183
|
+
handler: CliHandler;
|
|
184
|
+
/** Positional argument definitions. */
|
|
185
|
+
positionals?: CliPositional[];
|
|
186
|
+
/** Per-tool MCP exposure and metadata. */
|
|
187
|
+
mcpTool?: CliMcpToolConfig;
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* A routing command node with nested subcommands.
|
|
192
|
+
*/
|
|
193
|
+
export type CliRouter = CliNodeBase & {
|
|
194
|
+
/** Nested subcommands. */
|
|
195
|
+
commands: CliNode[];
|
|
196
|
+
/** Default subcommand when argv omits a command or uses an unknown token at this routing node. */
|
|
197
|
+
fallbackCommand?: string;
|
|
198
|
+
/** How fallbackCommand is applied at this routing node. */
|
|
199
|
+
fallbackMode?: CliFallbackMode;
|
|
200
|
+
};
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* A node in the user-defined command tree (router or leaf).
|
|
204
|
+
*/
|
|
205
|
+
export type CliNode = CliLeaf | CliRouter;
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Program root passed to `cliRun` / `cliInvoke`.
|
|
209
|
+
* May be a leaf or router, plus optional program-level MCP and install config.
|
|
210
|
+
*/
|
|
211
|
+
export type CliProgram = CliNode & {
|
|
212
|
+
/** When set, enables the `mcp` built-in subcommand. */
|
|
179
213
|
mcpServer?: CliMcpServerConfig;
|
|
180
|
-
/**
|
|
214
|
+
/** Opt-out and defaults for `install` (compiled binaries only). */
|
|
181
215
|
install?: CliInstallConfig;
|
|
182
|
-
|
|
183
|
-
|
|
216
|
+
};
|
|
217
|
+
|
|
218
|
+
/** True when the node is a leaf (has a handler). */
|
|
219
|
+
export function isCliLeaf(node: CliNode): node is CliLeaf {
|
|
220
|
+
return "handler" in node && typeof node.handler === "function";
|
|
184
221
|
}
|
|
185
222
|
|
|
186
|
-
/**
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
* The root may be a routing group or a leaf command.
|
|
191
|
-
*/
|
|
192
|
-
export type CliCommand =
|
|
193
|
-
| (CliCommandBase & {
|
|
194
|
-
/** Handler function for leaf commands. */
|
|
195
|
-
handler: CliHandler;
|
|
196
|
-
/** Positional argument definitions. */
|
|
197
|
-
positionals?: CliPositional[];
|
|
198
|
-
/** Nested subcommands (empty for leaf commands). */
|
|
199
|
-
commands?: never;
|
|
200
|
-
/** Default subcommand (routing commands only). */
|
|
201
|
-
fallbackCommand?: never;
|
|
202
|
-
/** How fallbackCommand is applied at this routing node (routing commands only). */
|
|
203
|
-
fallbackMode?: never;
|
|
204
|
-
})
|
|
205
|
-
| (CliCommandBase & {
|
|
206
|
-
/** Nested subcommands. */
|
|
207
|
-
commands: CliCommand[];
|
|
208
|
-
/** Default subcommand when argv omits a command or uses an unknown token at this routing node. */
|
|
209
|
-
fallbackCommand?: string;
|
|
210
|
-
/** How fallbackCommand is applied at this routing node (not root-only). */
|
|
211
|
-
fallbackMode?: CliFallbackMode;
|
|
212
|
-
/** Handler function (leaf commands only). */
|
|
213
|
-
handler?: never;
|
|
214
|
-
/** Positional argument definitions (leaf commands only). */
|
|
215
|
-
positionals?: never;
|
|
216
|
-
});
|
|
223
|
+
/** True when the node is a router (has subcommands). */
|
|
224
|
+
export function isCliRouter(node: CliNode): node is CliRouter {
|
|
225
|
+
return "commands" in node && Array.isArray(node.commands);
|
|
226
|
+
}
|
|
217
227
|
|
|
218
228
|
/**
|
|
219
229
|
* Handler closure type for leaf commands.
|
|
@@ -222,7 +232,7 @@ export type CliCommand =
|
|
|
222
232
|
export type CliHandler = (ctx: CliContext) => void | Promise<void>;
|
|
223
233
|
|
|
224
234
|
/**
|
|
225
|
-
* Error thrown when the static
|
|
235
|
+
* Error thrown when the static CLI tree violates ArgsBarg rules.
|
|
226
236
|
*/
|
|
227
237
|
export class CliSchemaValidationError extends Error {
|
|
228
238
|
/** Creates a schema validation error with a human-readable rule violation. */
|