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
|
@@ -2,15 +2,15 @@
|
|
|
2
2
|
This module serializes the CLI schema tree to JSON for machine-readable introspection.
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import { type CliSchemaExport, exportPresentationBuiltins } from "
|
|
6
|
-
import { cliResolveNotes } from "
|
|
7
|
-
import { visibleOptions } from "
|
|
5
|
+
import { type CliSchemaExport, exportPresentationBuiltins } from "~/builtins/export.ts";
|
|
6
|
+
import { cliResolveNotes } from "~/help.ts";
|
|
7
|
+
import { isCliSchemaHidden, visibleOptions } from "~/runtime/exposure.ts";
|
|
8
8
|
import { type CliNode, type CliProgram, isCliLeaf, isCliRouter, leafOutputSchema } from "./types.ts";
|
|
9
9
|
|
|
10
|
-
const RESERVED = new Set(["
|
|
10
|
+
const RESERVED = new Set(["http", "completion", "configure", "docs", "mcp", "version"]);
|
|
11
11
|
|
|
12
12
|
function exportCommand(cmd: CliNode, root: CliProgram): CliSchemaExport | null {
|
|
13
|
-
if (cmd
|
|
13
|
+
if (isCliSchemaHidden(cmd)) {
|
|
14
14
|
return null;
|
|
15
15
|
}
|
|
16
16
|
|
|
@@ -35,6 +35,8 @@ function exportCommand(cmd: CliNode, root: CliProgram): CliSchemaExport | null {
|
|
|
35
35
|
const outputSchema = leafOutputSchema(cmd);
|
|
36
36
|
if (outputSchema !== undefined) {
|
|
37
37
|
out.outputSchema = outputSchema;
|
|
38
|
+
} else if (cmd.http?.successContentType !== undefined) {
|
|
39
|
+
out.outputContentType = cmd.http.successContentType;
|
|
38
40
|
}
|
|
39
41
|
out.commands = exportPresentationBuiltins(root);
|
|
40
42
|
return out;
|
|
@@ -67,17 +69,27 @@ function resolveSchemaNotes(node: CliSchemaExport, appKey: string): CliSchemaExp
|
|
|
67
69
|
return out;
|
|
68
70
|
}
|
|
69
71
|
|
|
72
|
+
/** JSON-safe command tree export (handlers omitted). */
|
|
73
|
+
export interface CliSchemaRootExport extends CliSchemaExport {
|
|
74
|
+
/** Program-level error JSON Schema when configured on `httpServer.errors` or `mcpServer.errors`. */
|
|
75
|
+
errorSchema?: Record<string, unknown>;
|
|
76
|
+
}
|
|
77
|
+
|
|
70
78
|
/** Returns the JSON-safe command tree (handlers omitted). */
|
|
71
|
-
export function cliSchemaExport(root: CliProgram):
|
|
79
|
+
export function cliSchemaExport(root: CliProgram): CliSchemaRootExport {
|
|
72
80
|
const exported = exportCommand(root, root);
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
81
|
+
const errorSchema = root.httpServer?.errors?.errorSchema ?? root.mcpServer?.errors?.errorSchema;
|
|
82
|
+
const base: CliSchemaRootExport = !exported
|
|
83
|
+
? {
|
|
84
|
+
key: root.key,
|
|
85
|
+
description: root.description,
|
|
86
|
+
commands: exportPresentationBuiltins(root),
|
|
87
|
+
}
|
|
88
|
+
: resolveSchemaNotes(exported, root.key);
|
|
89
|
+
if (errorSchema !== undefined) {
|
|
90
|
+
base.errorSchema = errorSchema;
|
|
79
91
|
}
|
|
80
|
-
return
|
|
92
|
+
return base;
|
|
81
93
|
}
|
|
82
94
|
|
|
83
95
|
export function cliSchemaJson(root: CliProgram): string {
|
|
@@ -4,12 +4,13 @@ It is the shared declarative model that parsing, validation, help, and completio
|
|
|
4
4
|
read from, so the package has one source of truth.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
+
import type { AnyAppConfigSnapshot } from "~/config/context.ts";
|
|
7
8
|
import type { CliContext } from "./context.ts";
|
|
8
9
|
|
|
9
10
|
/**
|
|
10
11
|
* How a leaf handler was dispatched.
|
|
11
12
|
*/
|
|
12
|
-
export type CliInvocation = "cli" | "mcp" | "
|
|
13
|
+
export type CliInvocation = "cli" | "mcp" | "http";
|
|
13
14
|
|
|
14
15
|
/**
|
|
15
16
|
* Option kinds: presence (boolean flag), string (free-form text), number (strict double), enum (fixed choices), or json (parsed JSON object/array).
|
|
@@ -61,14 +62,49 @@ export enum CliFallbackMode {
|
|
|
61
62
|
UnknownOnly = "unknownOnly",
|
|
62
63
|
}
|
|
63
64
|
|
|
65
|
+
/**
|
|
66
|
+
* Per-surface CLI exposure (help, completions, cli-schema).
|
|
67
|
+
*/
|
|
68
|
+
export interface CliCliExposureConfig {
|
|
69
|
+
/** When `false`, not callable via CLI (cascades to descendants). Default: true. */
|
|
70
|
+
enabled?: boolean;
|
|
71
|
+
/** Callable; omit from help, completions, and schema export. */
|
|
72
|
+
hidden?: boolean;
|
|
73
|
+
completions?: { enabled?: boolean; hidden?: boolean };
|
|
74
|
+
schema?: { enabled?: boolean; hidden?: boolean };
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/** HTTP method for REST leaves. */
|
|
78
|
+
export type CliHttpMethod = "GET" | "POST" | "PUT" | "PATCH" | "DELETE";
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Per-node HTTP exposure and response defaults (routers: segment/enabled/hidden; leaves: full set).
|
|
82
|
+
*/
|
|
83
|
+
export interface CliHttpExposureConfig {
|
|
84
|
+
/** When `false`, omit from HTTP route table. Default: exposed. */
|
|
85
|
+
enabled?: boolean;
|
|
86
|
+
/** Callable; omit from OpenAPI / route discovery. */
|
|
87
|
+
hidden?: boolean;
|
|
88
|
+
/** Override inferred HTTP verb. */
|
|
89
|
+
method?: CliHttpMethod;
|
|
90
|
+
/** URL path segment override (≠ `key`). */
|
|
91
|
+
segment?: string;
|
|
92
|
+
/** Default success HTTP status when handler omits `ctx.respond({ status })`. */
|
|
93
|
+
successStatus?: number;
|
|
94
|
+
/** Default success Content-Type (OpenAPI + response headers). */
|
|
95
|
+
successContentType?: string;
|
|
96
|
+
/** Default Content-Disposition for binary/downloads. */
|
|
97
|
+
contentDisposition?: string;
|
|
98
|
+
}
|
|
99
|
+
|
|
64
100
|
/**
|
|
65
101
|
* A named flag or value option (`--long`, `-short`), listed on command `options`.
|
|
66
102
|
*/
|
|
67
103
|
export interface CliOption {
|
|
68
104
|
/** Option name (e.g., "name", "verbose"). */
|
|
69
105
|
name: string;
|
|
70
|
-
/**
|
|
71
|
-
|
|
106
|
+
/** Per-surface CLI exposure for this option. */
|
|
107
|
+
cli?: Pick<CliCliExposureConfig, "hidden">;
|
|
72
108
|
/** Description shown in help. */
|
|
73
109
|
description: string;
|
|
74
110
|
/** Option kind: presence flag, string value, or number value. */
|
|
@@ -120,7 +156,7 @@ export interface CliPositional {
|
|
|
120
156
|
argMax?: number;
|
|
121
157
|
}
|
|
122
158
|
|
|
123
|
-
/**
|
|
159
|
+
/** @experimental MCP bundle output options (program root `mcpServer.bundle` only). */
|
|
124
160
|
export interface CliMcpBundleConfig {
|
|
125
161
|
author?: {
|
|
126
162
|
name: string;
|
|
@@ -136,10 +172,15 @@ export interface CliMcpBundleConfig {
|
|
|
136
172
|
/**
|
|
137
173
|
* Enables `myapp mcp` and MCP stdio server metadata (program root only).
|
|
138
174
|
* Must include `enabled: true`; omit `mcpServer` entirely to disable MCP.
|
|
175
|
+
* @experimental
|
|
139
176
|
*/
|
|
140
177
|
export interface CliMcpServerConfig {
|
|
141
178
|
/** When `true`, enables the `mcp` built-in and MCP stdio server. */
|
|
142
179
|
enabled: boolean;
|
|
180
|
+
/** MCP error response defaults. */
|
|
181
|
+
errors?: CliMcpServerErrorsConfig;
|
|
182
|
+
/** Observe-only hooks for JSON-RPC messages. */
|
|
183
|
+
hooks?: CliMcpWireHooks;
|
|
143
184
|
/** When `true`, `mcp bundle` writes `dist/<key>.mcpb` for Claude Desktop. Default false. */
|
|
144
185
|
mcpd?: boolean;
|
|
145
186
|
/** When `true`, `mcp bundle` also writes `dist/claude-plugin/<name>.zip`. Default false. */
|
|
@@ -161,23 +202,69 @@ export interface CliMcpServerConfig {
|
|
|
161
202
|
bundle?: CliMcpBundleConfig;
|
|
162
203
|
}
|
|
163
204
|
|
|
205
|
+
/** JSON Schema for structured error responses (OpenAPI + HTTP/MCP error bodies). */
|
|
206
|
+
export type CliJsonSchema = Record<string, unknown>;
|
|
207
|
+
|
|
208
|
+
/** Wire-level HTTP hooks (observe-only; all requests including health and 404s). */
|
|
209
|
+
export interface CliHttpWireHooks {
|
|
210
|
+
onRequest?: (ctx: CliHttpWireContext) => void | Promise<void>;
|
|
211
|
+
onResponse?: (ctx: CliHttpWireContext & { status: number; durationMs: number }) => void | Promise<void>;
|
|
212
|
+
onError?: (ctx: CliHttpWireContext & { failureKind: InvokeFailureKind; error: unknown }) => void | Promise<void>;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/** Per-request HTTP wire context for {@link CliHttpWireHooks}. */
|
|
216
|
+
export interface CliHttpWireContext {
|
|
217
|
+
request: Request;
|
|
218
|
+
requestId: string;
|
|
219
|
+
clientIp: string;
|
|
220
|
+
path: string;
|
|
221
|
+
method: string;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/** Wire-level MCP hooks on JSON-RPC messages (observe-only). */
|
|
225
|
+
export interface CliMcpWireHooks {
|
|
226
|
+
onRequest?: (ctx: CliMcpWireContext) => void | Promise<void>;
|
|
227
|
+
onResponse?: (ctx: CliMcpWireContext & { durationMs: number }) => void | Promise<void>;
|
|
228
|
+
onError?: (ctx: CliMcpWireContext & { failureKind: InvokeFailureKind; error: unknown }) => void | Promise<void>;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/** Per-message MCP wire context for {@link CliMcpWireHooks}. */
|
|
232
|
+
export interface CliMcpWireContext {
|
|
233
|
+
rpcMethod: string;
|
|
234
|
+
requestId: string;
|
|
235
|
+
toolName?: string;
|
|
236
|
+
}
|
|
237
|
+
|
|
164
238
|
/**
|
|
165
|
-
* Enables `myapp
|
|
166
|
-
* Must include `enabled: true`; omit `
|
|
239
|
+
* Enables `myapp http` and the HTTP tool server (program root only).
|
|
240
|
+
* Must include `enabled: true`; omit `httpServer` entirely to disable HTTP.
|
|
167
241
|
*/
|
|
168
|
-
export interface
|
|
169
|
-
/** When `true`, enables the `
|
|
242
|
+
export interface CliHttpServerConfig {
|
|
243
|
+
/** When `true`, enables the `http` built-in and HTTP tool server. */
|
|
170
244
|
enabled: boolean;
|
|
171
245
|
/** Listen host (default: `127.0.0.1`). */
|
|
172
246
|
host?: string;
|
|
173
247
|
/** Listen port (default: `3000`). */
|
|
174
248
|
port?: number;
|
|
249
|
+
/** Honor `X-Forwarded-For` for client IP in hooks and logs. */
|
|
250
|
+
trustProxy?: boolean;
|
|
251
|
+
/** HTTP error response defaults. */
|
|
252
|
+
errors?: { errorSchema?: CliJsonSchema; obscureUnexpected?: boolean };
|
|
253
|
+
/** Observe-only hooks for all HTTP requests. */
|
|
254
|
+
hooks?: CliHttpWireHooks;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/** MCP server error defaults. */
|
|
258
|
+
export interface CliMcpServerErrorsConfig {
|
|
259
|
+
errorSchema?: CliJsonSchema;
|
|
260
|
+
obscureUnexpected?: boolean;
|
|
175
261
|
}
|
|
176
262
|
|
|
177
263
|
/**
|
|
178
|
-
* Declarative HTTP response hints
|
|
264
|
+
* Declarative HTTP response hints passed to {@link apiSuccessResponse}.
|
|
265
|
+
* @internal Prefer `CliHttpExposureConfig` on the leaf.
|
|
179
266
|
*/
|
|
180
|
-
export interface
|
|
267
|
+
export interface CliHttpResponseConfig {
|
|
181
268
|
/** Default success Content-Type (default: `application/json`). */
|
|
182
269
|
contentType?: string;
|
|
183
270
|
/** Optional Content-Disposition (e.g. `attachment; filename="invoice.pdf"`). */
|
|
@@ -219,15 +306,13 @@ export interface CliMcpResource {
|
|
|
219
306
|
export interface CliMcpToolConfig {
|
|
220
307
|
/** When `false`, omit from `tools/list` (default: exposed). */
|
|
221
308
|
enabled?: boolean;
|
|
309
|
+
/** Callable; omit from `tools/list` and MCP tool schemas. */
|
|
310
|
+
hidden?: boolean;
|
|
222
311
|
/**
|
|
223
312
|
* Override the generated MCP tool description.
|
|
224
313
|
* Default: auto-generated from command path and description.
|
|
225
314
|
*/
|
|
226
315
|
description?: string;
|
|
227
|
-
/**
|
|
228
|
-
* @deprecated Set `outputSchema` on the leaf command instead.
|
|
229
|
-
*/
|
|
230
|
-
outputSchema?: Record<string, unknown>;
|
|
231
316
|
}
|
|
232
317
|
|
|
233
318
|
/**
|
|
@@ -310,6 +395,7 @@ export interface CliCompletionConfig {
|
|
|
310
395
|
enabled?: boolean;
|
|
311
396
|
}
|
|
312
397
|
|
|
398
|
+
/** @experimental */
|
|
313
399
|
export interface CliConfigureConfig {
|
|
314
400
|
/** When `false`, hide/disable `configure` (default: enabled). */
|
|
315
401
|
enabled?: boolean;
|
|
@@ -385,21 +471,16 @@ export interface CliDocsTopic {
|
|
|
385
471
|
}
|
|
386
472
|
|
|
387
473
|
/**
|
|
388
|
-
*
|
|
389
|
-
*
|
|
474
|
+
* Opt-out and optional topics for the `docs` built-in (program root only).
|
|
475
|
+
* Docs is enabled by default; set `enabled: false` to disable.
|
|
390
476
|
*/
|
|
391
477
|
export interface CliDocsConfig {
|
|
392
|
-
/** When `
|
|
393
|
-
enabled
|
|
478
|
+
/** When `false`, hide/disable `docs` (default: enabled). */
|
|
479
|
+
enabled?: boolean;
|
|
394
480
|
/** Router description for `myapp docs` (default: "Print bundled CLI documentation."). */
|
|
395
481
|
description?: string;
|
|
396
|
-
/**
|
|
397
|
-
|
|
398
|
-
* When omitted, uses the first key in `topics` (insertion order).
|
|
399
|
-
*/
|
|
400
|
-
defaultTopic?: string;
|
|
401
|
-
/** Topic key → bundled markdown. Reserved keys: `mcp`, `all` (supplied by the built-in). */
|
|
402
|
-
topics: Record<string, CliDocsTopic>;
|
|
482
|
+
/** Optional consumer markdown topics. Reserved keys: `mcp`, `all` (supplied by the built-in). */
|
|
483
|
+
topics?: Record<string, CliDocsTopic>;
|
|
403
484
|
}
|
|
404
485
|
|
|
405
486
|
/**
|
|
@@ -408,8 +489,10 @@ export interface CliDocsConfig {
|
|
|
408
489
|
export interface CliNodeBase {
|
|
409
490
|
/** Program or command key (e.g., "myapp", "stat", "owner"). */
|
|
410
491
|
key: string;
|
|
411
|
-
/**
|
|
412
|
-
|
|
492
|
+
/** Per-surface CLI exposure. */
|
|
493
|
+
cli?: CliCliExposureConfig;
|
|
494
|
+
/** Per-surface HTTP exposure and response defaults. */
|
|
495
|
+
http?: CliHttpExposureConfig;
|
|
413
496
|
/** Short description shown in help. */
|
|
414
497
|
description: string;
|
|
415
498
|
/** Additional notes shown in help (`{argsbarg:program}` → program key). */
|
|
@@ -436,13 +519,11 @@ export type CliLeaf = CliNodeBase & {
|
|
|
436
519
|
positionals?: CliPositional[];
|
|
437
520
|
/**
|
|
438
521
|
* JSON Schema for structured stdout (e.g. with `--json` or MCP when the handler emits JSON).
|
|
439
|
-
* Exported in `docs cli-schema`, `docs
|
|
522
|
+
* Exported in `docs cli-schema`, `docs cli`, and MCP `tools/list`; not validated at runtime yet.
|
|
440
523
|
*/
|
|
441
524
|
outputSchema?: Record<string, unknown>;
|
|
442
525
|
/** JSON Schema for MCP/HTTP tool arguments (flat object). */
|
|
443
526
|
inputSchema?: Record<string, unknown>;
|
|
444
|
-
/** Declarative HTTP response metadata (Content-Type, Content-Disposition). */
|
|
445
|
-
apiResponse?: CliApiResponseConfig;
|
|
446
527
|
/** Per-tool MCP exposure and metadata. */
|
|
447
528
|
mcpTool?: CliMcpToolConfig;
|
|
448
529
|
};
|
|
@@ -464,6 +545,109 @@ export type CliRouter = CliNodeBase & {
|
|
|
464
545
|
*/
|
|
465
546
|
export type CliNode = CliLeaf | CliRouter;
|
|
466
547
|
|
|
548
|
+
/** Classified failure kind for invoke error pipeline and HTTP/MCP status mapping. */
|
|
549
|
+
export type InvokeFailureKind = "validation" | "help" | "unexpected" | "not_ready" | "missing_config" | "unknown_route";
|
|
550
|
+
|
|
551
|
+
/**
|
|
552
|
+
* Per-invocation context attached in hooks (e.g. DB handles, auth principals).
|
|
553
|
+
* Augment in app code: `declare module "argsbarg" { interface CliLocals { db: AppDb } }`.
|
|
554
|
+
*/
|
|
555
|
+
export interface CliLocals {
|
|
556
|
+
/** Correlation id seeded before hooks run (HTTP/MCP wire id or generated UUID). */
|
|
557
|
+
requestId?: string;
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
/**
|
|
561
|
+
* Cross-request server state (HTTP/MCP runtime bag).
|
|
562
|
+
* Augment in app code: `declare module "argsbarg" { interface ServerState { db: AppDb } }`.
|
|
563
|
+
*/
|
|
564
|
+
export interface ServerState {
|
|
565
|
+
/** Set when app config soft-validation fails at server start. */
|
|
566
|
+
configFileError?: string;
|
|
567
|
+
/** Short-TTL cache for readiness probe results. */
|
|
568
|
+
readinessCache?: {
|
|
569
|
+
at: number;
|
|
570
|
+
result: { ok: boolean; checks: Record<string, { ok: boolean; error?: string; missing?: string[] }> };
|
|
571
|
+
};
|
|
572
|
+
/** Last readiness probe result. */
|
|
573
|
+
readiness?: { ok: boolean; checks: Record<string, { ok: boolean; error?: string; missing?: string[] }> };
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
/** Cross-request mutable state created at HTTP/MCP server start. */
|
|
577
|
+
export interface ServerRuntime {
|
|
578
|
+
/** Mutable global bag (DB pool, degraded flags, readiness cache, etc.). */
|
|
579
|
+
state: ServerState;
|
|
580
|
+
program: CliProgram;
|
|
581
|
+
surface: "http" | "mcp";
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
/** Context for program-level invoke hooks (CLI, HTTP, MCP user commands). */
|
|
585
|
+
export interface InvokeHookContext {
|
|
586
|
+
invocation: CliInvocation;
|
|
587
|
+
path: string[];
|
|
588
|
+
pathParams: Record<string, string>;
|
|
589
|
+
opts: Record<string, string>;
|
|
590
|
+
/** Per-invocation bag; `beforeInvoke` may write. Framework seeds `requestId` before hooks run. */
|
|
591
|
+
locals: CliLocals;
|
|
592
|
+
runtime?: ServerRuntime;
|
|
593
|
+
appConfig: AnyAppConfigSnapshot;
|
|
594
|
+
http?: { request: Request; clientIp: string; requestId: string };
|
|
595
|
+
mcp?: { rpcMethod: string; toolName?: string; requestId: string };
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
/** Error hook context after failure classification. */
|
|
599
|
+
export interface ErrorHookContext extends InvokeHookContext {
|
|
600
|
+
failureKind: InvokeFailureKind;
|
|
601
|
+
error: unknown;
|
|
602
|
+
/** Default client-facing error before `formatError` override. */
|
|
603
|
+
clientError: ClientErrorOverride;
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
/** Client-facing error payload; `formatError` may return a partial override. */
|
|
607
|
+
export interface ClientErrorOverride {
|
|
608
|
+
message: string;
|
|
609
|
+
exitCode?: number;
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
/** Minimal invoke result passed to `afterInvoke` (see {@link Cli.invoke}). */
|
|
613
|
+
export interface CliInvokeHookResult {
|
|
614
|
+
kind: "ok" | "help" | "error";
|
|
615
|
+
exitCode: number;
|
|
616
|
+
failureKind?: InvokeFailureKind;
|
|
617
|
+
errorMsg?: string;
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
/** Program-level invoke and error hooks (skipped for builtins). */
|
|
621
|
+
export interface CliProgramHooks {
|
|
622
|
+
/** May mutate `locals`, `opts`, `args`; may throw. Skipped for builtins. */
|
|
623
|
+
beforeInvoke?: (ctx: InvokeHookContext) => void | Promise<void>;
|
|
624
|
+
afterInvoke?: (ctx: InvokeHookContext & { result: CliInvokeHookResult }) => void | Promise<void>;
|
|
625
|
+
/** Mutate client-facing error payload only. Runs before `onError`. */
|
|
626
|
+
formatError?: (ctx: ErrorHookContext) => ClientErrorOverride | undefined | Promise<ClientErrorOverride | undefined>;
|
|
627
|
+
/** Observe only — runs after `formatError`; may enrich `locals`. Never mutates client response. */
|
|
628
|
+
onError?: (ctx: ErrorHookContext) => void | Promise<void>;
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
/** Context for optional `program.readiness` (HTTP/MCP health only). */
|
|
632
|
+
export interface ReadinessContext {
|
|
633
|
+
program: CliProgram;
|
|
634
|
+
surface: "http" | "mcp";
|
|
635
|
+
appConfig: AnyAppConfigSnapshot;
|
|
636
|
+
runtime: ServerRuntime;
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
/** Framework logging defaults (ECS json or human text on stderr). */
|
|
640
|
+
export interface CliLogConfig {
|
|
641
|
+
/** `json` = ECS lines; `text` = human stderr lines. Default: `json`. */
|
|
642
|
+
format?: "json" | "text";
|
|
643
|
+
/** Tee stderr + append; relative paths resolve under the app config dir. */
|
|
644
|
+
file?: string;
|
|
645
|
+
/** Emit HTTP/MCP access logs. Default: true. */
|
|
646
|
+
access?: boolean;
|
|
647
|
+
/** Emit error events after the hook pipeline. Default: true. */
|
|
648
|
+
errors?: boolean;
|
|
649
|
+
}
|
|
650
|
+
|
|
467
651
|
/**
|
|
468
652
|
* Program root passed to {@link Cli}.
|
|
469
653
|
* May be a leaf or router, plus optional program-level MCP and install config.
|
|
@@ -475,14 +659,20 @@ export type CliProgram = CliNode & {
|
|
|
475
659
|
appConfig?: CliAppConfig;
|
|
476
660
|
/** When set with `enabled: true`, enables the `mcp` built-in subcommand. */
|
|
477
661
|
mcpServer?: CliMcpServerConfig;
|
|
478
|
-
/** When set with `enabled: true`, enables the `
|
|
479
|
-
|
|
662
|
+
/** When set with `enabled: true`, enables the `http` built-in HTTP server. */
|
|
663
|
+
httpServer?: CliHttpServerConfig;
|
|
480
664
|
/** Opt-out and defaults for `configure`. */
|
|
481
665
|
configure?: CliConfigureConfig;
|
|
482
666
|
/** Opt-out for shell completion generation (`completion bash|zsh|fish`). */
|
|
483
667
|
completion?: CliCompletionConfig;
|
|
484
|
-
/**
|
|
668
|
+
/** Opt-out and optional topics for the `docs` built-in (default: enabled). */
|
|
485
669
|
docs?: CliDocsConfig;
|
|
670
|
+
/** Invoke and error hooks for user commands on CLI, HTTP, and MCP. */
|
|
671
|
+
hooks?: CliProgramHooks;
|
|
672
|
+
/** Optional readiness probe for HTTP/MCP `GET /health/ready` only. */
|
|
673
|
+
readiness?: (ctx: ReadinessContext) => boolean | Promise<boolean>;
|
|
674
|
+
/** Framework logging (stderr + optional file). */
|
|
675
|
+
log?: CliLogConfig;
|
|
486
676
|
};
|
|
487
677
|
|
|
488
678
|
/** True when the node is a leaf (has a handler). */
|
|
@@ -500,9 +690,9 @@ export function isCliRouter(node: CliNode): node is CliRouter {
|
|
|
500
690
|
return "commands" in node && Array.isArray(node.commands);
|
|
501
691
|
}
|
|
502
692
|
|
|
503
|
-
/** Resolves structured stdout schema from the leaf
|
|
693
|
+
/** Resolves structured stdout schema from the leaf. */
|
|
504
694
|
export function leafOutputSchema(leaf: CliLeaf): Record<string, unknown> | undefined {
|
|
505
|
-
return leaf.outputSchema
|
|
695
|
+
return leaf.outputSchema;
|
|
506
696
|
}
|
|
507
697
|
|
|
508
698
|
/**
|
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
This module validates CLI schemas before execution.
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import {
|
|
6
|
-
import { reservedDocsTopicResourceUris } from "
|
|
7
|
-
import { DOCS_BUILTIN_TOPIC_KEYS } from "
|
|
5
|
+
import { AGENT_PAIRS, MCP_KEYS, mcpServerRequiredForArtifact } from "~/configure/artifacts/target-registry.ts";
|
|
6
|
+
import { reservedDocsTopicResourceUris } from "~/docs/mcp-resources.ts";
|
|
7
|
+
import { DOCS_BUILTIN_TOPIC_KEYS, docsEnabled } from "~/docs/resolve.ts";
|
|
8
|
+
import { resolveMcpSchemaUri } from "~/mcp/tools.ts";
|
|
9
|
+
import { reservedCommandNames, resolveCapabilities } from "~/runtime/capabilities.ts";
|
|
8
10
|
import { validateFormatValue } from "./formats.ts";
|
|
9
|
-
import { AGENT_PAIRS, MCP_KEYS, mcpServerRequiredForArtifact } from "./install/target-registry.ts";
|
|
10
|
-
import { resolveMcpSchemaUri } from "./mcp/tools.ts";
|
|
11
11
|
import {
|
|
12
12
|
type CliLeaf,
|
|
13
13
|
type CliNode,
|
|
@@ -24,20 +24,15 @@ import {
|
|
|
24
24
|
|
|
25
25
|
/** Validates `docs` configuration on the program root. */
|
|
26
26
|
function validateDocsConfig(docs: import("./types.ts").CliDocsConfig): void {
|
|
27
|
-
const
|
|
28
|
-
|
|
29
|
-
throw new CliSchemaValidationError("docs.topics must be non-empty");
|
|
30
|
-
}
|
|
27
|
+
const topics = docs.topics ?? {};
|
|
28
|
+
const keys = Object.keys(topics);
|
|
31
29
|
for (const reserved of DOCS_BUILTIN_TOPIC_KEYS) {
|
|
32
|
-
if (reserved in
|
|
30
|
+
if (reserved in topics) {
|
|
33
31
|
throw new CliSchemaValidationError(`docs.topics key '${reserved}' is reserved for the docs built-in`);
|
|
34
32
|
}
|
|
35
33
|
}
|
|
36
|
-
if (docs.defaultTopic !== undefined && !(docs.defaultTopic in docs.topics)) {
|
|
37
|
-
throw new CliSchemaValidationError(`docs.defaultTopic '${docs.defaultTopic}' is not a key in docs.topics`);
|
|
38
|
-
}
|
|
39
34
|
for (const key of keys) {
|
|
40
|
-
const text =
|
|
35
|
+
const text = topics[key]?.text;
|
|
41
36
|
if (text === undefined || text.length === 0) {
|
|
42
37
|
throw new CliSchemaValidationError(`docs.topics['${key}'].text must be non-empty`);
|
|
43
38
|
}
|
|
@@ -181,15 +176,11 @@ export function cliValidateProgram(program: CliProgram): void {
|
|
|
181
176
|
throw new CliSchemaValidationError("mcpServer requires enabled: true; omit mcpServer to disable MCP");
|
|
182
177
|
}
|
|
183
178
|
|
|
184
|
-
if (program.
|
|
185
|
-
throw new CliSchemaValidationError("
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
if (program.docs !== undefined && program.docs.enabled !== true) {
|
|
189
|
-
throw new CliSchemaValidationError("docs requires enabled: true; omit docs to disable bundled documentation");
|
|
179
|
+
if (program.httpServer !== undefined && program.httpServer.enabled !== true) {
|
|
180
|
+
throw new CliSchemaValidationError("httpServer requires enabled: true; omit httpServer to disable HTTP API");
|
|
190
181
|
}
|
|
191
182
|
|
|
192
|
-
if (program.docs?.
|
|
183
|
+
if (docsEnabled(program) && program.docs?.topics !== undefined) {
|
|
193
184
|
validateDocsConfig(program.docs);
|
|
194
185
|
}
|
|
195
186
|
|
|
@@ -215,14 +206,20 @@ export function cliValidateProgram(program: CliProgram): void {
|
|
|
215
206
|
walkNode(program, program, true);
|
|
216
207
|
}
|
|
217
208
|
|
|
209
|
+
const PARAM_ROUTER_KEY = /^:[a-zA-Z][a-zA-Z0-9_]*$/;
|
|
210
|
+
|
|
211
|
+
function isParamRouterKey(key: string): boolean {
|
|
212
|
+
return key.startsWith(":");
|
|
213
|
+
}
|
|
214
|
+
|
|
218
215
|
function walkNode(node: CliNode, program: CliProgram, isRoot: boolean): void {
|
|
219
216
|
if (!isRoot) {
|
|
220
217
|
const rogue = node as CliProgram;
|
|
221
218
|
if (rogue.mcpServer !== undefined) {
|
|
222
219
|
throw new CliSchemaValidationError(`mcpServer is only supported on the program root (not on ${node.key})`);
|
|
223
220
|
}
|
|
224
|
-
if (rogue.
|
|
225
|
-
throw new CliSchemaValidationError(`
|
|
221
|
+
if (rogue.httpServer !== undefined) {
|
|
222
|
+
throw new CliSchemaValidationError(`httpServer is only supported on the program root (not on ${node.key})`);
|
|
226
223
|
}
|
|
227
224
|
if (rogue.configure !== undefined) {
|
|
228
225
|
throw new CliSchemaValidationError(`configure is only supported on the program root (not on ${node.key})`);
|
|
@@ -251,12 +248,10 @@ function walkNode(node: CliNode, program: CliProgram, isRoot: boolean): void {
|
|
|
251
248
|
}
|
|
252
249
|
}
|
|
253
250
|
const outputSchema = node.outputSchema;
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
const resolved = outputSchema ?? legacyOutputSchema;
|
|
259
|
-
if (resolved !== undefined && (typeof resolved !== "object" || resolved === null || Array.isArray(resolved))) {
|
|
251
|
+
if (
|
|
252
|
+
outputSchema !== undefined &&
|
|
253
|
+
(typeof outputSchema !== "object" || outputSchema === null || Array.isArray(outputSchema))
|
|
254
|
+
) {
|
|
260
255
|
throw new CliSchemaValidationError("outputSchema must be a JSON Schema object (not null or an array)");
|
|
261
256
|
}
|
|
262
257
|
const inputSchema = node.inputSchema;
|
|
@@ -308,11 +303,26 @@ function walkNode(node: CliNode, program: CliProgram, isRoot: boolean): void {
|
|
|
308
303
|
|
|
309
304
|
if (isCliRouter(node)) {
|
|
310
305
|
const seenNames = new Set<string>();
|
|
306
|
+
let paramRouterCount = 0;
|
|
311
307
|
for (const child of node.commands) {
|
|
312
308
|
if (seenNames.has(child.key)) {
|
|
313
309
|
throw new CliSchemaValidationError(`Duplicate command name: ${child.key}`);
|
|
314
310
|
}
|
|
315
311
|
seenNames.add(child.key);
|
|
312
|
+
if (isParamRouterKey(child.key)) {
|
|
313
|
+
if (!PARAM_ROUTER_KEY.test(child.key)) {
|
|
314
|
+
throw new CliSchemaValidationError(
|
|
315
|
+
`Param router key '${child.key}' must match :[a-zA-Z][a-zA-Z0-9_]* on '${node.key}'`,
|
|
316
|
+
);
|
|
317
|
+
}
|
|
318
|
+
if (!isCliRouter(child)) {
|
|
319
|
+
throw new CliSchemaValidationError(`Param router '${child.key}' must be a router with subcommands`);
|
|
320
|
+
}
|
|
321
|
+
paramRouterCount++;
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
if (paramRouterCount > 1) {
|
|
325
|
+
throw new CliSchemaValidationError(`At most one param router per level on '${node.key}'`);
|
|
316
326
|
}
|
|
317
327
|
|
|
318
328
|
if (node.fallbackMode !== undefined && node.fallbackCommand === undefined) {
|
package/src/docs/builtin.ts
CHANGED
|
@@ -1,16 +1,8 @@
|
|
|
1
|
-
import { docsSkillTopicDescription } from "
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
CliFallbackMode,
|
|
5
|
-
type CliLeaf,
|
|
6
|
-
type CliOption,
|
|
7
|
-
CliOptionKind,
|
|
8
|
-
type CliProgram,
|
|
9
|
-
type CliRouter,
|
|
10
|
-
} from "../types.ts";
|
|
1
|
+
import { docsSkillTopicDescription } from "~/builtins/configure-copy.ts";
|
|
2
|
+
import { type CliLeaf, type CliOption, CliOptionKind, type CliProgram, type CliRouter } from "~/core/types.ts";
|
|
3
|
+
import { resolveCapabilities } from "~/runtime/capabilities.ts";
|
|
11
4
|
import {
|
|
12
5
|
DOCS_ROUTER_DESCRIPTION,
|
|
13
|
-
docsEffectiveDefaultTopic,
|
|
14
6
|
docsEnabled,
|
|
15
7
|
docsIncludesHttpTopic,
|
|
16
8
|
docsIncludesMcpTopic,
|
|
@@ -18,6 +10,7 @@ import {
|
|
|
18
10
|
docsTopicDescription,
|
|
19
11
|
docsUserTopicKeys,
|
|
20
12
|
printDocsTopic,
|
|
13
|
+
resolveDocsConfig,
|
|
21
14
|
} from "./resolve.ts";
|
|
22
15
|
import { saveDocsTopic } from "./save.ts";
|
|
23
16
|
|
|
@@ -54,14 +47,12 @@ function docsRouterNotes(): string {
|
|
|
54
47
|
|
|
55
48
|
/** Built-in `docs` router with bundled topic subcommands. */
|
|
56
49
|
export function cliBuiltinDocsGroup(program: CliProgram): CliRouter {
|
|
57
|
-
const docs = program
|
|
58
|
-
|
|
59
|
-
throw new Error("docs not enabled");
|
|
60
|
-
}
|
|
50
|
+
const docs = resolveDocsConfig(program);
|
|
51
|
+
const topics = docs.topics ?? {};
|
|
61
52
|
const leaves: CliLeaf[] = [];
|
|
62
53
|
|
|
63
54
|
for (const key of docsUserTopicKeys(docs)) {
|
|
64
|
-
const topic =
|
|
55
|
+
const topic = topics[key];
|
|
65
56
|
if (!topic) {
|
|
66
57
|
throw new Error(`docs topic missing: ${key}`);
|
|
67
58
|
}
|
|
@@ -82,7 +73,7 @@ export function cliBuiltinDocsGroup(program: CliProgram): CliRouter {
|
|
|
82
73
|
|
|
83
74
|
leaves.push(
|
|
84
75
|
docsLeaf(program, "cli-schema", "Print the full CLI command tree as JSON."),
|
|
85
|
-
docsLeaf(program, "
|
|
76
|
+
docsLeaf(program, "cli", "Print the full command reference as markdown."),
|
|
86
77
|
docsLeaf(program, "skill", docsSkillTopicDescription(program, resolveCapabilities(program))),
|
|
87
78
|
);
|
|
88
79
|
|
|
@@ -91,8 +82,6 @@ export function cliBuiltinDocsGroup(program: CliProgram): CliRouter {
|
|
|
91
82
|
description: docs.description ?? DOCS_ROUTER_DESCRIPTION,
|
|
92
83
|
notes: docsRouterNotes(),
|
|
93
84
|
options: [DOCS_SAVE_OPTION],
|
|
94
|
-
fallbackCommand: docsEffectiveDefaultTopic(docs),
|
|
95
|
-
fallbackMode: CliFallbackMode.MissingOnly,
|
|
96
85
|
commands: leaves,
|
|
97
86
|
};
|
|
98
87
|
}
|