argsbarg 6.1.2 → 6.1.3
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 +65 -1
- package/README.md +17 -19
- package/bin/argsbarg +10 -0
- package/docs/README.md +4 -3
- package/docs/ai-skills.md +4 -2
- package/docs/bundled-docs.md +50 -25
- package/docs/cli-program.md +52 -10
- package/docs/config-schema.md +10 -11
- package/docs/configure.md +2 -0
- package/docs/decisions.md +40 -0
- package/docs/developing.md +43 -5
- package/docs/http-server.md +171 -0
- package/docs/json-schema-subset.md +51 -0
- package/docs/mcp.md +4 -2
- package/docs/output-schema.md +55 -62
- package/examples/formats.ts +6 -6
- package/examples/full-example/Formula/full-example.rb +35 -0
- package/examples/full-example/README.md +20 -21
- package/examples/full-example/docs/README.md +1 -1
- package/examples/full-example/docs/cli-schema.json +1790 -98
- package/examples/full-example/docs/cli.md +1990 -0
- package/examples/full-example/docs/http.md +28 -29
- package/examples/full-example/docs/mcp.md +8 -22
- package/examples/full-example/docs/openapi.json +783 -50
- package/examples/full-example/docs/skill.md +10 -10
- package/examples/full-example/justfile +11 -1
- package/examples/full-example/src/commands/render-json/__generated__/RenderJsonInputSchema.json +15 -0
- package/examples/full-example/src/commands/render-json/__generated__/index.ts +5 -0
- package/examples/full-example/src/commands/render-json/command.test.ts +46 -0
- package/examples/full-example/src/commands/render-json/command.ts +30 -0
- package/examples/full-example/src/commands/render-json/types.ts +9 -0
- package/examples/full-example/src/commands/status/__generated__/StatusJsonOutputSchema.json +15 -0
- package/examples/full-example/src/commands/status/__generated__/index.ts +2 -2
- package/examples/full-example/src/commands/status/command.ts +5 -13
- package/examples/full-example/src/commands/status/types.ts +1 -14
- package/examples/full-example/src/commands/workspaces/__generated__/WorkspaceNameInputSchema.json +15 -0
- package/examples/full-example/src/commands/workspaces/__generated__/index.ts +5 -0
- package/examples/full-example/src/commands/workspaces/command.test.ts +58 -0
- package/examples/full-example/src/commands/workspaces/command.ts +94 -0
- package/examples/full-example/src/commands/workspaces/types.ts +6 -0
- package/examples/full-example/src/db/index.test.ts +86 -0
- package/examples/full-example/src/db/index.ts +101 -0
- package/examples/full-example/src/db/migrate.test.ts +35 -0
- package/examples/full-example/src/db/migrate.ts +69 -0
- package/examples/full-example/src/db/migrations/001_workspaces.sql +6 -0
- package/examples/full-example/src/db/tables/workspaces.ts +66 -0
- package/examples/full-example/src/program.ts +11 -36
- package/examples/full-example/src/types/argsbarg.d.ts +11 -0
- package/examples/full-example/src/types/md.d.ts +4 -0
- package/examples/full-example/tsconfig.json +5 -2
- package/examples/mcp-test.ts +1 -2
- package/examples/minimal.ts +1 -7
- package/examples/nested.ts +1 -2
- package/examples/option-required.ts +1 -1
- package/examples/servers.ts +4 -5
- package/index.d.ts +431 -136
- package/package.json +19 -2
- package/src/builtins/builtins.test.ts +7 -7
- package/src/builtins/completion-bash.ts +1 -1
- package/src/builtins/completion-fish.ts +1 -1
- package/src/builtins/completion-group.ts +4 -4
- package/src/builtins/completion-simulate-shared.ts +9 -0
- package/src/builtins/completion-zsh.ts +1 -1
- package/src/builtins/config.test.ts +3 -3
- package/src/builtins/config.ts +9 -9
- package/src/builtins/configure-copy.ts +2 -2
- package/src/builtins/configure.ts +4 -4
- package/src/builtins/dispatch.ts +19 -18
- package/src/builtins/export.ts +7 -5
- package/src/builtins/http.ts +68 -0
- package/src/builtins/mcp.ts +28 -4
- package/src/builtins/presentation.ts +6 -6
- package/src/builtins/registry.ts +6 -6
- package/src/builtins/scopes.ts +2 -2
- package/src/builtins/version.ts +1 -1
- package/src/cli-tool/full-example-capabilities.test.ts +10 -15
- package/src/cli-tool/main.ts +1 -1
- package/src/cli-tool/program.ts +3 -2
- package/src/cli-tool/prompt.ts +1 -1
- package/src/cli-tool/run-schemagen.ts +1 -3
- package/src/cli-tool/schemagen/cleanup.ts +6 -7
- package/src/cli-tool/schemagen/discover-schema-roots.ts +66 -120
- package/src/cli-tool/schemagen/index.ts +2 -2
- package/src/cli-tool/schemagen/names.ts +8 -13
- package/src/cli-tool/schemagen/run.ts +21 -28
- package/src/cli-tool/schemagen/schemagen.test.ts +136 -46
- package/src/config/bindings.test.ts +1 -1
- package/src/config/bindings.ts +1 -1
- package/src/config/bootstrap.test.ts +1 -1
- package/src/config/bootstrap.ts +36 -4
- package/src/config/context.test.ts +1 -1
- package/src/config/context.ts +1 -1
- package/src/config/entry.ts +1 -1
- package/src/config/file.test.ts +1 -1
- package/src/config/file.ts +3 -3
- package/src/config/manifest.ts +1 -1
- package/src/config/resolve.test.ts +1 -1
- package/src/config/resolve.ts +1 -1
- package/src/config/schema.ts +1 -1
- package/src/config/validate.ts +1 -1
- package/src/{install → configure/artifacts}/binary-placement.test.ts +1 -1
- package/src/{install → configure/artifacts}/binary-placement.ts +1 -1
- package/src/{install → configure/artifacts}/gh-release-update.ts +1 -1
- package/src/{install → configure/artifacts}/install-validate.test.ts +3 -3
- package/src/{install → configure/artifacts}/mcp-config.ts +1 -1
- package/src/{install → configure/artifacts}/mcp-opencode.test.ts +1 -1
- package/src/{install → configure/artifacts}/mcp-opencode.ts +1 -1
- package/src/{install → configure/artifacts}/paths.ts +5 -5
- package/src/configure/artifacts/plan.ts +24 -0
- package/src/{install → configure/artifacts}/status.test.ts +1 -1
- package/src/{install → configure/artifacts}/status.ts +2 -2
- package/src/{install → configure/artifacts}/target-base.ts +1 -1
- package/src/{install → configure/artifacts}/target-detect.ts +1 -1
- package/src/{install → configure/artifacts}/target-effective.ts +3 -9
- package/src/{install → configure/artifacts}/target-mcp-cli.ts +1 -1
- package/src/{install → configure/artifacts}/target-mcp-json.ts +1 -1
- package/src/{install → configure/artifacts}/target-plan-build.ts +2 -2
- package/src/{install → configure/artifacts}/target-registry.ts +2 -2
- package/src/{install → configure/artifacts}/target-scope.ts +3 -3
- package/src/{install → configure/artifacts}/target-skill.ts +1 -1
- package/src/{install → configure/artifacts}/target-types.ts +2 -2
- package/src/{install → configure/artifacts}/targets/app.ts +5 -5
- package/src/{install → configure/artifacts}/targets/chatgpt-mcp.ts +2 -2
- package/src/{install → configure/artifacts}/targets/claude-code-mcp.ts +2 -2
- package/src/{install → configure/artifacts}/targets/claude-desktop-mcp.ts +2 -2
- package/src/{install → configure/artifacts}/targets/claude-skill.ts +2 -2
- package/src/{install → configure/artifacts}/targets/codex-mcp.ts +2 -2
- package/src/{install → configure/artifacts}/targets/codex-skill.ts +2 -2
- package/src/{install → configure/artifacts}/targets/configure.ts +5 -5
- package/src/{install → configure/artifacts}/targets/cursor-mcp.ts +2 -2
- package/src/{install → configure/artifacts}/targets/cursor-skill.ts +2 -2
- package/src/{install → configure/artifacts}/targets/index.ts +1 -1
- package/src/{install → configure/artifacts}/targets/openclaw-mcp.ts +2 -2
- package/src/{install → configure/artifacts}/targets/openclaw-skill.ts +3 -3
- package/src/{install → configure/artifacts}/targets/opencode-mcp.ts +5 -5
- package/src/{install → configure/artifacts}/targets/opencode-skill.ts +3 -3
- package/src/{install → configure/artifacts}/targets.test.ts +1 -1
- package/src/{install → configure/artifacts}/uninstall.ts +1 -1
- package/src/configure/configure.test.ts +11 -11
- package/src/configure/index.ts +14 -14
- package/src/configure/prompt.ts +2 -2
- package/src/{context.ts → core/context.ts} +26 -20
- package/src/{json-leaf.test.ts → core/json-leaf.test.ts} +4 -4
- package/src/{leaf-inputs.test.ts → core/leaf-inputs.test.ts} +7 -7
- package/src/{leaf-inputs.ts → core/leaf-inputs.ts} +16 -12
- package/src/{parse.test.ts → core/parse.test.ts} +97 -109
- package/src/{parse.ts → core/parse.ts} +129 -31
- package/src/{schema.ts → core/schema.ts} +25 -13
- package/src/{types.ts → core/types.ts} +225 -35
- package/src/{validate.ts → core/validate.ts} +39 -29
- package/src/docs/builtin.ts +8 -19
- package/src/docs/{api-guide.test.ts → cli-guide.test.ts} +21 -21
- package/src/docs/{api-guide.ts → cli-guide.ts} +45 -16
- package/src/docs/docs.test.ts +76 -41
- package/src/docs/http-guide.ts +37 -34
- package/src/docs/mcp-guide.ts +12 -14
- package/src/docs/mcp-resources.test.ts +2 -3
- package/src/docs/mcp-resources.ts +6 -11
- package/src/docs/resolve.ts +22 -30
- package/src/docs/save.ts +3 -3
- package/src/exports/cli.ts +47 -0
- package/src/exports/headless.ts +13 -0
- package/src/exports/http.ts +6 -0
- package/src/exports/mcp.ts +6 -0
- package/src/{headless.test.ts → headless/routing.test.ts} +3 -3
- package/src/{headless.ts → headless/routing.ts} +3 -3
- package/src/headless/tool-call.ts +114 -46
- package/src/help.test.ts +152 -0
- package/src/help.ts +3 -3
- package/src/hooks/builtin.ts +20 -0
- package/src/hooks/run.ts +142 -0
- package/src/http/openapi.ts +182 -0
- package/src/http/readiness.ts +78 -0
- package/src/{api → http}/result.ts +16 -5
- package/src/http/routes.ts +329 -0
- package/src/http/server.ts +225 -0
- package/src/index.ts +36 -25
- package/src/log/ecs.test.ts +43 -0
- package/src/log/ecs.ts +59 -0
- package/src/log/emitter.ts +166 -0
- package/src/mcp/bundle.ts +2 -2
- package/src/mcp/claude.test.ts +1 -1
- package/src/mcp/claude.ts +4 -4
- package/src/{hidden-mcpb.test.ts → mcp/hidden-mcpb.test.ts} +10 -9
- package/src/mcp/result.ts +2 -2
- package/src/mcp/server.ts +54 -6
- package/src/mcp/tools.ts +9 -20
- package/src/{capabilities.ts → runtime/capabilities.ts} +11 -11
- package/src/{cli-errors.ts → runtime/cli-errors.ts} +4 -4
- package/src/{cli.ts → runtime/cli.ts} +159 -49
- package/src/runtime/exposure.ts +102 -0
- package/src/{invoke.test.ts → runtime/invoke.test.ts} +31 -7
- package/src/server/context.ts +25 -0
- package/src/server/overrides.ts +112 -0
- package/src/skill/generate.ts +8 -8
- package/src/skill/hint.ts +1 -1
- package/src/skill/install.ts +2 -2
- package/src/skill/naming.ts +1 -1
- package/src/{test-fixtures.ts → test/fixtures.ts} +3 -2
- package/src/{config.integration.test.ts → test/integration/config.test.ts} +8 -8
- package/src/{api.integration.test.ts → test/integration/http.test.ts} +170 -67
- package/src/{mcp.integration.test.ts → test/integration/mcp.test.ts} +11 -57
- package/docs/api-server.md +0 -141
- package/examples/full-example/docs/api.md +0 -511
- package/examples/full-example/src/commands/status/__generated__/outputSchema.json +0 -28
- package/examples/full-example/src/config/__generated__/configSchema.json +0 -40
- package/examples/full-example/src/config/__generated__/index.ts +0 -5
- package/examples/full-example/src/config/types.ts +0 -24
- package/src/api/openapi.ts +0 -117
- package/src/api/server.ts +0 -120
- package/src/builtins/api.ts +0 -38
- package/src/hidden.ts +0 -30
- package/src/install/plan.ts +0 -53
- /package/src/{install → configure/artifacts}/detect-installed.ts +0 -0
- /package/src/{install → configure/artifacts}/gh-release-update.test.ts +0 -0
- /package/src/{install → configure/artifacts}/mcp-codex.test.ts +0 -0
- /package/src/{install → configure/artifacts}/mcp-codex.ts +0 -0
- /package/src/{install → configure/artifacts}/mcp-openclaw.test.ts +0 -0
- /package/src/{install → configure/artifacts}/mcp-openclaw.ts +0 -0
- /package/src/{install → configure/artifacts}/normalize-uninstall.ts +0 -0
- /package/src/{install → configure/artifacts}/normalize.ts +0 -0
- /package/src/{install → configure/artifacts}/opts.ts +0 -0
- /package/src/{install → configure/artifacts}/shell.ts +0 -0
- /package/src/{formats.test.ts → core/formats.test.ts} +0 -0
- /package/src/{formats.ts → core/formats.ts} +0 -0
- /package/src/{respond.ts → core/respond.ts} +0 -0
- /package/src/{types.test.ts → core/types.test.ts} +0 -0
- /package/src/{api → http}/schema-deref.test.ts +0 -0
- /package/src/{api → http}/schema-deref.ts +0 -0
|
@@ -7,23 +7,23 @@ import { existsSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "no
|
|
|
7
7
|
import { tmpdir } from "node:os";
|
|
8
8
|
import { join } from "node:path";
|
|
9
9
|
import { $ } from "bun";
|
|
10
|
-
import { completionBashScript, completionZshScript } from "
|
|
11
|
-
import { cliPresentationRoot } from "
|
|
12
|
-
import { cliHelpRender } from "
|
|
13
|
-
import { Cli, CliFallbackMode, CliOptionKind, type CliProgram } from "
|
|
14
|
-
import { applyShellEnv } from "
|
|
15
|
-
import { allMcpResources, collectMcpTools, mcpToolCallToArgv, resolveMcpSchemaUri } from "
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
18
|
-
import { generatePluginSkillBundle, generateSkillBundle } from "./skill/generate.ts";
|
|
19
|
-
import { cliSkillInstall } from "./skill/install.ts";
|
|
10
|
+
import { completionBashScript, completionZshScript } from "~/builtins";
|
|
11
|
+
import { cliPresentationRoot } from "~/builtins/presentation.ts";
|
|
12
|
+
import { cliHelpRender } from "~/help.ts";
|
|
13
|
+
import { Cli, CliFallbackMode, CliOptionKind, type CliProgram } from "~/index";
|
|
14
|
+
import { applyShellEnv } from "~/mcp/env.ts";
|
|
15
|
+
import { allMcpResources, collectMcpTools, mcpToolCallToArgv, resolveMcpSchemaUri } from "~/mcp/tools.ts";
|
|
16
|
+
import { generatePluginSkillBundle, generateSkillBundle } from "~/skill/generate.ts";
|
|
17
|
+
import { cliSkillInstall } from "~/skill/install.ts";
|
|
20
18
|
import {
|
|
21
19
|
enumMcpFixture,
|
|
22
20
|
nestedDocsFallbackFixture,
|
|
23
21
|
nestedMcpFixture,
|
|
24
22
|
testProgram,
|
|
25
23
|
varargsReadFixture,
|
|
26
|
-
} from "
|
|
24
|
+
} from "~/test/fixtures.ts";
|
|
25
|
+
import { ParseKind, parse, postParseValidate } from "./parse.ts";
|
|
26
|
+
import { cliSchemaJson } from "./schema.ts";
|
|
27
27
|
import { cliValidateProgram } from "./validate.ts";
|
|
28
28
|
|
|
29
29
|
/** Tests that bundled short presence flags. */
|
|
@@ -115,6 +115,85 @@ test("fallback missing or unknown root flags", () => {
|
|
|
115
115
|
expect(pr.opts.name).toBe("bob");
|
|
116
116
|
});
|
|
117
117
|
|
|
118
|
+
test("param router descent captures pathParams", () => {
|
|
119
|
+
const root = testProgram({
|
|
120
|
+
key: "app",
|
|
121
|
+
description: "",
|
|
122
|
+
commands: [
|
|
123
|
+
{
|
|
124
|
+
key: "workspaces",
|
|
125
|
+
description: "Workspaces.",
|
|
126
|
+
commands: [
|
|
127
|
+
{
|
|
128
|
+
key: ":id",
|
|
129
|
+
description: "One workspace.",
|
|
130
|
+
commands: [
|
|
131
|
+
{
|
|
132
|
+
key: "get",
|
|
133
|
+
description: "Get workspace.",
|
|
134
|
+
handler: () => {},
|
|
135
|
+
},
|
|
136
|
+
],
|
|
137
|
+
},
|
|
138
|
+
],
|
|
139
|
+
},
|
|
140
|
+
],
|
|
141
|
+
});
|
|
142
|
+
cliValidateProgram(root);
|
|
143
|
+
const pr = postParseValidate(root, parse(root, ["workspaces", "qa2", "get"]));
|
|
144
|
+
expect(pr.kind).toBe(ParseKind.Ok);
|
|
145
|
+
expect(pr.path).toEqual(["workspaces", ":id", "get"]);
|
|
146
|
+
expect(pr.pathParams).toEqual({ id: "qa2" });
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
test("cli.enabled cascade blocks disabled router", () => {
|
|
150
|
+
const root = testProgram({
|
|
151
|
+
key: "app",
|
|
152
|
+
description: "",
|
|
153
|
+
commands: [
|
|
154
|
+
{
|
|
155
|
+
key: "workspaces",
|
|
156
|
+
description: "Disabled.",
|
|
157
|
+
cli: { enabled: false },
|
|
158
|
+
commands: [
|
|
159
|
+
{
|
|
160
|
+
key: "list",
|
|
161
|
+
description: "List.",
|
|
162
|
+
handler: () => {},
|
|
163
|
+
},
|
|
164
|
+
],
|
|
165
|
+
},
|
|
166
|
+
],
|
|
167
|
+
});
|
|
168
|
+
cliValidateProgram(root);
|
|
169
|
+
const pr = parse(root, ["workspaces", "list"]);
|
|
170
|
+
expect(pr.kind).toBe(ParseKind.Error);
|
|
171
|
+
expect(pr.errorMsg).toContain("Unknown command");
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
test("completion match child emits param router fallback", () => {
|
|
175
|
+
const root = testProgram({
|
|
176
|
+
key: "app",
|
|
177
|
+
description: "Test",
|
|
178
|
+
commands: [
|
|
179
|
+
{
|
|
180
|
+
key: "workspaces",
|
|
181
|
+
description: "Workspaces.",
|
|
182
|
+
commands: [
|
|
183
|
+
{
|
|
184
|
+
key: ":id",
|
|
185
|
+
description: "One workspace.",
|
|
186
|
+
commands: [{ key: "get", description: "Get.", handler: () => {} }],
|
|
187
|
+
},
|
|
188
|
+
],
|
|
189
|
+
},
|
|
190
|
+
],
|
|
191
|
+
});
|
|
192
|
+
cliValidateProgram(root);
|
|
193
|
+
const bash = completionBashScript(cliPresentationRoot(root));
|
|
194
|
+
expect(bash).toContain("*) echo");
|
|
195
|
+
});
|
|
196
|
+
|
|
118
197
|
test("unknown command", () => {
|
|
119
198
|
const root = testProgram({
|
|
120
199
|
key: "app",
|
|
@@ -551,7 +630,6 @@ test("root --schema is no longer a flag", () => {
|
|
|
551
630
|
version: "1.0.0",
|
|
552
631
|
description: "demo",
|
|
553
632
|
docs: {
|
|
554
|
-
enabled: true,
|
|
555
633
|
topics: { readme: { text: "# readme\n" } },
|
|
556
634
|
},
|
|
557
635
|
commands: [
|
|
@@ -639,98 +717,6 @@ test("cliSchemaExport resolves {argsbarg:program} in consumer notes", () => {
|
|
|
639
717
|
expect(schema.commands[0].notes).toBe("Run `myapp run` to start.");
|
|
640
718
|
});
|
|
641
719
|
|
|
642
|
-
/** Docs help lists schema, api, and skill subcommands. */
|
|
643
|
-
test("docs help lists schema, api, and skill subcommands", () => {
|
|
644
|
-
const root = testProgram({
|
|
645
|
-
key: "app",
|
|
646
|
-
version: "1.0.0",
|
|
647
|
-
description: "demo",
|
|
648
|
-
docs: {
|
|
649
|
-
enabled: true,
|
|
650
|
-
topics: { readme: { text: "# readme\n" } },
|
|
651
|
-
},
|
|
652
|
-
commands: [
|
|
653
|
-
{
|
|
654
|
-
key: "x",
|
|
655
|
-
description: "cmd",
|
|
656
|
-
handler: () => {},
|
|
657
|
-
},
|
|
658
|
-
],
|
|
659
|
-
});
|
|
660
|
-
const help = cliHelpRender(cliPresentationRoot(root), ["docs"], false);
|
|
661
|
-
expect(help).toContain("cli-schema");
|
|
662
|
-
expect(help).toContain("Print the full CLI command tree as JSON.");
|
|
663
|
-
expect(help).toContain("api");
|
|
664
|
-
expect(help).toContain("markdown");
|
|
665
|
-
expect(help).toContain("skill");
|
|
666
|
-
expect(help).toContain("reference agent SKILL");
|
|
667
|
-
});
|
|
668
|
-
|
|
669
|
-
/** Root help omits legacy --schema flag. */
|
|
670
|
-
test("root help omits legacy --schema flag", () => {
|
|
671
|
-
const root = testProgram({
|
|
672
|
-
key: "app",
|
|
673
|
-
version: "1.0.0",
|
|
674
|
-
description: "demo",
|
|
675
|
-
commands: [
|
|
676
|
-
{
|
|
677
|
-
key: "x",
|
|
678
|
-
description: "cmd",
|
|
679
|
-
handler: () => {},
|
|
680
|
-
},
|
|
681
|
-
],
|
|
682
|
-
});
|
|
683
|
-
const help = cliHelpRender(cliPresentationRoot(root), [], false);
|
|
684
|
-
expect(help).not.toContain("--schema");
|
|
685
|
-
});
|
|
686
|
-
|
|
687
|
-
/** Root help shows agent docs hint when docs enabled. */
|
|
688
|
-
test("root help shows agent docs hint when docs enabled", () => {
|
|
689
|
-
const root = testProgram({
|
|
690
|
-
key: "myapp",
|
|
691
|
-
version: "1.0.0",
|
|
692
|
-
description: "demo",
|
|
693
|
-
docs: {
|
|
694
|
-
enabled: true,
|
|
695
|
-
topics: { readme: { text: "# readme\n" } },
|
|
696
|
-
},
|
|
697
|
-
commands: [{ key: "run", description: "Run.", handler: () => {} }],
|
|
698
|
-
});
|
|
699
|
-
const help = cliHelpRender(cliPresentationRoot(root), [], false);
|
|
700
|
-
expect(help).toContain("For AI agents: `myapp docs skill`.");
|
|
701
|
-
expect(help).not.toContain("install --skill");
|
|
702
|
-
});
|
|
703
|
-
|
|
704
|
-
test("root help omits agent hint when docs disabled", () => {
|
|
705
|
-
const root = testProgram({
|
|
706
|
-
key: "myapp",
|
|
707
|
-
version: "1.0.0",
|
|
708
|
-
description: "demo",
|
|
709
|
-
commands: [{ key: "run", description: "Run.", handler: () => {} }],
|
|
710
|
-
});
|
|
711
|
-
const help = cliHelpRender(cliPresentationRoot(root), [], false);
|
|
712
|
-
expect(help).not.toContain("Agents:");
|
|
713
|
-
expect(help).not.toContain("docs skill");
|
|
714
|
-
});
|
|
715
|
-
|
|
716
|
-
/** Root help includes program notes and agent hint. */
|
|
717
|
-
test("root help includes program notes and agent hint", () => {
|
|
718
|
-
const root = testProgram({
|
|
719
|
-
key: "myapp",
|
|
720
|
-
version: "1.0.0",
|
|
721
|
-
description: "demo",
|
|
722
|
-
notes: "See `{argsbarg:program} docs readme` for the user guide.",
|
|
723
|
-
docs: {
|
|
724
|
-
enabled: true,
|
|
725
|
-
topics: { readme: { text: "# readme\n" } },
|
|
726
|
-
},
|
|
727
|
-
commands: [{ key: "run", description: "Run.", handler: () => {} }],
|
|
728
|
-
});
|
|
729
|
-
const help = cliHelpRender(cliPresentationRoot(root), [], false);
|
|
730
|
-
expect(help).toContain("See `myapp docs readme` for the user guide.");
|
|
731
|
-
expect(help).toContain("myapp docs skill");
|
|
732
|
-
});
|
|
733
|
-
|
|
734
720
|
test("Enum option inputSchema includes enum array", () => {
|
|
735
721
|
const tools = collectMcpTools(enumMcpFixture);
|
|
736
722
|
const run = tools.find((t) => t.name === "run")!;
|
|
@@ -814,14 +800,14 @@ test("cliValidateProgram rejects empty mcpServer", () => {
|
|
|
814
800
|
expect(() => cliValidateProgram(root)).toThrow(/mcpServer requires enabled: true/);
|
|
815
801
|
});
|
|
816
802
|
|
|
817
|
-
test("cliValidateProgram rejects empty
|
|
803
|
+
test("cliValidateProgram rejects empty httpServer", () => {
|
|
818
804
|
const root = testProgram({
|
|
819
805
|
key: "app",
|
|
820
806
|
description: "",
|
|
821
|
-
|
|
807
|
+
httpServer: {} as { enabled: boolean },
|
|
822
808
|
handler: () => {},
|
|
823
809
|
});
|
|
824
|
-
expect(() => cliValidateProgram(root)).toThrow(/
|
|
810
|
+
expect(() => cliValidateProgram(root)).toThrow(/httpServer requires enabled: true/);
|
|
825
811
|
});
|
|
826
812
|
|
|
827
813
|
test("resolveMcpSchemaUri uses sanitized root key", () => {
|
|
@@ -877,7 +863,7 @@ test("cliValidateProgram rejects resource URI matching auto docs topic", () => {
|
|
|
877
863
|
const root = testProgram({
|
|
878
864
|
key: "app",
|
|
879
865
|
description: "",
|
|
880
|
-
docs: {
|
|
866
|
+
docs: { topics: { readme: { text: "# r\n" } } },
|
|
881
867
|
mcpServer: {
|
|
882
868
|
enabled: true,
|
|
883
869
|
resources: [{ uri: "app://docs/readme", name: "dup", load: () => "" }],
|
|
@@ -908,7 +894,7 @@ test("allMcpResources includes docs topic resources", () => {
|
|
|
908
894
|
const root = testProgram({
|
|
909
895
|
key: "app",
|
|
910
896
|
description: "",
|
|
911
|
-
docs: {
|
|
897
|
+
docs: { topics: { readme: { text: "# hi\n" } } },
|
|
912
898
|
mcpServer: { enabled: true },
|
|
913
899
|
commands: [{ key: "leaf", description: "", handler: () => {} }],
|
|
914
900
|
});
|
|
@@ -971,6 +957,7 @@ test("nested fallback MissingOrUnknown routes unknown token to default", () => {
|
|
|
971
957
|
const root = testProgram({
|
|
972
958
|
key: "app",
|
|
973
959
|
description: "",
|
|
960
|
+
docs: { enabled: false },
|
|
974
961
|
commands: [
|
|
975
962
|
{
|
|
976
963
|
key: "docs",
|
|
@@ -1021,6 +1008,7 @@ test("cliValidateProgram rejects invalid nested fallbackCommand", () => {
|
|
|
1021
1008
|
const root = testProgram({
|
|
1022
1009
|
key: "app",
|
|
1023
1010
|
description: "",
|
|
1011
|
+
docs: { enabled: false },
|
|
1024
1012
|
commands: [
|
|
1025
1013
|
{
|
|
1026
1014
|
key: "docs",
|
|
@@ -7,6 +7,8 @@ It keeps handler dispatch and help on one parser so the CLI behavior stays consi
|
|
|
7
7
|
across every entry path.
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
+
import { isCliCallable } from "~/runtime/exposure.ts";
|
|
11
|
+
import { fullStringIsDouble } from "~/utils.ts";
|
|
10
12
|
import { formatValidationError, validateFormatValue } from "./formats.ts";
|
|
11
13
|
import {
|
|
12
14
|
CliFallbackMode,
|
|
@@ -14,11 +16,11 @@ import {
|
|
|
14
16
|
type CliNode,
|
|
15
17
|
type CliOption,
|
|
16
18
|
CliOptionKind,
|
|
19
|
+
type CliRouter,
|
|
17
20
|
isCliLeaf,
|
|
18
21
|
isCliRouter,
|
|
19
22
|
isJsonLeaf,
|
|
20
23
|
} from "./types.ts";
|
|
21
|
-
import { fullStringIsDouble } from "./utils.ts";
|
|
22
24
|
|
|
23
25
|
// ── Parse Result ──────────────────────────────────────────────────────────────
|
|
24
26
|
|
|
@@ -48,6 +50,8 @@ export interface ParseResult {
|
|
|
48
50
|
helpExplicit: boolean;
|
|
49
51
|
/** Path segments for scoped help (empty for root help). */
|
|
50
52
|
helpPath: string[];
|
|
53
|
+
/** Path parameter values from `:param` router descent (e.g. `{ id: "qa2" }`). */
|
|
54
|
+
pathParams: Record<string, string>;
|
|
51
55
|
/** User-facing error message when `kind === Error`. */
|
|
52
56
|
errorMsg: string;
|
|
53
57
|
/** Help path to render next to an error (for contextual help). */
|
|
@@ -69,6 +73,24 @@ function findChild(cmds: CliNode[], name: string): CliNode | undefined {
|
|
|
69
73
|
return cmds.find((c) => c.key === name);
|
|
70
74
|
}
|
|
71
75
|
|
|
76
|
+
function isParamRouterKey(key: string): boolean {
|
|
77
|
+
return key.startsWith(":");
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/** Static (non-`:param`) child by key. */
|
|
81
|
+
function findStaticChild(cmds: CliNode[], name: string): CliNode | undefined {
|
|
82
|
+
const ch = cmds.find((c) => c.key === name);
|
|
83
|
+
if (!ch || isParamRouterKey(ch.key)) {
|
|
84
|
+
return undefined;
|
|
85
|
+
}
|
|
86
|
+
return ch;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/** The single `:param` router child at this level, if any. */
|
|
90
|
+
function findParamChild(cmds: CliNode[]): CliNode | undefined {
|
|
91
|
+
return cmds.find((c) => isParamRouterKey(c.key));
|
|
92
|
+
}
|
|
93
|
+
|
|
72
94
|
/** Resolves a long-option definition by name (without leading `--`). */
|
|
73
95
|
function findOptionByName(defs: CliOption[], name: string): CliOption | undefined {
|
|
74
96
|
return defs.find((o) => o.name === name);
|
|
@@ -245,6 +267,7 @@ function finishJsonLeaf(
|
|
|
245
267
|
argv: string[],
|
|
246
268
|
path: string[],
|
|
247
269
|
opts: Record<string, string>,
|
|
270
|
+
pathParams: Record<string, string>,
|
|
248
271
|
): ParseResult {
|
|
249
272
|
let idx = startIdx;
|
|
250
273
|
const args: string[] = [];
|
|
@@ -252,20 +275,20 @@ function finishJsonLeaf(
|
|
|
252
275
|
if (idx < argv.length) {
|
|
253
276
|
const tok = argv[idx];
|
|
254
277
|
if (isHelpTok(tok)) {
|
|
255
|
-
return helpResult(path, true);
|
|
278
|
+
return helpResult(path, true, pathParams);
|
|
256
279
|
}
|
|
257
280
|
if (tok === "--") {
|
|
258
|
-
return errorResult("Unexpected extra arguments", path, []);
|
|
281
|
+
return errorResult("Unexpected extra arguments", path, [], pathParams);
|
|
259
282
|
}
|
|
260
283
|
if (tok.startsWith("-")) {
|
|
261
|
-
return errorResult(`JSON commands do not accept options: ${tok}`, path, []);
|
|
284
|
+
return errorResult(`JSON commands do not accept options: ${tok}`, path, [], pathParams);
|
|
262
285
|
}
|
|
263
286
|
args.push(tok);
|
|
264
287
|
idx += 1;
|
|
265
288
|
}
|
|
266
289
|
|
|
267
290
|
if (idx < argv.length) {
|
|
268
|
-
return errorResult("Unexpected extra arguments", path, []);
|
|
291
|
+
return errorResult("Unexpected extra arguments", path, [], pathParams);
|
|
269
292
|
}
|
|
270
293
|
|
|
271
294
|
return {
|
|
@@ -273,6 +296,7 @@ function finishJsonLeaf(
|
|
|
273
296
|
path,
|
|
274
297
|
opts,
|
|
275
298
|
args,
|
|
299
|
+
pathParams,
|
|
276
300
|
helpExplicit: false,
|
|
277
301
|
helpPath: [],
|
|
278
302
|
errorMsg: "",
|
|
@@ -289,6 +313,7 @@ function finishLeaf(
|
|
|
289
313
|
opts: Record<string, string>,
|
|
290
314
|
optionDefs: CliOption[],
|
|
291
315
|
forcePositionalsIn: boolean,
|
|
316
|
+
pathParams: Record<string, string>,
|
|
292
317
|
): ParseResult {
|
|
293
318
|
let idx = startIdx;
|
|
294
319
|
const args: string[] = [];
|
|
@@ -299,7 +324,7 @@ function finishLeaf(
|
|
|
299
324
|
if (argMax === 1) {
|
|
300
325
|
if (argMin >= 1) {
|
|
301
326
|
if (idx >= argv.length) {
|
|
302
|
-
return errorResult(`Missing positional argument: ${p.name}`, path, []);
|
|
327
|
+
return errorResult(`Missing positional argument: ${p.name}`, path, [], pathParams);
|
|
303
328
|
}
|
|
304
329
|
args.push(argv[idx]);
|
|
305
330
|
idx += 1;
|
|
@@ -327,14 +352,14 @@ function finishLeaf(
|
|
|
327
352
|
}
|
|
328
353
|
|
|
329
354
|
if (!forcePositionals && isHelpTok(tok)) {
|
|
330
|
-
return helpResult(path, true);
|
|
355
|
+
return helpResult(path, true, pathParams);
|
|
331
356
|
}
|
|
332
357
|
|
|
333
358
|
if (!forcePositionals && tok.startsWith("-")) {
|
|
334
359
|
// MUST be false — lenient mode swallows unknown flags as positionals silently
|
|
335
360
|
const tailRep = consumeOptions(optionDefs, false, argv, idx, opts);
|
|
336
361
|
if (tailRep.report.err) {
|
|
337
|
-
return errorResult(tailRep.report.err, path, []);
|
|
362
|
+
return errorResult(tailRep.report.err, path, [], pathParams);
|
|
338
363
|
}
|
|
339
364
|
if (tailRep.report.sawDoubleDash) {
|
|
340
365
|
forcePositionals = true;
|
|
@@ -343,7 +368,7 @@ function finishLeaf(
|
|
|
343
368
|
idx = tailRep.nextIndex;
|
|
344
369
|
continue;
|
|
345
370
|
}
|
|
346
|
-
return errorResult(`Unexpected option token: ${tok}`, path, []);
|
|
371
|
+
return errorResult(`Unexpected option token: ${tok}`, path, [], pathParams);
|
|
347
372
|
}
|
|
348
373
|
|
|
349
374
|
args.push(tok);
|
|
@@ -358,27 +383,27 @@ function finishLeaf(
|
|
|
358
383
|
}
|
|
359
384
|
}
|
|
360
385
|
if (count < argMin) {
|
|
361
|
-
return errorResult(`Expected at least ${argMin} argument(s) for ${p.name}, got ${count}`, path, []);
|
|
386
|
+
return errorResult(`Expected at least ${argMin} argument(s) for ${p.name}, got ${count}`, path, [], pathParams);
|
|
362
387
|
}
|
|
363
388
|
}
|
|
364
389
|
|
|
365
390
|
if (idx < argv.length) {
|
|
366
391
|
if (forcePositionals) {
|
|
367
|
-
return errorResult("Unexpected extra arguments", path, []);
|
|
392
|
+
return errorResult("Unexpected extra arguments", path, [], pathParams);
|
|
368
393
|
}
|
|
369
394
|
|
|
370
395
|
if (isHelpTok(argv[idx])) {
|
|
371
|
-
return helpResult(path, true);
|
|
396
|
+
return helpResult(path, true, pathParams);
|
|
372
397
|
}
|
|
373
398
|
|
|
374
399
|
const tailRep = consumeOptions(optionDefs, false, argv, idx, opts);
|
|
375
400
|
if (tailRep.report.err) {
|
|
376
|
-
return errorResult(tailRep.report.err, path, []);
|
|
401
|
+
return errorResult(tailRep.report.err, path, [], pathParams);
|
|
377
402
|
}
|
|
378
403
|
idx = tailRep.nextIndex;
|
|
379
404
|
|
|
380
405
|
if (idx < argv.length) {
|
|
381
|
-
return errorResult("Unexpected extra arguments", path, []);
|
|
406
|
+
return errorResult("Unexpected extra arguments", path, [], pathParams);
|
|
382
407
|
}
|
|
383
408
|
}
|
|
384
409
|
|
|
@@ -387,6 +412,7 @@ function finishLeaf(
|
|
|
387
412
|
path,
|
|
388
413
|
opts,
|
|
389
414
|
args,
|
|
415
|
+
pathParams,
|
|
390
416
|
helpExplicit: false,
|
|
391
417
|
helpPath: [],
|
|
392
418
|
errorMsg: "",
|
|
@@ -397,12 +423,18 @@ function finishLeaf(
|
|
|
397
423
|
// ── Main Parser ───────────────────────────────────────────────────────────────
|
|
398
424
|
|
|
399
425
|
/** Builds a user-error parse result; `path` defaults to `errorHelpPath`. */
|
|
400
|
-
function errorResult(
|
|
426
|
+
function errorResult(
|
|
427
|
+
errorMsg: string,
|
|
428
|
+
errorHelpPath: string[] = [],
|
|
429
|
+
path: string[] = errorHelpPath,
|
|
430
|
+
pathParams: Record<string, string> = {},
|
|
431
|
+
): ParseResult {
|
|
401
432
|
return {
|
|
402
433
|
kind: ParseKind.Error,
|
|
403
434
|
path,
|
|
404
435
|
opts: {},
|
|
405
436
|
args: [],
|
|
437
|
+
pathParams,
|
|
406
438
|
helpExplicit: false,
|
|
407
439
|
helpPath: [],
|
|
408
440
|
errorMsg,
|
|
@@ -411,12 +443,13 @@ function errorResult(errorMsg: string, errorHelpPath: string[] = [], path: strin
|
|
|
411
443
|
}
|
|
412
444
|
|
|
413
445
|
/** Builds a help-request result for the current routing path. */
|
|
414
|
-
function helpResult(p: string[], explicit: boolean): ParseResult {
|
|
446
|
+
function helpResult(p: string[], explicit: boolean, pathParams: Record<string, string> = {}): ParseResult {
|
|
415
447
|
return {
|
|
416
448
|
kind: ParseKind.Help,
|
|
417
449
|
path: [],
|
|
418
450
|
opts: {},
|
|
419
451
|
args: [],
|
|
452
|
+
pathParams,
|
|
420
453
|
helpExplicit: explicit,
|
|
421
454
|
helpPath: p,
|
|
422
455
|
errorMsg: "",
|
|
@@ -424,13 +457,45 @@ function helpResult(p: string[], explicit: boolean): ParseResult {
|
|
|
424
457
|
};
|
|
425
458
|
}
|
|
426
459
|
|
|
460
|
+
type DescendResult = { ok: true; node: CliNode; cliEnabled: boolean } | { ok: false; error: ParseResult };
|
|
461
|
+
|
|
462
|
+
/** Descends into a static or `:param` child, updating path and pathParams. */
|
|
463
|
+
function descendChild(
|
|
464
|
+
parent: CliRouter,
|
|
465
|
+
tok: string,
|
|
466
|
+
path: string[],
|
|
467
|
+
pathParams: Record<string, string>,
|
|
468
|
+
cliEnabled: boolean,
|
|
469
|
+
): DescendResult {
|
|
470
|
+
const staticChild = findStaticChild(parent.commands, tok);
|
|
471
|
+
if (staticChild) {
|
|
472
|
+
if (!isCliCallable(staticChild, cliEnabled)) {
|
|
473
|
+
return { ok: false, error: errorResult(`Unknown subcommand: ${tok}`, path, [], pathParams) };
|
|
474
|
+
}
|
|
475
|
+
path.push(tok);
|
|
476
|
+
return { ok: true, node: staticChild, cliEnabled: isCliCallable(staticChild, cliEnabled) };
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
const paramChild = findParamChild(parent.commands);
|
|
480
|
+
if (paramChild && isCliCallable(paramChild, cliEnabled)) {
|
|
481
|
+
const paramName = paramChild.key.slice(1);
|
|
482
|
+
path.push(paramChild.key);
|
|
483
|
+
pathParams[paramName] = tok;
|
|
484
|
+
return { ok: true, node: paramChild, cliEnabled: isCliCallable(paramChild, cliEnabled) };
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
return { ok: false, error: errorResult(`Unknown subcommand: ${tok}`, path, [], pathParams) };
|
|
488
|
+
}
|
|
489
|
+
|
|
427
490
|
/**
|
|
428
491
|
* Parses `argv` against the program root, routing into subcommands and filling `opts` / `args`.
|
|
429
492
|
*/
|
|
430
493
|
export function parse(root: CliNode, argv: string[]): ParseResult {
|
|
431
494
|
let i = 0;
|
|
432
495
|
const path: string[] = [];
|
|
496
|
+
const pathParams: Record<string, string> = {};
|
|
433
497
|
const opts: Record<string, string> = {};
|
|
498
|
+
let cliEnabled = true;
|
|
434
499
|
|
|
435
500
|
const rootLenient =
|
|
436
501
|
isCliRouter(root) &&
|
|
@@ -456,9 +521,9 @@ export function parse(root: CliNode, argv: string[]): ParseResult {
|
|
|
456
521
|
|
|
457
522
|
if (isCliLeaf(root)) {
|
|
458
523
|
if (isJsonLeaf(root)) {
|
|
459
|
-
return finishJsonLeaf(root, i, argv, path, opts);
|
|
524
|
+
return finishJsonLeaf(root, i, argv, path, opts, pathParams);
|
|
460
525
|
}
|
|
461
|
-
return finishLeaf(root, i, argv, path, opts, root.options ?? [], forcePositionals);
|
|
526
|
+
return finishLeaf(root, i, argv, path, opts, root.options ?? [], forcePositionals, pathParams);
|
|
462
527
|
}
|
|
463
528
|
|
|
464
529
|
if (i >= argv.length) {
|
|
@@ -477,12 +542,41 @@ export function parse(root: CliNode, argv: string[]): ParseResult {
|
|
|
477
542
|
}
|
|
478
543
|
} else {
|
|
479
544
|
const peek = argv[i];
|
|
480
|
-
const childPick = !forcePositionals ?
|
|
545
|
+
const childPick = !forcePositionals ? findStaticChild(root.commands, peek) : undefined;
|
|
481
546
|
|
|
482
547
|
if (childPick !== undefined) {
|
|
548
|
+
if (!isCliCallable(childPick, cliEnabled)) {
|
|
549
|
+
return errorResult(`Unknown command: ${peek}`, path, [], pathParams);
|
|
550
|
+
}
|
|
483
551
|
cmdName = peek;
|
|
484
552
|
i += 1;
|
|
485
553
|
node = childPick;
|
|
554
|
+
cliEnabled = isCliCallable(childPick, cliEnabled);
|
|
555
|
+
} else if (!forcePositionals && isCliRouter(root)) {
|
|
556
|
+
const paramChild = findParamChild(root.commands);
|
|
557
|
+
if (paramChild && isCliCallable(paramChild, cliEnabled)) {
|
|
558
|
+
cmdName = paramChild.key;
|
|
559
|
+
pathParams[paramChild.key.slice(1)] = peek;
|
|
560
|
+
i += 1;
|
|
561
|
+
node = paramChild;
|
|
562
|
+
cliEnabled = isCliCallable(paramChild, cliEnabled);
|
|
563
|
+
} else {
|
|
564
|
+
const fallbackCommand = root.fallbackCommand;
|
|
565
|
+
const canRouteUnknown =
|
|
566
|
+
fallbackCommand !== undefined &&
|
|
567
|
+
((root.fallbackMode ?? CliFallbackMode.MissingOnly) === CliFallbackMode.MissingOrUnknown ||
|
|
568
|
+
(root.fallbackMode ?? CliFallbackMode.MissingOnly) === CliFallbackMode.UnknownOnly);
|
|
569
|
+
|
|
570
|
+
if (canRouteUnknown) {
|
|
571
|
+
cmdName = fallbackCommand;
|
|
572
|
+
node = findChild(root.commands, cmdName);
|
|
573
|
+
if (!node) {
|
|
574
|
+
return errorResult(`Unknown command: ${cmdName}`, path, [], pathParams);
|
|
575
|
+
}
|
|
576
|
+
} else {
|
|
577
|
+
return errorResult(`Unknown command: ${peek}`, path, [], pathParams);
|
|
578
|
+
}
|
|
579
|
+
}
|
|
486
580
|
} else {
|
|
487
581
|
const fallbackCommand = root.fallbackCommand;
|
|
488
582
|
const canRouteUnknown =
|
|
@@ -520,7 +614,7 @@ export function parse(root: CliNode, argv: string[]): ParseResult {
|
|
|
520
614
|
// Walk the command tree
|
|
521
615
|
while (true) {
|
|
522
616
|
if (isCliLeaf(current) && isJsonLeaf(current)) {
|
|
523
|
-
return finishJsonLeaf(current, i, argv, path, opts);
|
|
617
|
+
return finishJsonLeaf(current, i, argv, path, opts, pathParams);
|
|
524
618
|
}
|
|
525
619
|
|
|
526
620
|
if (!forcePositionals) {
|
|
@@ -535,7 +629,7 @@ export function parse(root: CliNode, argv: string[]): ParseResult {
|
|
|
535
629
|
}
|
|
536
630
|
|
|
537
631
|
if (i < argv.length && !forcePositionals && isHelpTok(argv[i])) {
|
|
538
|
-
return helpResult(path, true);
|
|
632
|
+
return helpResult(path, true, pathParams);
|
|
539
633
|
}
|
|
540
634
|
|
|
541
635
|
if (i >= argv.length) {
|
|
@@ -547,28 +641,29 @@ export function parse(root: CliNode, argv: string[]): ParseResult {
|
|
|
547
641
|
if (fbNode) {
|
|
548
642
|
path.push(fb);
|
|
549
643
|
current = fbNode;
|
|
644
|
+
cliEnabled = isCliCallable(fbNode, cliEnabled);
|
|
550
645
|
continue;
|
|
551
646
|
}
|
|
552
647
|
}
|
|
553
|
-
return helpResult(path, false);
|
|
648
|
+
return helpResult(path, false, pathParams);
|
|
554
649
|
}
|
|
555
650
|
if (!isCliLeaf(current)) {
|
|
556
|
-
return helpResult(path, false);
|
|
651
|
+
return helpResult(path, false, pathParams);
|
|
557
652
|
}
|
|
558
|
-
return finishLeaf(current, i, argv, path, opts, collectOptionDefs(root, path), forcePositionals);
|
|
653
|
+
return finishLeaf(current, i, argv, path, opts, collectOptionDefs(root, path), forcePositionals, pathParams);
|
|
559
654
|
}
|
|
560
655
|
|
|
561
656
|
const tok = argv[i];
|
|
562
657
|
if (!forcePositionals && tok.startsWith("-")) {
|
|
563
|
-
return errorResult(`Unexpected option token: ${tok}`, path);
|
|
658
|
+
return errorResult(`Unexpected option token: ${tok}`, path, [], pathParams);
|
|
564
659
|
}
|
|
565
660
|
|
|
566
661
|
if (!forcePositionals && isCliRouter(current)) {
|
|
567
|
-
const
|
|
568
|
-
if (
|
|
662
|
+
const descended = descendChild(current, tok, path, pathParams, cliEnabled);
|
|
663
|
+
if (descended.ok) {
|
|
569
664
|
i += 1;
|
|
570
|
-
|
|
571
|
-
|
|
665
|
+
current = descended.node;
|
|
666
|
+
cliEnabled = descended.cliEnabled;
|
|
572
667
|
continue;
|
|
573
668
|
}
|
|
574
669
|
}
|
|
@@ -584,6 +679,7 @@ export function parse(root: CliNode, argv: string[]): ParseResult {
|
|
|
584
679
|
if (fbNode) {
|
|
585
680
|
path.push(fb);
|
|
586
681
|
current = fbNode;
|
|
682
|
+
cliEnabled = isCliCallable(fbNode, cliEnabled);
|
|
587
683
|
continue;
|
|
588
684
|
}
|
|
589
685
|
}
|
|
@@ -591,13 +687,15 @@ export function parse(root: CliNode, argv: string[]): ParseResult {
|
|
|
591
687
|
return errorResult(
|
|
592
688
|
forcePositionals ? `Expected subcommand but got positional: ${tok}` : `Unknown subcommand: ${tok}`,
|
|
593
689
|
path,
|
|
690
|
+
[],
|
|
691
|
+
pathParams,
|
|
594
692
|
);
|
|
595
693
|
}
|
|
596
694
|
|
|
597
695
|
if (!isCliLeaf(current)) {
|
|
598
|
-
return helpResult(path, false);
|
|
696
|
+
return helpResult(path, false, pathParams);
|
|
599
697
|
}
|
|
600
|
-
return finishLeaf(current, i, argv, path, opts, collectOptionDefs(root, path), forcePositionals);
|
|
698
|
+
return finishLeaf(current, i, argv, path, opts, collectOptionDefs(root, path), forcePositionals, pathParams);
|
|
601
699
|
}
|
|
602
700
|
}
|
|
603
701
|
|