argsbarg 3.0.0 → 3.2.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/CHANGELOG.md +28 -1
- package/README.md +6 -6
- package/bun.lock +21 -0
- package/docs/ai-skills.md +8 -4
- package/docs/bundled-docs.md +91 -0
- package/docs/install.md +16 -4
- package/docs/mcp.md +4 -6
- package/examples/minimal.ts +6 -0
- package/examples/nested.ts +6 -0
- package/index.d.ts +46 -1
- package/package.json +4 -1
- package/src/builtins/completion-bash.ts +1 -8
- package/src/builtins/completion-fish.ts +0 -5
- package/src/builtins/completion-zsh.ts +1 -9
- package/src/builtins/dispatch.ts +40 -0
- package/src/builtins/export.ts +9 -0
- package/src/builtins/install.ts +9 -3
- package/src/builtins/presentation.ts +9 -0
- package/src/builtins/shell-helpers.ts +0 -2
- package/src/builtins/update.ts +14 -0
- package/src/capabilities.ts +12 -1
- package/src/docs/api-guide.test.ts +55 -0
- package/src/docs/api-guide.ts +129 -0
- package/src/docs/builtin.ts +61 -0
- package/src/docs/docs.test.ts +167 -0
- package/src/docs/mcp-guide.ts +118 -0
- package/src/docs/resolve.ts +119 -0
- package/src/help.ts +3 -7
- package/src/index.test.ts +40 -66
- package/src/index.ts +4 -0
- package/src/install/binary.ts +8 -3
- package/src/install/index.ts +55 -30
- package/src/install/plan.ts +5 -3
- package/src/install/update.test.ts +106 -0
- package/src/install/update.ts +55 -0
- package/src/invoke.ts +17 -15
- package/src/mcp/tools.ts +1 -1
- package/src/parse.ts +0 -27
- package/src/runtime.ts +12 -6
- package/src/schema.ts +7 -2
- package/src/skill/generate.ts +6 -39
- package/src/types.ts +47 -0
- package/src/validate.ts +53 -6
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,31 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [3.2.0] - 2026-06-20
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- **`docs schema`** — print the full command tree as JSON (`myapp docs schema`). Replaces root `--schema` (requires `docs.enabled`).
|
|
15
|
+
- **`docs api`** — print the command tree as markdown (`myapp docs api`). Human-readable companion to `docs schema`.
|
|
16
|
+
- **`docs skill`** — print generated Cursor `SKILL.md` content to stdout (`myapp docs skill`).
|
|
17
|
+
- **`update` built-in** — when `install.updateGetLatest` is set, `myapp update` downloads the latest binary and reinstalls installed artifacts.
|
|
18
|
+
- **`install --reinstall`** — replaces `--update` (still accepted as a deprecated alias). Optional `--from <path>` for the binary source.
|
|
19
|
+
|
|
20
|
+
### Changed
|
|
21
|
+
|
|
22
|
+
- **Breaking:** root **`--schema`** removed — use **`docs schema`** when `docs.enabled` is `true`.
|
|
23
|
+
- **Breaking:** **`install --update`** renamed to **`install --reinstall`**.
|
|
24
|
+
|
|
25
|
+
## [3.1.0] - 2026-06-20
|
|
26
|
+
|
|
27
|
+
### Added
|
|
28
|
+
|
|
29
|
+
- **`docs` built-in** — opt in with `docs: { enabled: true, topics: { ... } }` on the program root. Bundled markdown topics on stdout (`myapp docs`, `myapp docs readme`, `myapp docs all`). Auto **`docs mcp`** guide when `docs` and `mcpServer` are both enabled. See [docs/bundled-docs.md](docs/bundled-docs.md).
|
|
30
|
+
|
|
31
|
+
### Changed
|
|
32
|
+
|
|
33
|
+
- **Agent skills** — `SKILL.md` is shell-only (removed MCP setup, `mcp.json`, and `tools/call` content). Use `docs mcp` or MCP tools for agent execution guidance.
|
|
34
|
+
|
|
10
35
|
## [3.0.0] - 2026-06-20
|
|
11
36
|
|
|
12
37
|
### Added
|
|
@@ -198,7 +223,9 @@ const cli = { ... } satisfies CliProgram; // or : CliProgram
|
|
|
198
223
|
- 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`).
|
|
199
224
|
- Imports: use `CliPositional` where needed; replace `CliOptionDef` with `CliOption` or `CliPositional` as appropriate.
|
|
200
225
|
|
|
201
|
-
[Unreleased]: https://github.com/bdombro/bun-argsbarg/compare/v3.
|
|
226
|
+
[Unreleased]: https://github.com/bdombro/bun-argsbarg/compare/v3.2.0...HEAD
|
|
227
|
+
[3.2.0]: https://github.com/bdombro/bun-argsbarg/releases/tag/v3.2.0
|
|
228
|
+
[3.1.0]: https://github.com/bdombro/bun-argsbarg/releases/tag/v3.1.0
|
|
202
229
|
[3.0.0]: https://github.com/bdombro/bun-argsbarg/releases/tag/v3.0.0
|
|
203
230
|
[2.1.1]: https://github.com/bdombro/bun-argsbarg/releases/tag/v2.1.1
|
|
204
231
|
[2.1.0]: https://github.com/bdombro/bun-argsbarg/releases/tag/v2.1.0
|
package/README.md
CHANGED
|
@@ -95,20 +95,20 @@ Everything you need for a first-class CLI:
|
|
|
95
95
|
Every app gets:
|
|
96
96
|
|
|
97
97
|
- `-h` / `--help` at any routing depth (scoped help).
|
|
98
|
-
- **`--schema`** at the program root — print the full command tree as JSON (for tooling and agents).
|
|
99
98
|
- **`completion bash` / `completion zsh` / `completion fish`** — print shell completion scripts to stdout (injected by `cliRun`).
|
|
100
99
|
- **`version`** — print `CliProgram.version` (`myapp version`).
|
|
101
100
|
- **`mcp`** — when `mcpServer.enabled` is `true`, run as an MCP stdio server (`myapp mcp`).
|
|
101
|
+
- **`docs`** — when `docs.enabled` is `true`, print bundled markdown topics, schema JSON, API markdown, and generated skill content (`myapp docs`, `myapp docs readme`, `myapp docs schema`, `myapp docs api`, `myapp docs skill`, …). See [docs/bundled-docs.md](docs/bundled-docs.md).
|
|
102
102
|
- **`install`** — install the binary, completions, skills, and MCP config to the user environment (`myapp install --all --yes`). See [docs/install.md](docs/install.md).
|
|
103
103
|
|
|
104
104
|
Do not declare a top-level command named **`completion`**, **`version`**, or **`install`** — they are reserved.
|
|
105
105
|
When **`mcpServer.enabled`** is `true`, do not declare a top-level command named **`mcp`** — it is reserved for the MCP built-in.
|
|
106
|
-
|
|
106
|
+
When **`docs.enabled`** is `true`, do not declare a top-level command named **`docs`** — it is reserved for the docs built-in.
|
|
107
107
|
|
|
108
108
|
|
|
109
109
|
### MCP (AI agents)
|
|
110
110
|
|
|
111
|
-
Opt in on the program root with `mcpServer: { enabled: true }`, then run `myapp mcp` for a stdio MCP server. Each leaf command becomes a tool; the CLI tree is available as resource `<sanitized-key>://schema` (same as `myapp
|
|
111
|
+
Opt in on the program root with `mcpServer: { enabled: true }`, then run `myapp mcp` for a stdio MCP server. Each leaf command becomes a tool; the CLI tree is available as resource `<sanitized-key>://schema` (same as `myapp docs schema`). Handlers can read `ctx.invocation` and use `cliInvoke` for headless testing.
|
|
112
112
|
|
|
113
113
|
See **[docs/mcp.md](docs/mcp.md)** for configuration, env bootstrapping, custom resources, Cursor setup, and protocol details.
|
|
114
114
|
|
|
@@ -122,7 +122,7 @@ myapp install --all --yes
|
|
|
122
122
|
|
|
123
123
|
This copies the binary to `~/.local/bin`, installs shell completions (bash/zsh/fish when each shell is on PATH), writes Cursor/Claude skills when agent directories exist, and merges MCP server entries into Cursor and Claude config files.
|
|
124
124
|
|
|
125
|
-
See **[docs/install.md](docs/install.md)** for `--update`, `--status`, `--uninstall`, and flags.
|
|
125
|
+
See **[docs/install.md](docs/install.md)** for `--reinstall`, `update`, `--status`, `--uninstall`, and flags.
|
|
126
126
|
|
|
127
127
|
|
|
128
128
|
### Shell completions
|
|
@@ -187,7 +187,7 @@ Add `CliPositional` entries to the command’s `positionals` list (separate from
|
|
|
187
187
|
|
|
188
188
|
### Capabilities (built-ins)
|
|
189
189
|
|
|
190
|
-
`completion`, `version`, `install`, and `mcp` are not part of your schema — they are injected at runtime from program-level config (`mcpServer`, `install`). Reserved command names: `completion` and `version` always; `install` unless `install.enabled: false`; `mcp` when `mcpServer.enabled` is `true`.
|
|
190
|
+
`completion`, `version`, `install`, `update`, and `mcp` are not part of your schema — they are injected at runtime from program-level config (`mcpServer`, `install`, `docs`). Reserved command names: `completion` and `version` always; `install` unless `install.enabled: false`; `update` when `install.updateGetLatest` is set; `mcp` when `mcpServer.enabled` is `true`; `docs` when `docs.enabled` is `true`.
|
|
191
191
|
|
|
192
192
|
|
|
193
193
|
|
|
@@ -228,7 +228,7 @@ The package root (`argsbarg` / `src/index.ts`) exports the types and runtime you
|
|
|
228
228
|
| `cliInvoke(root, argv)` | Parse and dispatch without exiting; returns captured stdout/stderr. |
|
|
229
229
|
| `cliErrWithHelp(ctx, msg)` | Print error + scoped help on stderr, exit 1. |
|
|
230
230
|
|
|
231
|
-
Reserved identifiers (validated at startup): root commands **`completion`**, **`version`**, **`install`**, and **`mcp`** (
|
|
231
|
+
Reserved identifiers (validated at startup): root commands **`completion`**, **`version`**, **`install`**, **`docs`** (when `docs.enabled` is `true`), and **`mcp`** (when `mcpServer.enabled` is `true`).
|
|
232
232
|
|
|
233
233
|
---
|
|
234
234
|
|
package/bun.lock
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"lockfileVersion": 1,
|
|
3
|
+
"configVersion": 1,
|
|
4
|
+
"workspaces": {
|
|
5
|
+
"": {
|
|
6
|
+
"name": "argsbarg",
|
|
7
|
+
"devDependencies": {
|
|
8
|
+
"@types/bun": "^1.3.12",
|
|
9
|
+
},
|
|
10
|
+
},
|
|
11
|
+
},
|
|
12
|
+
"packages": {
|
|
13
|
+
"@types/bun": ["@types/bun@1.3.14", "", { "dependencies": { "bun-types": "1.3.14" } }, "sha512-h1hFqFVcvAvD9j9K7ZW7vd82aSA+rTdznZa+5bwvCwqSB1jmmfLcbIWhOLx1/+boy/xmjgCs/OMUL8hRJSmnPw=="],
|
|
14
|
+
|
|
15
|
+
"@types/node": ["@types/node@26.0.0", "", { "dependencies": { "undici-types": "~8.3.0" } }, "sha512-vf2YFi1iY9lHGwNJMs01biZFbKJkrZR1T6/MlzjhJLPdntOHLhTrDSnSVcdtvjihi4VQNlrFRIxLsDBlQpAipA=="],
|
|
16
|
+
|
|
17
|
+
"bun-types": ["bun-types@1.3.14", "", { "dependencies": { "@types/node": "*" } }, "sha512-4N0ig0fEomHt5R0KCFWjovxow98rIoRwKolrYdCcknNwMekCXRnWEUvgu5soYV8QXtVsrUD8B95MBOZGPvr6KQ=="],
|
|
18
|
+
|
|
19
|
+
"undici-types": ["undici-types@8.3.0", "", {}, "sha512-j375ScV60dom+YkPFIfTLcOiPxkN/buHz5GobjLhixFuANaNs3C9l4GmrWqejgXWJ7BbJcFYpTEUkS1Ge8bpZQ=="],
|
|
20
|
+
}
|
|
21
|
+
}
|
package/docs/ai-skills.md
CHANGED
|
@@ -31,17 +31,21 @@ For library use, call `cliSkillInstall(root, "cursor" | "claude", { global: true
|
|
|
31
31
|
|
|
32
32
|
## Generated content
|
|
33
33
|
|
|
34
|
-
- **`SKILL.md`** — YAML frontmatter, when-to-use guidance, command catalog,
|
|
35
|
-
- **`reference.md`** — full
|
|
34
|
+
- **`SKILL.md`** — YAML frontmatter, when-to-use guidance, shell command catalog, pitfalls
|
|
35
|
+
- **`reference.md`** — full `docs schema` JSON export
|
|
36
36
|
|
|
37
|
-
|
|
37
|
+
Skills describe **shell invocation only** — no MCP setup, `mcp.json`, or `tools/call` guidance. Use **`myapp docs mcp`** (when `docs` and `mcpServer` are enabled) or connect the MCP server for agent execution.
|
|
38
|
+
|
|
39
|
+
## MCP vs skills vs docs
|
|
38
40
|
|
|
39
41
|
| Mechanism | Role |
|
|
40
42
|
| --- | --- |
|
|
41
43
|
| **`myapp mcp`** (requires `mcpServer`) | Runtime tool execution over MCP |
|
|
42
|
-
| **`myapp install --skill`** | Static
|
|
44
|
+
| **`myapp install --skill`** | Static shell command catalog for agents |
|
|
45
|
+
| **`myapp docs`** (requires `docs`) | Bundled markdown on stdout (`docs mcp` when MCP enabled) |
|
|
43
46
|
|
|
44
47
|
See also:
|
|
45
48
|
|
|
49
|
+
- [Bundled docs](bundled-docs.md) — `docs` config and compile-time imports
|
|
46
50
|
- [MCP server](mcp.md) — `mcpServer` config and `mcp` protocol
|
|
47
51
|
- [Install](install.md) — binary, completions, skills, and MCP config
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# Bundled documentation (`docs`)
|
|
2
|
+
|
|
3
|
+
ArgsBarg can expose bundled markdown topics as the built-in `docs` command group. Opt in on the program root with `docs: { enabled: true, topics: { ... } }`.
|
|
4
|
+
|
|
5
|
+
## Quick start
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
import readmeText from "../README.md" with { type: "text" };
|
|
9
|
+
import archText from "../docs/architecture.md" with { type: "text" };
|
|
10
|
+
|
|
11
|
+
const cli = {
|
|
12
|
+
key: "myapp",
|
|
13
|
+
version: "1.0.0",
|
|
14
|
+
description: "My app.",
|
|
15
|
+
docs: {
|
|
16
|
+
enabled: true,
|
|
17
|
+
topics: {
|
|
18
|
+
readme: { text: readmeText },
|
|
19
|
+
architecture: { text: archText, description: "Contributor architecture notes." },
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
commands: [/* ... */],
|
|
23
|
+
} satisfies CliProgram;
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
myapp docs # first topic (readme) via fallback
|
|
28
|
+
myapp docs readme
|
|
29
|
+
myapp docs architecture
|
|
30
|
+
myapp docs schema # full command tree as JSON
|
|
31
|
+
myapp docs api # command tree as markdown
|
|
32
|
+
myapp docs skill # generated Cursor SKILL.md
|
|
33
|
+
myapp docs all # all user topics; includes auto mcp when MCP enabled
|
|
34
|
+
myapp docs mcp # auto-generated when mcpServer.enabled
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Configuration
|
|
38
|
+
|
|
39
|
+
| Field | Default | Purpose |
|
|
40
|
+
| --- | --- | --- |
|
|
41
|
+
| `enabled` | *(required)* | Must be `true` when `docs` is set |
|
|
42
|
+
| `description` | `"Print bundled CLI documentation."` | Router help for `myapp docs` |
|
|
43
|
+
| `defaultTopic` | first key in `topics` | `fallbackCommand` for bare `myapp docs` |
|
|
44
|
+
| `topics` | *(required)* | Topic key → `{ text, description? }` |
|
|
45
|
+
|
|
46
|
+
Reserved topic keys in `topics`: **`mcp`**, **`all`**, **`schema`**, **`api`**, **`skill`** (supplied by the built-in).
|
|
47
|
+
|
|
48
|
+
When `description` is omitted on a topic, ArgsBarg generates leaf help (`readme` → "Print README (user guide).").
|
|
49
|
+
|
|
50
|
+
## Compile-time bundling
|
|
51
|
+
|
|
52
|
+
Topic `text` must be **bundled markdown strings**. Use Bun text imports in the consumer module graph:
|
|
53
|
+
|
|
54
|
+
```typescript
|
|
55
|
+
import readmeText from "../README.md" with { type: "text" };
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Bun embeds the file when you `bun build --compile`. ArgsBarg does not read the filesystem at runtime.
|
|
59
|
+
|
|
60
|
+
For several topics, use a barrel file (e.g. `src/docs/topics.ts`) so `index.tsx` stays small.
|
|
61
|
+
|
|
62
|
+
## Schema, API, and skill (`docs schema`, `docs api`, `docs skill`)
|
|
63
|
+
|
|
64
|
+
When `docs.enabled` is `true`:
|
|
65
|
+
|
|
66
|
+
- **`docs schema`** — same JSON as the former root `--schema` flag (handlers omitted; built-in subtrees included for leaf roots).
|
|
67
|
+
- **`docs api`** — markdown rendering of the same command tree (options, positionals, subcommands, fallback routing).
|
|
68
|
+
- **`docs skill`** — prints generated Cursor `SKILL.md` content (same prose as `install --skill`, without writing files).
|
|
69
|
+
|
|
70
|
+
## MCP guide (`docs mcp`)
|
|
71
|
+
|
|
72
|
+
When both `docs.enabled` and `mcpServer.enabled` are `true`, ArgsBarg injects a **`docs mcp`** topic with an auto-generated guide: tool list, `requiresEnv`, schema resource URI, `install --mcp`, and protocol notes.
|
|
73
|
+
|
|
74
|
+
There is no override API in v1 — customize behavior via `mcpTool.description` on leaf commands.
|
|
75
|
+
|
|
76
|
+
## MCP tools
|
|
77
|
+
|
|
78
|
+
All `docs` subcommands are hidden from MCP `tools/list` (`mcpTool: { enabled: false }`).
|
|
79
|
+
|
|
80
|
+
## Skills vs docs vs MCP
|
|
81
|
+
|
|
82
|
+
| Channel | Role |
|
|
83
|
+
| --- | --- |
|
|
84
|
+
| `install --skill` | Writes shell command catalog + `reference.md` to disk |
|
|
85
|
+
| `docs skill` | Print generated `SKILL.md` to stdout |
|
|
86
|
+
| `docs api` | Print command tree markdown to stdout |
|
|
87
|
+
| `docs schema` | Print command tree JSON to stdout |
|
|
88
|
+
| `docs` | Bundled markdown topics on stdout |
|
|
89
|
+
| `mcp` | Callable tools + schema resource |
|
|
90
|
+
|
|
91
|
+
Do not declare a top-level command named **`docs`** when `docs.enabled` is `true` — it is reserved.
|
package/docs/install.md
CHANGED
|
@@ -8,8 +8,11 @@ The `install` built-in installs the binary, shell completions, agent skills, and
|
|
|
8
8
|
# First-time setup
|
|
9
9
|
myapp install --all --yes
|
|
10
10
|
|
|
11
|
-
# Refresh after upgrading
|
|
12
|
-
myapp install --
|
|
11
|
+
# Refresh after upgrading (re-copy running binary + refresh installed artifacts)
|
|
12
|
+
myapp install --reinstall
|
|
13
|
+
|
|
14
|
+
# Download latest release (when install.updateGetLatest is configured)
|
|
15
|
+
myapp update
|
|
13
16
|
|
|
14
17
|
# See what is installed
|
|
15
18
|
myapp install --status
|
|
@@ -42,9 +45,15 @@ On the program root:
|
|
|
42
45
|
install: {
|
|
43
46
|
enabled: false, // opt out of the install built-in
|
|
44
47
|
prefix: "~/.local/bin", // default bin directory
|
|
48
|
+
updateGetLatest: async ({ version }) => {
|
|
49
|
+
// download or locate latest binary; return { path, version, cleanup }
|
|
50
|
+
return { path: "/tmp/myapp", version: "2.0.0" };
|
|
51
|
+
},
|
|
45
52
|
}
|
|
46
53
|
```
|
|
47
54
|
|
|
55
|
+
When `updateGetLatest` is set, ArgsBarg also registers the **`update`** built-in (`myapp update`).
|
|
56
|
+
|
|
48
57
|
Environment:
|
|
49
58
|
|
|
50
59
|
- `INSTALL_PREFIX` — same as `install.prefix` / `--prefix`
|
|
@@ -53,15 +62,18 @@ Environment:
|
|
|
53
62
|
|
|
54
63
|
| Flag | Description |
|
|
55
64
|
| --- | --- |
|
|
56
|
-
| `--yes` | Skip confirmation (required for non-TTY unless `--json` / `--
|
|
65
|
+
| `--yes` | Skip confirmation (required for non-TTY unless `--json` / `--reinstall`) |
|
|
57
66
|
| `--dry` | Preview changes; per-step messages on stderr with `[dry run]` |
|
|
58
67
|
| `--json` | Machine-readable output on stdout (implies `--yes`) |
|
|
59
68
|
| `--quiet` | Suppress summaries and per-step messages (requires `--yes`) |
|
|
60
69
|
| `--prefix <dir>` | Override binary install directory |
|
|
61
|
-
| `--
|
|
70
|
+
| `--reinstall` | Reinstall artifacts already on disk (implies `--bin` + `--yes`) |
|
|
71
|
+
| `--from <path>` | Binary to copy with `--reinstall` (default: running executable) |
|
|
62
72
|
| `--status` | Read-only inventory |
|
|
63
73
|
| `--uninstall` | Remove detected artifacts (scope with `--bin`, `--completions`, `--skill`, `--mcp`) |
|
|
64
74
|
|
|
75
|
+
`--update` is accepted as a deprecated alias for `--reinstall`.
|
|
76
|
+
|
|
65
77
|
## MCP merge behavior
|
|
66
78
|
|
|
67
79
|
When `--mcp` runs, entries are merged into `mcpServers[<sanitized-key>]` with:
|
package/docs/mcp.md
CHANGED
|
@@ -113,7 +113,7 @@ Each tool’s `description` includes the human CLI path and the leaf’s help te
|
|
|
113
113
|
|
|
114
114
|
### Per-leaf visibility
|
|
115
115
|
|
|
116
|
-
Set `mcpTool: { enabled: false }` on a **leaf command** to hide it from `tools/list` while keeping it in the CLI and in
|
|
116
|
+
Set `mcpTool: { enabled: false }` on a **leaf command** to hide it from `tools/list` while keeping it in the CLI and in `docs schema` output:
|
|
117
117
|
|
|
118
118
|
```typescript
|
|
119
119
|
{
|
|
@@ -172,11 +172,11 @@ On success (`isError: false`):
|
|
|
172
172
|
|
|
173
173
|
On failure (parse error, validation error, non-zero exit, thrown error), the message is returned as text content with `isError: true`. Handler stderr is included when present.
|
|
174
174
|
|
|
175
|
-
Help and
|
|
175
|
+
Help and `docs schema` are not available through tool calls; use the schema resource or run the CLI directly for those.
|
|
176
176
|
|
|
177
177
|
## Schema and custom resources
|
|
178
178
|
|
|
179
|
-
The built-in schema resource (default URI `<sanitized-key>://schema`, e.g. `nested.ts` → `nested_ts://schema`) exposes your full CLI tree as JSON — the same output as `myapp
|
|
179
|
+
The built-in schema resource (default URI `<sanitized-key>://schema`, e.g. `nested.ts` → `nested_ts://schema`) exposes your full CLI tree as JSON — the same output as `myapp docs schema`. Override with `schemaResourceUri` if needed.
|
|
180
180
|
|
|
181
181
|
| Property | Value |
|
|
182
182
|
| --- | --- |
|
|
@@ -291,9 +291,7 @@ You should get one JSON line on stdout with `result.capabilities` and `result.se
|
|
|
291
291
|
|
|
292
292
|
When MCP is enabled:
|
|
293
293
|
|
|
294
|
-
- Do not declare a top-level command named **`ai`** — it is reserved for the built-in AI integration group.
|
|
295
294
|
- Do not declare a top-level command named **`completion`** — reserved for shell completions.
|
|
296
|
-
- Do not declare an option named **`schema`** — reserved for `--schema`.
|
|
297
295
|
|
|
298
296
|
Running `myapp mcp` without `mcpServer` on the root fails with an error (exit 1).
|
|
299
297
|
|
|
@@ -304,4 +302,4 @@ Running `myapp mcp` without `mcpServer` on the root fails with an error (exit 1)
|
|
|
304
302
|
- **User schema only** — tool dispatch uses your program root, not merged presentation builtins.
|
|
305
303
|
- **Buffered output** — MCP tool results are sent after the handler finishes. Incremental stdout (log tail, progress) is not streamed; a future release may add MCP progress notifications.
|
|
306
304
|
|
|
307
|
-
For the
|
|
305
|
+
For the `docs schema` export used by the resource, see [docs/bundled-docs.md](bundled-docs.md).
|
package/examples/minimal.ts
CHANGED
package/examples/nested.ts
CHANGED
|
@@ -15,6 +15,12 @@ const cli = {
|
|
|
15
15
|
version: pkg.version,
|
|
16
16
|
description: "Nested groups demo.",
|
|
17
17
|
mcpServer: { enabled: true },
|
|
18
|
+
docs: {
|
|
19
|
+
enabled: true,
|
|
20
|
+
topics: {
|
|
21
|
+
readme: { text: "# nested.ts\n\nNested groups demo.\n" },
|
|
22
|
+
},
|
|
23
|
+
},
|
|
18
24
|
commands: [
|
|
19
25
|
{
|
|
20
26
|
key: "stat",
|
package/index.d.ts
CHANGED
|
@@ -167,11 +167,54 @@ export interface CliMcpToolConfig {
|
|
|
167
167
|
/**
|
|
168
168
|
* Opt-out and defaults for the `install` built-in (program root only).
|
|
169
169
|
*/
|
|
170
|
+
export interface CliUpdateArtifact {
|
|
171
|
+
/** Path to an executable binary to copy into the install location. */
|
|
172
|
+
path: string;
|
|
173
|
+
/** Release version of `path` (used for already-current checks and success messages). */
|
|
174
|
+
version?: string;
|
|
175
|
+
/** Called after reinstall completes (e.g. remove a temp download directory). */
|
|
176
|
+
cleanup?: () => void | Promise<void>;
|
|
177
|
+
}
|
|
178
|
+
/** Fetches the latest release binary for the `update` built-in. */
|
|
179
|
+
export type CliUpdateGetLatest = (ctx: {
|
|
180
|
+
version: string;
|
|
181
|
+
}) => Promise<CliUpdateArtifact>;
|
|
170
182
|
export interface CliInstallConfig {
|
|
171
183
|
/** When `false`, hide/disable `install` (default: enabled). */
|
|
172
184
|
enabled?: boolean;
|
|
173
185
|
/** Default bin directory (default: `~/.local/bin`). Overridden by `INSTALL_PREFIX` env and `--prefix`. */
|
|
174
186
|
prefix?: string;
|
|
187
|
+
/**
|
|
188
|
+
* When set, enables the `update` built-in (`myapp update`).
|
|
189
|
+
* Should download or locate the latest release binary and return its path.
|
|
190
|
+
*/
|
|
191
|
+
updateGetLatest?: CliUpdateGetLatest;
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* One bundled documentation topic for the `docs` built-in (program root only).
|
|
195
|
+
*/
|
|
196
|
+
export interface CliDocsTopic {
|
|
197
|
+
/** Bundled markdown (use compile-time text imports in the consumer). */
|
|
198
|
+
text: string;
|
|
199
|
+
/** Leaf help text for `myapp docs <key> -h`. Auto-generated from key when omitted. */
|
|
200
|
+
description?: string;
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* Enables `myapp docs` and bundled markdown topics (program root only).
|
|
204
|
+
* Must include `enabled: true`; omit `docs` entirely to disable.
|
|
205
|
+
*/
|
|
206
|
+
export interface CliDocsConfig {
|
|
207
|
+
/** When `true`, enables the `docs` built-in command group. */
|
|
208
|
+
enabled: boolean;
|
|
209
|
+
/** Router description for `myapp docs` (default: "Print bundled CLI documentation."). */
|
|
210
|
+
description?: string;
|
|
211
|
+
/**
|
|
212
|
+
* Subcommand for bare `myapp docs` (maps to router `fallbackCommand`).
|
|
213
|
+
* When omitted, uses the first key in `topics` (insertion order).
|
|
214
|
+
*/
|
|
215
|
+
defaultTopic?: string;
|
|
216
|
+
/** Topic key → bundled markdown. Reserved keys: `mcp`, `all` (supplied by the built-in). */
|
|
217
|
+
topics: Record<string, CliDocsTopic>;
|
|
175
218
|
}
|
|
176
219
|
/**
|
|
177
220
|
* Base properties shared by all nodes in the user command tree.
|
|
@@ -223,6 +266,8 @@ export type CliProgram = CliNode & {
|
|
|
223
266
|
mcpServer?: CliMcpServerConfig;
|
|
224
267
|
/** Opt-out and defaults for `install`. */
|
|
225
268
|
install?: CliInstallConfig;
|
|
269
|
+
/** When set with `enabled: true`, enables the `docs` built-in command group. */
|
|
270
|
+
docs?: CliDocsConfig;
|
|
226
271
|
};
|
|
227
272
|
/**
|
|
228
273
|
* Handler closure type for leaf commands.
|
|
@@ -237,7 +282,7 @@ export declare class CliSchemaValidationError extends Error {
|
|
|
237
282
|
constructor(message: string);
|
|
238
283
|
}
|
|
239
284
|
/** Outcome of a non-exiting CLI invocation. */
|
|
240
|
-
export type CliInvokeKind = "ok" | "help" | "
|
|
285
|
+
export type CliInvokeKind = "ok" | "help" | "error";
|
|
241
286
|
/** Result of cliInvoke: captured output and exit metadata without process.exit. */
|
|
242
287
|
export interface CliInvokeResult {
|
|
243
288
|
/** Invocation outcome. */
|
package/package.json
CHANGED
|
@@ -5,7 +5,6 @@ import {
|
|
|
5
5
|
identToken,
|
|
6
6
|
kHelpLong,
|
|
7
7
|
kHelpShort,
|
|
8
|
-
kSchemaLong,
|
|
9
8
|
mainName,
|
|
10
9
|
} from "./shell-helpers.ts";
|
|
11
10
|
|
|
@@ -17,9 +16,6 @@ function emitConsumeLong(ident: string, scopes: ScopeRec[]): string {
|
|
|
17
16
|
o += " " + i + ")\n";
|
|
18
17
|
o += " case $w in\n";
|
|
19
18
|
o += " " + kHelpLong + "|${kHelpLong}=*|${kHelpShort}) echo 1 ;;\n".replace(/\$\{kHelpLong\}/g, kHelpLong).replace(/\$\{kHelpShort\}/g, kHelpShort);
|
|
20
|
-
if (sc.path === "") {
|
|
21
|
-
o += " " + kSchemaLong + ") echo 1 ;;\n";
|
|
22
|
-
}
|
|
23
19
|
for (const op of sc.opts) {
|
|
24
20
|
const base = "--" + op.name;
|
|
25
21
|
if (op.kind === "presence") {
|
|
@@ -107,7 +103,7 @@ function emitSimulate(ident: string): string {
|
|
|
107
103
|
o += " local i=1 sid=0 w steps next\n";
|
|
108
104
|
o += " while (( i < COMP_CWORD )); do\n";
|
|
109
105
|
o += " w=\"${COMP_WORDS[i]}\"\n";
|
|
110
|
-
o += " if [[ $w == " + kHelpShort + " || $w == " + kHelpLong + "
|
|
106
|
+
o += " if [[ $w == " + kHelpShort + " || $w == " + kHelpLong + " ]]; then\n";
|
|
111
107
|
o += " ((i++)); continue\n";
|
|
112
108
|
o += " fi\n";
|
|
113
109
|
o += " if [[ $w == --* ]]; then\n";
|
|
@@ -209,9 +205,6 @@ export function completionBashScript(schema: CliRouter): string {
|
|
|
209
205
|
for (const [i, sc] of scopes.entries()) {
|
|
210
206
|
out += "A_" + ident + "_" + i + "_opts=()\n";
|
|
211
207
|
out += "A_" + ident + "_" + i + "_opts+=('" + kHelpLong + "' '" + kHelpShort + "')\n";
|
|
212
|
-
if (sc.path === "") {
|
|
213
|
-
out += "A_" + ident + "_" + i + "_opts+=('" + kSchemaLong + "')\n";
|
|
214
|
-
}
|
|
215
208
|
for (const o of sc.opts) {
|
|
216
209
|
out += "A_" + ident + "_" + i + "_opts+=('--" + o.name + "')\n";
|
|
217
210
|
if (o.shortName) {
|
|
@@ -5,8 +5,6 @@ import {
|
|
|
5
5
|
identToken,
|
|
6
6
|
kHelpLong,
|
|
7
7
|
kHelpShort,
|
|
8
|
-
kSchemaDesc,
|
|
9
|
-
kSchemaLong,
|
|
10
8
|
} from "./shell-helpers.ts";
|
|
11
9
|
|
|
12
10
|
function scopeCondition(ident: string, scopeIndex: number, path: string): string {
|
|
@@ -43,9 +41,6 @@ export function completionFishScript(schema: CliRouter): string {
|
|
|
43
41
|
}
|
|
44
42
|
|
|
45
43
|
out += `complete -c ${app} -n '${cond}' -s h -l help -d '${escFishSingleQuoted("Show help for this command.")}'\n`;
|
|
46
|
-
if (sc.path === "") {
|
|
47
|
-
out += `complete -c ${app} -n '${cond}' -l schema -d '${escFishSingleQuoted(kSchemaDesc)}'\n`;
|
|
48
|
-
}
|
|
49
44
|
|
|
50
45
|
for (const op of sc.opts) {
|
|
51
46
|
if (op.kind === CliOptionKind.Presence) {
|
|
@@ -5,8 +5,6 @@ import {
|
|
|
5
5
|
identToken,
|
|
6
6
|
kHelpLong,
|
|
7
7
|
kHelpShort,
|
|
8
|
-
kSchemaDesc,
|
|
9
|
-
kSchemaLong,
|
|
10
8
|
mainName,
|
|
11
9
|
} from "./shell-helpers.ts";
|
|
12
10
|
|
|
@@ -16,9 +14,6 @@ function emitScopeArraysZsh(ident: string, scopes: ScopeRec[]): string {
|
|
|
16
14
|
out += "typeset -g A_" + ident + "_" + i + "_opts\n";
|
|
17
15
|
out += "A_" + ident + "_" + i + "_opts=(";
|
|
18
16
|
out += "'" + escShellSingleQuoted(kHelpLong) + ":" + escShellSingleQuoted("Show help for this command.") + "' '" + escShellSingleQuoted(kHelpShort) + ":" + escShellSingleQuoted("Show help for this command.") + "'";
|
|
19
|
-
if (sc.path === "") {
|
|
20
|
-
out += " '" + escShellSingleQuoted(kSchemaLong) + ":" + escShellSingleQuoted(kSchemaDesc) + "'";
|
|
21
|
-
}
|
|
22
17
|
for (const o of sc.opts) {
|
|
23
18
|
out += " '" + escShellSingleQuoted("--" + o.name) + ":" + escShellSingleQuoted(o.description) + "'";
|
|
24
19
|
if (o.shortName) {
|
|
@@ -47,9 +42,6 @@ function emitConsumeLongZsh(ident: string, scopes: ScopeRec[]): string {
|
|
|
47
42
|
o += " " + i + ")\n";
|
|
48
43
|
o += " case $w in\n";
|
|
49
44
|
o += " " + kHelpLong + "|${kHelpLong}=*|${kHelpShort}) echo 1 ;;\n".replace(/\$\{kHelpLong\}/g, kHelpLong).replace(/\$\{kHelpShort\}/g, kHelpShort);
|
|
50
|
-
if (sc.path === "") {
|
|
51
|
-
o += " " + kSchemaLong + ") echo 1 ;;\n";
|
|
52
|
-
}
|
|
53
45
|
for (const op of sc.opts) {
|
|
54
46
|
const base = "--" + op.name;
|
|
55
47
|
if (op.kind === "presence") {
|
|
@@ -137,7 +129,7 @@ function emitSimulateZsh(ident: string): string {
|
|
|
137
129
|
o += " local i=2 sid=0 w steps next\n";
|
|
138
130
|
o += " while (( i < CURRENT )); do\n";
|
|
139
131
|
o += " w=$words[i]\n";
|
|
140
|
-
o += " if [[ $w == " + kHelpShort + " || $w == " + kHelpLong + "
|
|
132
|
+
o += " if [[ $w == " + kHelpShort + " || $w == " + kHelpLong + " ]]; then\n";
|
|
141
133
|
o += " ((i++)); continue\n";
|
|
142
134
|
o += " fi\n";
|
|
143
135
|
o += " if [[ $w == --* ]]; then\n";
|
package/src/builtins/dispatch.ts
CHANGED
|
@@ -6,11 +6,14 @@ import { completionFishScript } from "./completion-fish.ts";
|
|
|
6
6
|
import { completionZshScript } from "./completion-zsh.ts";
|
|
7
7
|
import { cliBuiltinInstallCommand } from "./install.ts";
|
|
8
8
|
import { cliBuiltinMcpCommand } from "./mcp.ts";
|
|
9
|
+
import { cliBuiltinUpdateCommand } from "./update.ts";
|
|
9
10
|
import { cliBuiltinVersionCommand } from "./version.ts";
|
|
10
11
|
import { cliBuiltinCompletionGroup as completionGroup } from "./completion-group.ts";
|
|
11
12
|
import { cliPresentationRoot } from "./presentation.ts";
|
|
13
|
+
import { cliBuiltinDocsGroupIfEnabled } from "../docs/builtin.ts";
|
|
12
14
|
import { cliMcpServeStdio } from "../mcp.ts";
|
|
13
15
|
import { cliInstall } from "../install/index.ts";
|
|
16
|
+
import { cliUpdate } from "../install/update.ts";
|
|
14
17
|
import type { ParseResult } from "../parse.ts";
|
|
15
18
|
import { ParseKind } from "../parse.ts";
|
|
16
19
|
|
|
@@ -79,6 +82,20 @@ export async function dispatchBuiltin(
|
|
|
79
82
|
process.exit(0);
|
|
80
83
|
}
|
|
81
84
|
|
|
85
|
+
if (pr.path[0] === "update") {
|
|
86
|
+
if (!caps.update) {
|
|
87
|
+
process.stderr.write(
|
|
88
|
+
"update is not enabled. Set install.updateGetLatest on the program root.\n",
|
|
89
|
+
);
|
|
90
|
+
process.exit(1);
|
|
91
|
+
}
|
|
92
|
+
if (pr.path.length !== 1) {
|
|
93
|
+
process.stderr.write("Unknown subcommand: update " + pr.path.slice(1).join(" ") + "\n");
|
|
94
|
+
process.exit(1);
|
|
95
|
+
}
|
|
96
|
+
await cliUpdate(program);
|
|
97
|
+
}
|
|
98
|
+
|
|
82
99
|
if (pr.path[0] === "install") {
|
|
83
100
|
if (!caps.install) {
|
|
84
101
|
process.stderr.write("install is disabled. Remove install.enabled: false from the program root.\n");
|
|
@@ -126,6 +143,17 @@ export function builtinInterceptRoot(
|
|
|
126
143
|
};
|
|
127
144
|
}
|
|
128
145
|
|
|
146
|
+
if (first === "update" && caps.update) {
|
|
147
|
+
return {
|
|
148
|
+
parseRoot: {
|
|
149
|
+
key: program.key,
|
|
150
|
+
description: program.description,
|
|
151
|
+
commands: [cliBuiltinUpdateCommand(program)],
|
|
152
|
+
},
|
|
153
|
+
isLeafCompletionIntercept: false,
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
|
|
129
157
|
if (first === "mcp" && caps.mcp) {
|
|
130
158
|
return {
|
|
131
159
|
parseRoot: {
|
|
@@ -148,5 +176,17 @@ export function builtinInterceptRoot(
|
|
|
148
176
|
};
|
|
149
177
|
}
|
|
150
178
|
|
|
179
|
+
const docsGroup = cliBuiltinDocsGroupIfEnabled(program);
|
|
180
|
+
if (first === "docs" && docsGroup) {
|
|
181
|
+
return {
|
|
182
|
+
parseRoot: {
|
|
183
|
+
key: program.key,
|
|
184
|
+
description: program.description,
|
|
185
|
+
commands: [docsGroup],
|
|
186
|
+
},
|
|
187
|
+
isLeafCompletionIntercept: false,
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
|
|
151
191
|
return { parseRoot: program, isLeafCompletionIntercept: false };
|
|
152
192
|
}
|
package/src/builtins/export.ts
CHANGED
|
@@ -3,7 +3,9 @@ import type { CliFallbackMode, CliOption, CliPositional, CliProgram } from "../t
|
|
|
3
3
|
import { cliBuiltinCompletionGroup } from "./completion-group.ts";
|
|
4
4
|
import { cliBuiltinInstallCommand } from "./install.ts";
|
|
5
5
|
import { cliBuiltinMcpCommand } from "./mcp.ts";
|
|
6
|
+
import { cliBuiltinUpdateCommand } from "./update.ts";
|
|
6
7
|
import { cliBuiltinVersionCommand } from "./version.ts";
|
|
8
|
+
import { cliBuiltinDocsGroupIfEnabled } from "../docs/builtin.ts";
|
|
7
9
|
|
|
8
10
|
/** JSON-safe command node (no handlers). */
|
|
9
11
|
export interface CliSchemaExport {
|
|
@@ -50,6 +52,13 @@ export function exportPresentationBuiltins(program: CliProgram, caps?: CliCapabi
|
|
|
50
52
|
if (resolved.install) {
|
|
51
53
|
builtins.push(exportBuiltinNode(cliBuiltinInstallCommand(program)));
|
|
52
54
|
}
|
|
55
|
+
if (resolved.update) {
|
|
56
|
+
builtins.push(exportBuiltinNode(cliBuiltinUpdateCommand(program)));
|
|
57
|
+
}
|
|
58
|
+
const docsGroup = cliBuiltinDocsGroupIfEnabled(program);
|
|
59
|
+
if (docsGroup) {
|
|
60
|
+
builtins.push(exportBuiltinNode(docsGroup));
|
|
61
|
+
}
|
|
53
62
|
if (resolved.mcp) {
|
|
54
63
|
builtins.push(exportBuiltinNode(cliBuiltinMcpCommand()));
|
|
55
64
|
}
|
package/src/builtins/install.ts
CHANGED
|
@@ -26,10 +26,15 @@ export function installBuiltinOptions(root: CliProgram): CliOption[] {
|
|
|
26
26
|
kind: CliOptionKind.Presence,
|
|
27
27
|
},
|
|
28
28
|
{
|
|
29
|
-
name: "
|
|
30
|
-
description: "
|
|
29
|
+
name: "reinstall",
|
|
30
|
+
description: "Reinstall artifacts already on disk (always includes the binary).",
|
|
31
31
|
kind: CliOptionKind.Presence,
|
|
32
32
|
},
|
|
33
|
+
{
|
|
34
|
+
name: "from",
|
|
35
|
+
description: "Binary to copy (default: running executable). Used with --reinstall.",
|
|
36
|
+
kind: CliOptionKind.String,
|
|
37
|
+
},
|
|
33
38
|
{
|
|
34
39
|
name: "status",
|
|
35
40
|
description: "Print what is currently installed (read-only).",
|
|
@@ -87,7 +92,8 @@ export function cliBuiltinInstallCommand(root: CliProgram): CliLeaf {
|
|
|
87
92
|
"First-time setup:\n" +
|
|
88
93
|
` {app} install --all --yes\n\n` +
|
|
89
94
|
"Refresh after upgrading:\n" +
|
|
90
|
-
` {app} install --
|
|
95
|
+
` {app} install --reinstall\n` +
|
|
96
|
+
` {app} update\n\n` +
|
|
91
97
|
"See what is installed:\n" +
|
|
92
98
|
` {app} install --status\n\n` +
|
|
93
99
|
"Remove everything:\n" +
|