argsbarg 3.3.14 → 3.4.0
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/.private/scratch.md +3 -1
- package/CHANGELOG.md +12 -1
- package/docs/cli-program.md +19 -0
- package/docs/mcp.md +23 -3
- package/index.d.ts +47 -0
- package/package.json +1 -1
- package/src/builtins/dispatch.ts +16 -5
- package/src/builtins/export.ts +31 -17
- package/src/builtins/index.ts +1 -1
- package/src/builtins/mcp.ts +21 -5
- package/src/builtins/presentation.ts +46 -7
- package/src/docs/api-guide.test.ts +30 -0
- package/src/docs/api-guide.ts +18 -0
- package/src/help.ts +5 -4
- package/src/hidden-mcpb.test.ts +154 -0
- package/src/hidden.ts +32 -0
- package/src/index.test.ts +175 -1
- package/src/index.ts +3 -0
- package/src/invoke.ts +2 -2
- package/src/mcp/bundle.ts +251 -0
- package/src/mcp/server.ts +1 -0
- package/src/mcp/tools.ts +27 -10
- package/src/runtime.ts +3 -3
- package/src/schema.ts +26 -6
- package/src/types.ts +33 -0
- package/src/validate.ts +16 -0
package/.private/scratch.md
CHANGED
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [3.4.0] - 2026-06-22
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- **`hidden`** — boolean on commands and options; omitted from help listings, `docs schema` / `docs api`, shell completions, and MCP `tools/list`, but still parseable and invocable. Direct `-h` on a hidden command still works.
|
|
15
|
+
- **`mcp bundle`** — built-in subcommand when `mcpServer.enabled` (macOS-only v1). Runs `myapp mcp bundle` to pack `dist/<key>.mcpb` from `dist/<key>`. Bare `myapp mcp` still starts the stdio server.
|
|
16
|
+
- **`mcpServer.bundle`** — optional author, icon, and `longDescription` for MCP Bundle metadata.
|
|
17
|
+
- **Leaf `outputSchema`** — optional JSON Schema for structured stdout; exported in `docs schema`, `docs api`, skill `reference.md`, and MCP `tools/list` (stdout not validated at runtime yet). Legacy `mcpTool.outputSchema` still works.
|
|
18
|
+
- **MCP tool descriptions** — leaf `notes` are appended to `tools/list` descriptions (`{argsbarg:program}` resolved).
|
|
19
|
+
|
|
10
20
|
## [3.3.14] - 2026-06-21
|
|
11
21
|
|
|
12
22
|
### Changed
|
|
@@ -335,7 +345,8 @@ const cli = { ... } satisfies CliProgram; // or : CliProgram
|
|
|
335
345
|
- Migrate schemas: rename every `children` property to **`commands`**; move positional definitions to **`CliPositional`** objects on `positionals` and strip `positional` / `argMin` / `argMax` from flag definitions under `options` (flags only carry `name`, `description`, `kind`, and optional `shortName`).
|
|
336
346
|
- Imports: use `CliPositional` where needed; replace `CliOptionDef` with `CliOption` or `CliPositional` as appropriate.
|
|
337
347
|
|
|
338
|
-
[Unreleased]: https://github.com/bdombro/bun-argsbarg/compare/v3.
|
|
348
|
+
[Unreleased]: https://github.com/bdombro/bun-argsbarg/compare/v3.4.0...HEAD
|
|
349
|
+
[3.4.0]: https://github.com/bdombro/bun-argsbarg/releases/tag/v3.4.0
|
|
339
350
|
[3.3.14]: https://github.com/bdombro/bun-argsbarg/releases/tag/v3.3.14
|
|
340
351
|
[3.3.13]: https://github.com/bdombro/bun-argsbarg/releases/tag/v3.3.13
|
|
341
352
|
[3.3.12]: https://github.com/bdombro/bun-argsbarg/releases/tag/v3.3.12
|
package/docs/cli-program.md
CHANGED
|
@@ -113,6 +113,25 @@ Many "MCP problems" are schema or handler gaps. Prefer these over escape hatches
|
|
|
113
113
|
| `requiresEnv: [...]` | Runtime secrets; appended to MCP description and enforced at `tools/call` |
|
|
114
114
|
| `description: "..."` | **Irreducible** MCP limitation (e.g. live tail / `--watch` cannot be streamed on the MCP wire yet) |
|
|
115
115
|
|
|
116
|
+
### Structured stdout
|
|
117
|
+
|
|
118
|
+
On **leaf commands**, set `outputSchema` to a JSON Schema describing stdout when the handler emits JSON (typically with `--json`, or via MCP on the headless path):
|
|
119
|
+
|
|
120
|
+
```typescript
|
|
121
|
+
{
|
|
122
|
+
key: "lookup",
|
|
123
|
+
description: "Resolve owner info.",
|
|
124
|
+
outputSchema: {
|
|
125
|
+
type: "object",
|
|
126
|
+
properties: { user: { type: "string" }, path: { type: "string" } },
|
|
127
|
+
required: ["user", "path"],
|
|
128
|
+
},
|
|
129
|
+
handler: (ctx) => { /* ... */ },
|
|
130
|
+
}
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
Exported in `docs schema`, `docs api`, skill `reference.md`, and MCP `tools/list`. Not validated at runtime yet. Pair with `notes` for prose examples; do not duplicate the full schema in `notes`.
|
|
134
|
+
|
|
116
135
|
Do **not** use `mcpTool.description` to paper over missing `--yes`, non-standard flag names, or handlers that only work interactively — fix those instead.
|
|
117
136
|
|
|
118
137
|
If help text and MCP behavior match after your fixes, **omit `mcpTool` entirely**.
|
package/docs/mcp.md
CHANGED
|
@@ -103,7 +103,7 @@ Tool names are derived from the command path, with each segment sanitized (non-a
|
|
|
103
103
|
|
|
104
104
|
### Tool descriptions
|
|
105
105
|
|
|
106
|
-
Each tool’s `description` includes the human CLI path and the leaf’s help text, separated by an em dash. Tool arguments are defined in `inputSchema` (options and positionals with their descriptions). `mcpTool.requiresEnv` is appended as `[requires env: …]
|
|
106
|
+
Each tool’s `description` includes the human CLI path and the leaf’s help text, separated by an em dash. Leaf **`notes`** are appended after a blank line (with `{argsbarg:program}` resolved). Tool arguments are defined in `inputSchema` (options and positionals with their descriptions). `mcpTool.requiresEnv` is appended as `[requires env: …]` on auto-generated descriptions.
|
|
107
107
|
|
|
108
108
|
| CLI path | MCP `description` (example) |
|
|
109
109
|
| --- | --- |
|
|
@@ -138,6 +138,8 @@ mcpTool: {
|
|
|
138
138
|
}
|
|
139
139
|
```
|
|
140
140
|
|
|
141
|
+
Set **`outputSchema` on the leaf** (not under `mcpTool`) — see [cli-program.md — Structured stdout](cli-program.md#structured-stdout).
|
|
142
|
+
|
|
141
143
|
- **`description`** — when set, replaces the auto-generated `path — help` description entirely (no automatic `requiresEnv` suffix; mention vars in your text if needed).
|
|
142
144
|
- **`requiresEnv`** — on auto-generated descriptions, appended as `[requires env: …]`. Enforced at `tools/call` time before the handler runs. Empty or unset env values count as missing.
|
|
143
145
|
|
|
@@ -276,7 +278,7 @@ mcpServer: {
|
|
|
276
278
|
| `initialize` | Returns capabilities (`tools`, `resources`) and `serverInfo`. |
|
|
277
279
|
| `notifications/initialized` | Acknowledged; no response (notification). |
|
|
278
280
|
| `ping` | Returns `{}`. |
|
|
279
|
-
| `tools/list` | Lists all tools with `name`, `description`, `inputSchema`. |
|
|
281
|
+
| `tools/list` | Lists all tools with `name`, `description`, `inputSchema`, and optional `outputSchema`. |
|
|
280
282
|
| `tools/call` | Runs a leaf handler; params: `name`, `arguments` (object). |
|
|
281
283
|
| `resources/list` | Lists schema + custom resources. |
|
|
282
284
|
| `resources/read` | Returns resource body; params: `uri`. |
|
|
@@ -291,11 +293,29 @@ printf '%s\n' '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{}}' | bun
|
|
|
291
293
|
|
|
292
294
|
You should get one JSON line on stdout with `result.capabilities` and `result.serverInfo`.
|
|
293
295
|
|
|
296
|
+
## MCP Bundle (`mcp bundle`)
|
|
297
|
+
|
|
298
|
+
When `mcpServer.enabled` is true, **`mcp bundle`** packs a Claude Desktop **`.mcpb`** bundle (macOS-only v1):
|
|
299
|
+
|
|
300
|
+
```bash
|
|
301
|
+
just build
|
|
302
|
+
./dist/myapp mcp bundle
|
|
303
|
+
# → dist/myapp.mcpb
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
Expects the compiled binary at **`dist/<program.key>`** and writes **`dist/<program.key>.mcpb`**. Manifest metadata is generated from your schema (`mcpServerId`, tools, `requiresEnv`). Optional pack-time fields live under **`mcpServer.bundle`** (`author`, `icon`, `longDescription`).
|
|
307
|
+
|
|
308
|
+
Bare **`myapp mcp`** still runs the stdio MCP server (unchanged for `install --mcp` and MCP hosts). Use **`install --mcp`** for Cursor / Claude Code JSON config.
|
|
309
|
+
|
|
310
|
+
## Hidden commands and options
|
|
311
|
+
|
|
312
|
+
Set **`hidden: true`** on a command or option to omit it from help listings, `docs schema` / `docs api`, shell completions, and MCP `tools/list` / tool `inputSchema`. Hidden commands remain invocable; **`myapp hidden-cmd -h`** still works.
|
|
313
|
+
|
|
294
314
|
## Reserved names
|
|
295
315
|
|
|
296
316
|
When MCP is enabled:
|
|
297
317
|
|
|
298
|
-
- Do not declare
|
|
318
|
+
- Do not declare top-level commands named **`completion`** or **`mcp`** — reserved for platform builtins.
|
|
299
319
|
|
|
300
320
|
Running `myapp mcp` without `mcpServer` on the root fails with an error (exit 1).
|
|
301
321
|
|
package/index.d.ts
CHANGED
|
@@ -69,6 +69,8 @@ export declare enum CliFallbackMode {
|
|
|
69
69
|
export interface CliOption {
|
|
70
70
|
/** Option name (e.g., "name", "verbose"). */
|
|
71
71
|
name: string;
|
|
72
|
+
/** When `true`, omit from help, schema, completions, and MCP tool inputSchema (still parseable). */
|
|
73
|
+
hidden?: boolean;
|
|
72
74
|
/** Description shown in help. */
|
|
73
75
|
description: string;
|
|
74
76
|
/** Option kind: presence flag, string value, or number value. */
|
|
@@ -104,6 +106,18 @@ export interface CliPositional {
|
|
|
104
106
|
*/
|
|
105
107
|
argMax?: number;
|
|
106
108
|
}
|
|
109
|
+
/** Optional metadata for `mcp bundle` MCP Bundle output (program root `mcpServer.bundle` only). */
|
|
110
|
+
export interface CliMcpBundleConfig {
|
|
111
|
+
author?: {
|
|
112
|
+
name: string;
|
|
113
|
+
email?: string;
|
|
114
|
+
url?: string;
|
|
115
|
+
};
|
|
116
|
+
/** Repo-relative path to a PNG icon copied into the bundle. */
|
|
117
|
+
icon?: string;
|
|
118
|
+
/** Manifest `long_description` (defaults to program description). */
|
|
119
|
+
longDescription?: string;
|
|
120
|
+
}
|
|
107
121
|
/**
|
|
108
122
|
* Enables `myapp mcp` and MCP stdio server metadata (program root only).
|
|
109
123
|
* Must include `enabled: true`; omit `mcpServer` entirely to disable MCP.
|
|
@@ -130,6 +144,8 @@ export interface CliMcpServerConfig {
|
|
|
130
144
|
* URIs must be unique and must not equal schemaResourceUri.
|
|
131
145
|
*/
|
|
132
146
|
resources?: CliMcpResource[];
|
|
147
|
+
/** Optional MCP Bundle (`.mcpb`) metadata for `mcp bundle`. */
|
|
148
|
+
bundle?: CliMcpBundleConfig;
|
|
133
149
|
}
|
|
134
150
|
/**
|
|
135
151
|
* A custom MCP resource exposed under resources/list and resources/read.
|
|
@@ -163,6 +179,10 @@ export interface CliMcpToolConfig {
|
|
|
163
179
|
* Empty string counts as absent.
|
|
164
180
|
*/
|
|
165
181
|
requiresEnv?: string[];
|
|
182
|
+
/**
|
|
183
|
+
* @deprecated Set `outputSchema` on the leaf command instead.
|
|
184
|
+
*/
|
|
185
|
+
outputSchema?: Record<string, unknown>;
|
|
166
186
|
}
|
|
167
187
|
/**
|
|
168
188
|
* Opt-out and defaults for the `install` built-in (program root only).
|
|
@@ -222,6 +242,8 @@ export interface CliDocsConfig {
|
|
|
222
242
|
export interface CliNodeBase {
|
|
223
243
|
/** Program or command key (e.g., "myapp", "stat", "owner"). */
|
|
224
244
|
key: string;
|
|
245
|
+
/** When `true`, omit from help listings, schema, completions, and MCP tools (still invocable). */
|
|
246
|
+
hidden?: boolean;
|
|
225
247
|
/** Short description shown in help. */
|
|
226
248
|
description: string;
|
|
227
249
|
/** Additional notes shown in help (`{argsbarg:program}` → program key). */
|
|
@@ -237,6 +259,11 @@ export type CliLeaf = CliNodeBase & {
|
|
|
237
259
|
handler: CliHandler;
|
|
238
260
|
/** Positional argument definitions. */
|
|
239
261
|
positionals?: CliPositional[];
|
|
262
|
+
/**
|
|
263
|
+
* JSON Schema for structured stdout (e.g. with `--json` or MCP when the handler emits JSON).
|
|
264
|
+
* Exported in `docs schema`, `docs api`, and MCP `tools/list`; not validated at runtime yet.
|
|
265
|
+
*/
|
|
266
|
+
outputSchema?: Record<string, unknown>;
|
|
240
267
|
/** Per-tool MCP exposure and metadata. */
|
|
241
268
|
mcpTool?: CliMcpToolConfig;
|
|
242
269
|
};
|
|
@@ -378,5 +405,25 @@ export declare function createGhVersionCheck(config: GhVersionCheckConfig): {
|
|
|
378
405
|
};
|
|
379
406
|
/** Shared `gh release view` fetcher for hooks and version-check refresh. */
|
|
380
407
|
export declare function createGhFetchLatest(config: Pick<GhReleaseUpdateConfig, "repo" | "repoEnvHint">): () => Promise<string>;
|
|
408
|
+
/** Resolved paths for `mcp bundle`. */
|
|
409
|
+
export interface McpBundlePaths {
|
|
410
|
+
binaryPath: string;
|
|
411
|
+
outPath: string;
|
|
412
|
+
binaryName: string;
|
|
413
|
+
}
|
|
414
|
+
/** Default `dist/<key>` binary and `dist/<key>.mcpb` output under cwd. */
|
|
415
|
+
export declare function defaultMcpBundlePaths(program: CliProgram, cwd?: string): McpBundlePaths;
|
|
416
|
+
/** Generates MCPB `manifest.json` object from program schema and MCP tools. */
|
|
417
|
+
export declare function generateMcpManifest(program: CliProgram, binaryName: string): Record<string, unknown>;
|
|
418
|
+
export interface PackMcpBundleOpts {
|
|
419
|
+
cwd?: string;
|
|
420
|
+
binaryPath?: string;
|
|
421
|
+
outPath?: string;
|
|
422
|
+
}
|
|
423
|
+
/**
|
|
424
|
+
* Stages manifest + binary (+ optional icon) and writes a `.mcpb` ZIP.
|
|
425
|
+
* macOS-only v1; requires the compiled binary to exist.
|
|
426
|
+
*/
|
|
427
|
+
export declare function packMcpBundle(program: CliProgram, opts?: PackMcpBundleOpts): string;
|
|
381
428
|
|
|
382
429
|
export {};
|
package/package.json
CHANGED
package/src/builtins/dispatch.ts
CHANGED
|
@@ -9,6 +9,7 @@ import { cliBuiltinMcpCommand } from "./mcp.ts";
|
|
|
9
9
|
import { cliBuiltinVersionCommand } from "./version.ts";
|
|
10
10
|
import { cliBuiltinCompletionGroup as completionGroup } from "./completion-group.ts";
|
|
11
11
|
import { cliPresentationRoot } from "./presentation.ts";
|
|
12
|
+
import { runMcpBundle } from "../mcp/bundle.ts";
|
|
12
13
|
import { cliBuiltinDocsGroupIfEnabled } from "../docs/builtin.ts";
|
|
13
14
|
import { cliMcpServeStdio } from "../mcp.ts";
|
|
14
15
|
import { cliInstall } from "../install/index.ts";
|
|
@@ -72,12 +73,22 @@ export async function dispatchBuiltin(
|
|
|
72
73
|
process.stderr.write("MCP is not enabled. Set mcpServer: { enabled: true } on the program root.\n");
|
|
73
74
|
process.exit(1);
|
|
74
75
|
}
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
76
|
+
const sub = pr.path[1];
|
|
77
|
+
if (pr.path.length === 1 || sub === "serve") {
|
|
78
|
+
await cliMcpServeStdio(program);
|
|
79
|
+
process.exit(0);
|
|
78
80
|
}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
+
if (pr.path.length === 2 && sub === "bundle") {
|
|
82
|
+
try {
|
|
83
|
+
runMcpBundle(program);
|
|
84
|
+
} catch (err) {
|
|
85
|
+
process.stderr.write(err instanceof Error ? err.message + "\n" : "mcp bundle failed.\n");
|
|
86
|
+
process.exit(1);
|
|
87
|
+
}
|
|
88
|
+
process.exit(0);
|
|
89
|
+
}
|
|
90
|
+
process.stderr.write("Unknown subcommand: mcp " + pr.path.slice(1).join(" ") + "\n");
|
|
91
|
+
process.exit(1);
|
|
81
92
|
}
|
|
82
93
|
|
|
83
94
|
if (pr.path[0] === "install") {
|
package/src/builtins/export.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { type CliCapabilities, resolveCapabilities } from "../capabilities.ts";
|
|
2
|
-
import type { CliFallbackMode, CliOption, CliPositional, CliProgram } from "../types.ts";
|
|
2
|
+
import type { CliFallbackMode, CliNode, CliOption, CliPositional, CliProgram } from "../types.ts";
|
|
3
|
+
import { isCliRouter } from "../types.ts";
|
|
4
|
+
import { visibleOptions } from "../hidden.ts";
|
|
3
5
|
import { cliBuiltinCompletionGroup } from "./completion-group.ts";
|
|
4
6
|
import { cliBuiltinInstallCommand } from "./install.ts";
|
|
5
7
|
import { cliBuiltinMcpCommand } from "./mcp.ts";
|
|
@@ -11,6 +13,8 @@ export interface CliSchemaExport {
|
|
|
11
13
|
key: string;
|
|
12
14
|
description: string;
|
|
13
15
|
notes?: string;
|
|
16
|
+
/** JSON Schema for structured stdout when set on the leaf `mcpTool`. */
|
|
17
|
+
outputSchema?: Record<string, unknown>;
|
|
14
18
|
options?: CliOption[];
|
|
15
19
|
fallbackCommand?: string;
|
|
16
20
|
fallbackMode?: CliFallbackMode;
|
|
@@ -18,13 +22,11 @@ export interface CliSchemaExport {
|
|
|
18
22
|
positionals?: CliPositional[];
|
|
19
23
|
}
|
|
20
24
|
|
|
21
|
-
function exportBuiltinNode(cmd: {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
commands?: CliSchemaExport[];
|
|
27
|
-
}): CliSchemaExport {
|
|
25
|
+
function exportBuiltinNode(cmd: CliNode): CliSchemaExport | null {
|
|
26
|
+
if (cmd.hidden) {
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
|
|
28
30
|
const out: CliSchemaExport = {
|
|
29
31
|
key: cmd.key,
|
|
30
32
|
description: cmd.description,
|
|
@@ -32,11 +34,23 @@ function exportBuiltinNode(cmd: {
|
|
|
32
34
|
if ((cmd.notes ?? "").length > 0) {
|
|
33
35
|
out.notes = cmd.notes;
|
|
34
36
|
}
|
|
35
|
-
|
|
36
|
-
|
|
37
|
+
const options = visibleOptions(cmd.options);
|
|
38
|
+
if (options.length > 0) {
|
|
39
|
+
out.options = options;
|
|
37
40
|
}
|
|
38
|
-
if ((cmd
|
|
39
|
-
|
|
41
|
+
if (isCliRouter(cmd)) {
|
|
42
|
+
if (cmd.fallbackCommand !== undefined) {
|
|
43
|
+
out.fallbackCommand = cmd.fallbackCommand;
|
|
44
|
+
}
|
|
45
|
+
if (cmd.fallbackMode !== undefined) {
|
|
46
|
+
out.fallbackMode = cmd.fallbackMode;
|
|
47
|
+
}
|
|
48
|
+
const children = cmd.commands
|
|
49
|
+
.map((ch) => exportBuiltinNode(ch))
|
|
50
|
+
.filter((ch): ch is CliSchemaExport => ch !== null);
|
|
51
|
+
if (children.length > 0) {
|
|
52
|
+
out.commands = children;
|
|
53
|
+
}
|
|
40
54
|
}
|
|
41
55
|
return out;
|
|
42
56
|
}
|
|
@@ -45,18 +59,18 @@ function exportBuiltinNode(cmd: {
|
|
|
45
59
|
export function exportPresentationBuiltins(program: CliProgram, caps?: CliCapabilities): CliSchemaExport[] {
|
|
46
60
|
const resolved = caps ?? resolveCapabilities(program);
|
|
47
61
|
const builtins: CliSchemaExport[] = [
|
|
48
|
-
exportBuiltinNode(cliBuiltinCompletionGroup(program))
|
|
49
|
-
exportBuiltinNode(cliBuiltinVersionCommand())
|
|
62
|
+
exportBuiltinNode(cliBuiltinCompletionGroup(program))!,
|
|
63
|
+
exportBuiltinNode(cliBuiltinVersionCommand())!,
|
|
50
64
|
];
|
|
51
65
|
if (resolved.install) {
|
|
52
|
-
builtins.push(exportBuiltinNode(cliBuiltinInstallCommand(program)));
|
|
66
|
+
builtins.push(exportBuiltinNode(cliBuiltinInstallCommand(program))!);
|
|
53
67
|
}
|
|
54
68
|
const docsGroup = cliBuiltinDocsGroupIfEnabled(program);
|
|
55
69
|
if (docsGroup) {
|
|
56
|
-
builtins.push(exportBuiltinNode(docsGroup));
|
|
70
|
+
builtins.push(exportBuiltinNode(docsGroup)!);
|
|
57
71
|
}
|
|
58
72
|
if (resolved.mcp) {
|
|
59
|
-
builtins.push(exportBuiltinNode(cliBuiltinMcpCommand(program)));
|
|
73
|
+
builtins.push(exportBuiltinNode(cliBuiltinMcpCommand(program))!);
|
|
60
74
|
}
|
|
61
75
|
return builtins;
|
|
62
76
|
}
|
package/src/builtins/index.ts
CHANGED
|
@@ -4,7 +4,7 @@ export { completionFishScript } from "./completion-fish.ts";
|
|
|
4
4
|
export { cliBuiltinCompletionGroup } from "./completion-group.ts";
|
|
5
5
|
export { cliBuiltinInstallCommand, installBuiltinOptions } from "./install.ts";
|
|
6
6
|
export { cliBuiltinMcpCommand } from "./mcp.ts";
|
|
7
|
-
export { cliPresentationRoot, presentationBuiltins } from "./presentation.ts";
|
|
7
|
+
export { cliParseRoot, cliPresentationRoot, parseBuiltins, presentationBuiltins } from "./presentation.ts";
|
|
8
8
|
export { exportPresentationBuiltins, type CliSchemaExport } from "./export.ts";
|
|
9
9
|
export { dispatchBuiltin, builtinInterceptRoot } from "./dispatch.ts";
|
|
10
10
|
export { collectScopes, type ScopeRec } from "./scopes.ts";
|
package/src/builtins/mcp.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { resolveCapabilities } from "../capabilities.ts";
|
|
2
2
|
import { docsEnabled } from "../docs/resolve.ts";
|
|
3
|
-
import { type CliLeaf, type CliProgram } from "../types.ts";
|
|
3
|
+
import { type CliLeaf, type CliProgram, type CliRouter, CliFallbackMode } from "../types.ts";
|
|
4
4
|
|
|
5
|
-
/**
|
|
6
|
-
export function cliBuiltinMcpCommand(program: CliProgram):
|
|
5
|
+
/** Built-in `mcp` router: bare `myapp mcp` runs stdio (via hidden `serve` fallback); `mcp bundle` packs `.mcpb`. */
|
|
6
|
+
export function cliBuiltinMcpCommand(program: CliProgram): CliRouter {
|
|
7
7
|
const caps = resolveCapabilities(program);
|
|
8
8
|
const lines = [
|
|
9
9
|
"Stdio MCP server. Add to Cursor or Claude:",
|
|
@@ -18,10 +18,26 @@ export function cliBuiltinMcpCommand(program: CliProgram): CliLeaf {
|
|
|
18
18
|
if (docsEnabled(program)) {
|
|
19
19
|
lines.push("Full setup guide: {argsbarg:program} docs mcp");
|
|
20
20
|
}
|
|
21
|
+
|
|
22
|
+
const serve: CliLeaf = {
|
|
23
|
+
key: "serve",
|
|
24
|
+
hidden: true,
|
|
25
|
+
description: "Run as an MCP server over stdio for AI agents.",
|
|
26
|
+
handler: () => {},
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const bundle: CliLeaf = {
|
|
30
|
+
key: "bundle",
|
|
31
|
+
description: "Pack a Claude Desktop MCP Bundle (.mcpb) from dist/<key> (macOS-only v1).",
|
|
32
|
+
handler: () => {},
|
|
33
|
+
};
|
|
34
|
+
|
|
21
35
|
return {
|
|
22
36
|
key: "mcp",
|
|
23
|
-
description: "
|
|
37
|
+
description: "MCP server and bundle tools.",
|
|
24
38
|
notes: lines.join("\n"),
|
|
25
|
-
|
|
39
|
+
fallbackCommand: "serve",
|
|
40
|
+
fallbackMode: CliFallbackMode.MissingOnly,
|
|
41
|
+
commands: [serve, bundle],
|
|
26
42
|
};
|
|
27
43
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { CliCapabilities } from "../capabilities.ts";
|
|
2
2
|
import { resolveCapabilities } from "../capabilities.ts";
|
|
3
|
+
import { presentationNode, visibleOptions } from "../hidden.ts";
|
|
3
4
|
import type { CliLeaf, CliNode, CliProgram, CliRouter } from "../types.ts";
|
|
4
5
|
import { isCliLeaf, isCliRouter } from "../types.ts";
|
|
5
6
|
import { cliBuiltinCompletionGroup } from "./completion-group.ts";
|
|
@@ -8,8 +9,8 @@ import { cliBuiltinMcpCommand } from "./mcp.ts";
|
|
|
8
9
|
import { cliBuiltinVersionCommand } from "./version.ts";
|
|
9
10
|
import { cliBuiltinDocsGroupIfEnabled } from "../docs/builtin.ts";
|
|
10
11
|
|
|
11
|
-
/**
|
|
12
|
-
export function
|
|
12
|
+
/** All built-in command nodes for argv parsing (includes hidden builtins). */
|
|
13
|
+
export function parseBuiltins(program: CliProgram, caps: CliCapabilities): CliNode[] {
|
|
13
14
|
const builtins: CliNode[] = [
|
|
14
15
|
cliBuiltinCompletionGroup(program),
|
|
15
16
|
cliBuiltinVersionCommand(),
|
|
@@ -27,9 +28,44 @@ export function presentationBuiltins(program: CliProgram, caps: CliCapabilities)
|
|
|
27
28
|
return builtins;
|
|
28
29
|
}
|
|
29
30
|
|
|
31
|
+
/** Built-in subtrees visible in help, schema, and completions (hidden builtins omitted). */
|
|
32
|
+
export function presentationBuiltins(program: CliProgram, caps: CliCapabilities): CliNode[] {
|
|
33
|
+
return parseBuiltins(program, caps).filter((b) => !b.hidden);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Full command tree for argv parsing, including hidden commands and builtins.
|
|
38
|
+
* Routing programs merge user commands with builtins; leaf programs wrap builtins only.
|
|
39
|
+
*/
|
|
40
|
+
export function cliParseRoot(program: CliProgram): CliRouter {
|
|
41
|
+
const caps = resolveCapabilities(program);
|
|
42
|
+
const builtins = parseBuiltins(program, caps);
|
|
43
|
+
|
|
44
|
+
if (isCliLeaf(program)) {
|
|
45
|
+
return {
|
|
46
|
+
key: program.key,
|
|
47
|
+
description: program.description,
|
|
48
|
+
notes: program.notes,
|
|
49
|
+
options: program.options,
|
|
50
|
+
commands: builtins,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return {
|
|
55
|
+
key: program.key,
|
|
56
|
+
description: program.description,
|
|
57
|
+
notes: program.notes,
|
|
58
|
+
options: program.options,
|
|
59
|
+
fallbackCommand: program.fallbackCommand,
|
|
60
|
+
fallbackMode: program.fallbackMode,
|
|
61
|
+
commands: [...program.commands, ...builtins],
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
|
|
30
65
|
/**
|
|
31
66
|
* Returns a schema suitable for help display, including capability-built-in subtrees.
|
|
32
|
-
* Routing programs get builtins merged;
|
|
67
|
+
* Hidden commands and options are omitted. Routing programs get builtins merged;
|
|
68
|
+
* leaf programs are wrapped as a tiny router.
|
|
33
69
|
*/
|
|
34
70
|
export function cliPresentationRoot(program: CliProgram): CliRouter {
|
|
35
71
|
const caps = resolveCapabilities(program);
|
|
@@ -41,19 +77,23 @@ export function cliPresentationRoot(program: CliProgram): CliRouter {
|
|
|
41
77
|
key: program.key,
|
|
42
78
|
description: program.description,
|
|
43
79
|
notes,
|
|
44
|
-
options: program.options,
|
|
80
|
+
options: visibleOptions(program.options),
|
|
45
81
|
commands: builtins,
|
|
46
82
|
};
|
|
47
83
|
}
|
|
48
84
|
|
|
85
|
+
const userCommands = program.commands
|
|
86
|
+
.map((ch) => presentationNode(ch))
|
|
87
|
+
.filter((ch): ch is CliNode => ch !== null);
|
|
88
|
+
|
|
49
89
|
return {
|
|
50
90
|
key: program.key,
|
|
51
91
|
description: program.description,
|
|
52
92
|
notes,
|
|
53
|
-
options: program.options,
|
|
93
|
+
options: visibleOptions(program.options),
|
|
54
94
|
fallbackCommand: program.fallbackCommand,
|
|
55
95
|
fallbackMode: program.fallbackMode,
|
|
56
|
-
commands: [...
|
|
96
|
+
commands: [...userCommands, ...builtins],
|
|
57
97
|
};
|
|
58
98
|
}
|
|
59
99
|
|
|
@@ -74,4 +114,3 @@ export function presentationRootNotes(program: CliProgram, caps: CliCapabilities
|
|
|
74
114
|
|
|
75
115
|
/** Presentation tree may include builtin leaf stubs. */
|
|
76
116
|
export type CliPresentationNode = CliNode | CliLeaf;
|
|
77
|
-
|
|
@@ -105,3 +105,33 @@ test("generateApiGuide resolves {argsbarg:program} in consumer notes", () => {
|
|
|
105
105
|
const md = generateApiGuide(fixture);
|
|
106
106
|
expect(md).toContain("Invoke `myapp run`.");
|
|
107
107
|
});
|
|
108
|
+
|
|
109
|
+
test("generateApiGuide and cliSchemaExport include leaf outputSchema", () => {
|
|
110
|
+
const fixture: CliProgram = {
|
|
111
|
+
key: "myapp",
|
|
112
|
+
version: "1.0.0",
|
|
113
|
+
description: "Demo app.",
|
|
114
|
+
commands: [
|
|
115
|
+
{
|
|
116
|
+
key: "run",
|
|
117
|
+
description: "Run.",
|
|
118
|
+
outputSchema: {
|
|
119
|
+
type: "object",
|
|
120
|
+
properties: { id: { type: "string" } },
|
|
121
|
+
required: ["id"],
|
|
122
|
+
},
|
|
123
|
+
handler: () => {},
|
|
124
|
+
},
|
|
125
|
+
],
|
|
126
|
+
};
|
|
127
|
+
const schema = cliSchemaExport(fixture);
|
|
128
|
+
expect(schema.commands![0]!.outputSchema).toEqual({
|
|
129
|
+
type: "object",
|
|
130
|
+
properties: { id: { type: "string" } },
|
|
131
|
+
required: ["id"],
|
|
132
|
+
});
|
|
133
|
+
const md = generateApiGuide(fixture);
|
|
134
|
+
expect(md).toContain("#### Output");
|
|
135
|
+
expect(md).toContain('"id"');
|
|
136
|
+
expect(md).toContain('"type": "string"');
|
|
137
|
+
});
|
package/src/docs/api-guide.ts
CHANGED
|
@@ -52,6 +52,20 @@ function formatNotesBlockquote(notes: string, appKey: string): string {
|
|
|
52
52
|
.join("\n");
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
+
/** Markdown section for leaf outputSchema (docs api / skill reference). */
|
|
56
|
+
function formatOutputSchemaSection(schema: Record<string, unknown>): string[] {
|
|
57
|
+
return [
|
|
58
|
+
"#### Output",
|
|
59
|
+
"",
|
|
60
|
+
"JSON Schema for structured stdout (typically with `--json`, or via MCP when the handler emits JSON):",
|
|
61
|
+
"",
|
|
62
|
+
"```json",
|
|
63
|
+
JSON.stringify(schema, null, 2),
|
|
64
|
+
"```",
|
|
65
|
+
"",
|
|
66
|
+
];
|
|
67
|
+
}
|
|
68
|
+
|
|
55
69
|
/** Fallback routing note when present on a router node. */
|
|
56
70
|
function fallbackLine(node: CliSchemaExport): string | null {
|
|
57
71
|
if (node.fallbackCommand === undefined) {
|
|
@@ -103,6 +117,10 @@ function renderCommandNode(
|
|
|
103
117
|
lines.push("");
|
|
104
118
|
}
|
|
105
119
|
|
|
120
|
+
if (node.outputSchema !== undefined) {
|
|
121
|
+
lines.push(...formatOutputSchemaSection(node.outputSchema));
|
|
122
|
+
}
|
|
123
|
+
|
|
106
124
|
const children = node.commands ?? [];
|
|
107
125
|
if (children.length > 0) {
|
|
108
126
|
lines.push("#### Subcommands", "");
|
package/src/help.ts
CHANGED
|
@@ -8,6 +8,7 @@ style no matter how help is reached.
|
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
import { CliNode, CliOption, CliOptionKind, CliPositional, CliRouter, isCliLeaf, isCliRouter } from "./types.ts";
|
|
11
|
+
import { visibleOptions, visibleSubcommands } from "./hidden.ts";
|
|
11
12
|
|
|
12
13
|
// ── ANSI Style Helpers ────────────────────────────────────────────────────────
|
|
13
14
|
|
|
@@ -372,9 +373,9 @@ function rowsForPositionals(defs: CliPositional[], color: boolean): HelpRow[] {
|
|
|
372
373
|
return defs.map((p) => ({ label: cliPositionalLabel(p, color), description: p.description }));
|
|
373
374
|
}
|
|
374
375
|
|
|
375
|
-
/** Table rows for subcommands, sorted by key. */
|
|
376
|
+
/** Table rows for subcommands, sorted by key (hidden commands omitted). */
|
|
376
377
|
function rowsForSubcommands(cmds: CliNode[]): HelpRow[] {
|
|
377
|
-
return cmds
|
|
378
|
+
return visibleSubcommands(cmds)
|
|
378
379
|
.sort((a, b) => a.key.localeCompare(b.key))
|
|
379
380
|
.map((c) => ({ label: c.key, description: c.description }));
|
|
380
381
|
}
|
|
@@ -420,7 +421,7 @@ export function cliHelpRender(schema: CliRouter, helpPath: string[], useStderr:
|
|
|
420
421
|
).join("\n"),
|
|
421
422
|
);
|
|
422
423
|
|
|
423
|
-
const optBox = renderTableBox("Options", rowsForOptions(schema.options
|
|
424
|
+
const optBox = renderTableBox("Options", rowsForOptions(visibleOptions(schema.options), color), hw, color);
|
|
424
425
|
if (optBox.length > 0) {
|
|
425
426
|
lines.push("");
|
|
426
427
|
lines.push(optBox.join("\n"));
|
|
@@ -470,7 +471,7 @@ export function cliHelpRender(schema: CliRouter, helpPath: string[], useStderr:
|
|
|
470
471
|
).join("\n"),
|
|
471
472
|
);
|
|
472
473
|
|
|
473
|
-
const optBox = renderTableBox("Options", rowsForOptions(node.options
|
|
474
|
+
const optBox = renderTableBox("Options", rowsForOptions(visibleOptions(node.options), color), hw, color);
|
|
474
475
|
if (optBox.length > 0) {
|
|
475
476
|
lines.push("");
|
|
476
477
|
lines.push(optBox.join("\n"));
|