argsbarg 3.4.2 → 3.6.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 +31 -1
- package/README.md +24 -8
- package/biome.json +29 -6
- package/bun.lock +22 -0
- package/docs/cli-program.md +75 -1
- package/docs/install.md +1 -1
- package/docs/mcp.md +45 -1
- package/docs/templates/cursor/rules/cli-program.mdc +15 -21
- package/index.d.ts +95 -50
- package/justfile +24 -6
- package/package.json +4 -2
- package/scripts/release.ts +26 -9
- package/src/builtins/builtins.test.ts +9 -4
- package/src/builtins/completion-bash.ts +74 -50
- package/src/builtins/completion-fish.ts +3 -8
- package/src/builtins/completion-group.ts +1 -1
- package/src/builtins/completion-zsh.ts +80 -42
- package/src/builtins/dispatch.ts +20 -16
- package/src/builtins/export.ts +19 -10
- package/src/builtins/index.ts +9 -4
- package/src/builtins/install.ts +10 -10
- package/src/builtins/mcp.ts +1 -1
- package/src/builtins/presentation.ts +8 -8
- package/src/builtins/scopes.ts +1 -1
- package/src/builtins/version.ts +1 -1
- package/src/completion.ts +4 -4
- package/src/context.ts +91 -15
- package/src/docs/api-guide.test.ts +2 -2
- package/src/docs/api-guide.ts +19 -5
- package/src/docs/builtin.ts +27 -8
- package/src/docs/docs.test.ts +18 -11
- package/src/docs/mcp-guide.ts +108 -25
- package/src/docs/resolve.ts +10 -3
- package/src/docs/save.ts +11 -3
- package/src/formats.test.ts +35 -0
- package/src/formats.ts +135 -0
- package/src/headless.test.ts +8 -16
- package/src/help.ts +73 -43
- package/src/hidden-mcpb.test.ts +7 -6
- package/src/hidden.ts +2 -2
- package/src/index.test.ts +120 -96
- package/src/index.ts +36 -24
- package/src/install/binary.ts +12 -5
- package/src/install/completions.ts +7 -3
- package/src/install/detect-installed.ts +29 -4
- package/src/install/gh-release-update.ts +31 -23
- package/src/install/index.ts +69 -19
- package/src/install/install.test.ts +31 -8
- package/src/install/mcp-codex.test.ts +57 -0
- package/src/install/mcp-codex.ts +125 -0
- package/src/install/mcp-config.ts +12 -5
- package/src/install/mcp-opencode.test.ts +98 -0
- package/src/install/mcp-opencode.ts +149 -0
- package/src/install/paths.ts +29 -3
- package/src/install/plan.ts +73 -6
- package/src/install/shell.ts +1 -4
- package/src/install/status.ts +12 -6
- package/src/install/uninstall.ts +38 -4
- package/src/install/update.test.ts +2 -2
- package/src/install/update.ts +3 -1
- package/src/invoke.ts +12 -9
- package/src/mcp/bundle.ts +36 -8
- package/src/mcp/env.ts +7 -13
- package/src/mcp/server.ts +12 -6
- package/src/mcp/tools.ts +83 -18
- package/src/mcp.ts +3 -3
- package/src/parse.ts +129 -27
- package/src/runtime.ts +22 -12
- package/src/schema.ts +11 -5
- package/src/skill/generate.ts +4 -4
- package/src/skill/install.ts +6 -2
- package/src/types.ts +24 -0
- package/src/validate.ts +75 -16
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,34 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [3.6.0] - 2026-06-23
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- **`CliValueFormat`** — optional `format` on string options: `duration`, `comma-list`, `date`, `date-time`; optional `default` and `pattern` (mutually exclusive with `format`).
|
|
15
|
+
- **`CliContext`** — `durationOpt`, `commaListOpt`, `dateOpt`, `dateTimeOpt`, and `readLeafInputs()` for schema-driven handler reads.
|
|
16
|
+
- **`formats` exports** — `parseDurationMs`, `parseCommaList`, `parseDate`, `parseDateTime` for reuse outside handlers.
|
|
17
|
+
|
|
18
|
+
### Changed
|
|
19
|
+
|
|
20
|
+
- **Post-parse validation** — applies option `default` values and validates `format` / `pattern` before handlers run.
|
|
21
|
+
- **MCP varargs** — `tools/call` positional arrays must be JSON arrays (comma-separated strings no longer accepted).
|
|
22
|
+
- **MCP comma-list options** — `format: comma-list` accepts string or array in `tools/call`.
|
|
23
|
+
- **`docs mcp`**, **`docs api`**, and **`docs/cli-program.md`** — document value formats and varargs policy.
|
|
24
|
+
- **Cursor rule template** (`docs/templates/cursor/rules/cli-program.mdc`) — thin tripwire that directs agents to read `node_modules/argsbarg/docs/cli-program.md` instead of duplicating authoring guidance.
|
|
25
|
+
|
|
26
|
+
## [3.5.0] - 2026-06-22
|
|
27
|
+
|
|
28
|
+
### Added
|
|
29
|
+
|
|
30
|
+
- **`install --mcp`** — OpenCode: merges local MCP entry into `~/.config/opencode` config (`mcp` key, OpenCode `type: "local"` format).
|
|
31
|
+
- **`install --mcp`** — Codex: runs `codex mcp add` when `codex` is on PATH.
|
|
32
|
+
- **`install --mcp`** — ChatGPT desktop: merges into `chatgpt_mcp_config.json` when ChatGPT app data exists.
|
|
33
|
+
|
|
34
|
+
### Changed
|
|
35
|
+
|
|
36
|
+
- **`docs mcp`** — Codex/ChatGPT guidance: Connectors for web (remote MCP); gated desktop JSON auto-install.
|
|
37
|
+
|
|
10
38
|
## [3.4.2] - 2026-06-22
|
|
11
39
|
|
|
12
40
|
### Added
|
|
@@ -359,7 +387,9 @@ const cli = { ... } satisfies CliProgram; // or : CliProgram
|
|
|
359
387
|
- 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`).
|
|
360
388
|
- Imports: use `CliPositional` where needed; replace `CliOptionDef` with `CliOption` or `CliPositional` as appropriate.
|
|
361
389
|
|
|
362
|
-
[Unreleased]: https://github.com/bdombro/bun-argsbarg/compare/v3.
|
|
390
|
+
[Unreleased]: https://github.com/bdombro/bun-argsbarg/compare/v3.6.0...HEAD
|
|
391
|
+
[3.6.0]: https://github.com/bdombro/bun-argsbarg/releases/tag/v3.6.0
|
|
392
|
+
[3.5.0]: https://github.com/bdombro/bun-argsbarg/releases/tag/v3.5.0
|
|
363
393
|
[3.4.2]: https://github.com/bdombro/bun-argsbarg/releases/tag/v3.4.2
|
|
364
394
|
[3.4.1]: https://github.com/bdombro/bun-argsbarg/releases/tag/v3.4.1
|
|
365
395
|
[3.4.0]: https://github.com/bdombro/bun-argsbarg/releases/tag/v3.4.0
|
package/README.md
CHANGED
|
@@ -112,9 +112,9 @@ Opt in on the program root with `mcpServer: { enabled: true }`, then run `myapp
|
|
|
112
112
|
|
|
113
113
|
See **[docs/mcp.md](docs/mcp.md)** for configuration, env bootstrapping, custom resources, Cursor setup, and protocol details. See **[docs/cli-program.md](docs/cli-program.md)** for schema authoring (consumer apps: copy **`docs/templates/cursor/rules/cli-program.mdc`** to **`.cursor/rules/cli-program.mdc`**).
|
|
114
114
|
|
|
115
|
-
### Install
|
|
115
|
+
### Install CLI
|
|
116
116
|
|
|
117
|
-
After `bun build --compile` (or when running via `bun`), ship your CLI and let users run:
|
|
117
|
+
argsbarg includes CLI features to manage installation of your compiled bun app. After `bun build --compile` (or when running via `bun`), ship your CLI and let users run:
|
|
118
118
|
|
|
119
119
|
```bash
|
|
120
120
|
myapp install --all --yes
|
|
@@ -140,12 +140,23 @@ myapp completion fish > ~/.config/fish/completions/myapp.fish
|
|
|
140
140
|
|
|
141
141
|
|
|
142
142
|
|
|
143
|
-
##
|
|
143
|
+
## Quick Start
|
|
144
144
|
|
|
145
145
|
```bash
|
|
146
|
-
bun add
|
|
146
|
+
bun add argsbarg
|
|
147
147
|
```
|
|
148
148
|
|
|
149
|
+
### Cursor / AI agents
|
|
150
|
+
|
|
151
|
+
Argsbarg ships authoring docs in `node_modules/argsbarg/docs/`. Agents do not load them unless your repo points there — copy the thin Cursor rule after install (it tells agents to **read** `cli-program.md`, not duplicate it):
|
|
152
|
+
|
|
153
|
+
```bash
|
|
154
|
+
mkdir -p .cursor/rules
|
|
155
|
+
cp node_modules/argsbarg/docs/templates/cursor/rules/cli-program.mdc .cursor/rules/cli-program.mdc
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
Add app-specific conventions in a second rule if needed. Full guide: **[docs/cli-program.md](docs/cli-program.md)**.
|
|
159
|
+
|
|
149
160
|
|
|
150
161
|
## How it works
|
|
151
162
|
|
|
@@ -178,9 +189,13 @@ Add `CliPositional` entries to the command’s `positionals` list (separate from
|
|
|
178
189
|
|
|
179
190
|
### Reading values (`CliContext`)
|
|
180
191
|
|
|
181
|
-
- `ctx.flag("verbose")` — presence options (`boolean`).
|
|
192
|
+
- `ctx.flag("verbose")` / `ctx.hasFlag("verbose")` — presence options (`boolean`).
|
|
182
193
|
- `ctx.stringOpt("name")` / `ctx.numberOpt("count")` — `string | undefined` / `number | null`.
|
|
183
|
-
- `ctx.
|
|
194
|
+
- `ctx.durationOpt("timeout")` — duration options (`format: CliValueFormat.Duration`) as milliseconds.
|
|
195
|
+
- `ctx.commaListOpt("services")` — comma-list options as `string[] | undefined`.
|
|
196
|
+
- `ctx.dateOpt("on")` / `ctx.dateTimeOpt("since")` — ISO date / date-time options.
|
|
197
|
+
- `ctx.readLeafInputs()` — coerced option and positional values for the current leaf (schema-driven).
|
|
198
|
+
- `ctx.typedOpt<T>("custom", parseFn)` — custom parsing for type-safe option resolution.
|
|
184
199
|
- `ctx.args` — positional words in order as `string[]`.
|
|
185
200
|
- `ctx.positional("name")` — named positional lookup; varargs slots return `string[]`, single slots return `string | undefined`.
|
|
186
201
|
- `ctx.program` — program root (`CliProgram`) for contextual help.
|
|
@@ -221,12 +236,13 @@ The package root (`argsbarg` / `src/index.ts`) exports the types and runtime you
|
|
|
221
236
|
| Symbol | Role |
|
|
222
237
|
| --- | --- |
|
|
223
238
|
| `CliProgram`, `CliOption`, `CliPositional`, `CliHandler` | Schema and handler types. |
|
|
224
|
-
| `CliOptionKind`, `CliFallbackMode` | Option kinds (`
|
|
239
|
+
| `CliOptionKind`, `CliValueFormat`, `CliFallbackMode` | Option kinds, value formats (`duration`, `comma-list`, `date`, `date-time`), and root fallback behavior. |
|
|
225
240
|
| `CliSchemaValidationError` | Thrown when the static command tree violates schema rules. |
|
|
226
|
-
| `CliContext` | Handler context (`ctx.flag`, `ctx.stringOpt`, `ctx.
|
|
241
|
+
| `CliContext` | Handler context (`ctx.flag`, `ctx.stringOpt`, `ctx.durationOpt`, `ctx.readLeafInputs`, `ctx.invocation`, …). |
|
|
227
242
|
| `cliRun(root, [argv])` | Validate, parse argv, dispatch, exit. |
|
|
228
243
|
| `cliInvoke(root, argv)` | Parse and dispatch without exiting; returns captured stdout/stderr. |
|
|
229
244
|
| `cliErrWithHelp(ctx, msg)` | Print error + scoped help on stderr, exit 1. |
|
|
245
|
+
| `parseDurationMs`, `parseCommaList`, `parseDate`, `parseDateTime` | Optional format parsers for use outside handlers. |
|
|
230
246
|
|
|
231
247
|
Reserved identifiers (validated at startup): root commands **`completion`**, **`version`**, **`install`**, **`docs`** (when `docs.enabled` is `true`), and **`mcp`** (when `mcpServer.enabled` is `true`).
|
|
232
248
|
|
package/biome.json
CHANGED
|
@@ -1,17 +1,40 @@
|
|
|
1
1
|
{
|
|
2
|
-
"$schema": "https://biomejs.dev/schemas/
|
|
3
|
-
"organizeImports":
|
|
4
|
-
"enabled": true
|
|
5
|
-
},
|
|
2
|
+
"$schema": "https://biomejs.dev/schemas/2.5.0/schema.json",
|
|
3
|
+
"assist": { "actions": { "source": { "organizeImports": "on" } } },
|
|
6
4
|
"linter": {
|
|
7
5
|
"enabled": true,
|
|
8
6
|
"rules": {
|
|
9
|
-
"
|
|
7
|
+
"preset": "recommended"
|
|
10
8
|
}
|
|
11
9
|
},
|
|
12
10
|
"formatter": {
|
|
13
11
|
"enabled": true,
|
|
14
12
|
"indentStyle": "space",
|
|
15
13
|
"lineWidth": 100
|
|
16
|
-
}
|
|
14
|
+
},
|
|
15
|
+
"overrides": [
|
|
16
|
+
{
|
|
17
|
+
"includes": ["**/completion-bash.ts", "**/completion-zsh.ts"],
|
|
18
|
+
"linter": {
|
|
19
|
+
"rules": {
|
|
20
|
+
"suspicious": {
|
|
21
|
+
"noTemplateCurlyInString": "off"
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"includes": ["**/*.test.ts"],
|
|
28
|
+
"linter": {
|
|
29
|
+
"rules": {
|
|
30
|
+
"style": {
|
|
31
|
+
"noNonNullAssertion": "off"
|
|
32
|
+
},
|
|
33
|
+
"suspicious": {
|
|
34
|
+
"noTemplateCurlyInString": "off"
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
]
|
|
17
40
|
}
|
package/bun.lock
CHANGED
|
@@ -5,17 +5,39 @@
|
|
|
5
5
|
"": {
|
|
6
6
|
"name": "argsbarg",
|
|
7
7
|
"devDependencies": {
|
|
8
|
+
"@biomejs/biome": "^2.5.0",
|
|
8
9
|
"@types/bun": "^1.3.12",
|
|
10
|
+
"typescript": "^5.9.3",
|
|
9
11
|
},
|
|
10
12
|
},
|
|
11
13
|
},
|
|
12
14
|
"packages": {
|
|
15
|
+
"@biomejs/biome": ["@biomejs/biome@2.5.0", "", { "optionalDependencies": { "@biomejs/cli-darwin-arm64": "2.5.0", "@biomejs/cli-darwin-x64": "2.5.0", "@biomejs/cli-linux-arm64": "2.5.0", "@biomejs/cli-linux-arm64-musl": "2.5.0", "@biomejs/cli-linux-x64": "2.5.0", "@biomejs/cli-linux-x64-musl": "2.5.0", "@biomejs/cli-win32-arm64": "2.5.0", "@biomejs/cli-win32-x64": "2.5.0" }, "bin": { "biome": "bin/biome" } }, "sha512-4kURkd9hAPrdDM3C9n82ycYgx8hvQcW6MjKTEejruj8rK0N8P3OPpdy8BvI8kt3KWY4ycF5XtDOrktetEfhfuw=="],
|
|
16
|
+
|
|
17
|
+
"@biomejs/cli-darwin-arm64": ["@biomejs/cli-darwin-arm64@2.5.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-Mn3Fwi3SA5fgmfCPqmzpWF2DLZnms3BVAhM088nTnGrTZmHS3wwIjcoZPqpXeNgd3DrrLH6xp8vTLIBuJoZiXw=="],
|
|
18
|
+
|
|
19
|
+
"@biomejs/cli-darwin-x64": ["@biomejs/cli-darwin-x64@2.5.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-rg3VPL5P8mYro6pqlXYXuJWph21slVp3SZtAqWSrkZs40d2gTzYmHF8E/X1iTID25btmNKltNDJ926sqVBp7DQ=="],
|
|
20
|
+
|
|
21
|
+
"@biomejs/cli-linux-arm64": ["@biomejs/cli-linux-arm64@2.5.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-tl+LW8fdD96/xdeWtWwc82LIOc5CoY7N2AsogLTp5R4ECErYt+8Jl/N68ezN9vzSiqPTxw6vjcihoLPYKZHrlw=="],
|
|
22
|
+
|
|
23
|
+
"@biomejs/cli-linux-arm64-musl": ["@biomejs/cli-linux-arm64-musl@2.5.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-vQdM4oSGaf7ZNeGO9w5+Y8SBtyser9M6znxYbm7Ec8wInxJu1WiKxFYZW5Auj2d80bcVvefuGGRxoFOE0eee8g=="],
|
|
24
|
+
|
|
25
|
+
"@biomejs/cli-linux-x64": ["@biomejs/cli-linux-x64@2.5.0", "", { "os": "linux", "cpu": "x64" }, "sha512-zpEGf4RQbFEh8Vt7OmavLyyOzRbtcE9osCqrS1kfvt8jDvxwhKXLSf7n0ebr/ov0RJ9ssP+lhs6C8a9WwFvrQA=="],
|
|
26
|
+
|
|
27
|
+
"@biomejs/cli-linux-x64-musl": ["@biomejs/cli-linux-x64-musl@2.5.0", "", { "os": "linux", "cpu": "x64" }, "sha512-+9hIcMngJ+yGUahXqZuZ8CoWKJE9SAZsFsM3QDvXpNsLbXZ9lqVzgBhOk/jTSYkOA0GLP9eu3teukqpLUojHMg=="],
|
|
28
|
+
|
|
29
|
+
"@biomejs/cli-win32-arm64": ["@biomejs/cli-win32-arm64@2.5.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-jB0wAvTLI4itx5VidqVUejPQFhRUxiZ9l9FvZ26D5fl6t3qme+ZB4PD3bTSeL1vZ8NI2Rx/zj6H9zcESuGHKGw=="],
|
|
30
|
+
|
|
31
|
+
"@biomejs/cli-win32-x64": ["@biomejs/cli-win32-x64@2.5.0", "", { "os": "win32", "cpu": "x64" }, "sha512-VT/lF+GId+67j8aDfLkxdxNoVApsPSTbyAtB3jJq0IWTrY77WXfbPfpngxq0bA6JCEv/7k8C9qWjDRKRznDlyw=="],
|
|
32
|
+
|
|
13
33
|
"@types/bun": ["@types/bun@1.3.14", "", { "dependencies": { "bun-types": "1.3.14" } }, "sha512-h1hFqFVcvAvD9j9K7ZW7vd82aSA+rTdznZa+5bwvCwqSB1jmmfLcbIWhOLx1/+boy/xmjgCs/OMUL8hRJSmnPw=="],
|
|
14
34
|
|
|
15
35
|
"@types/node": ["@types/node@26.0.0", "", { "dependencies": { "undici-types": "~8.3.0" } }, "sha512-vf2YFi1iY9lHGwNJMs01biZFbKJkrZR1T6/MlzjhJLPdntOHLhTrDSnSVcdtvjihi4VQNlrFRIxLsDBlQpAipA=="],
|
|
16
36
|
|
|
17
37
|
"bun-types": ["bun-types@1.3.14", "", { "dependencies": { "@types/node": "*" } }, "sha512-4N0ig0fEomHt5R0KCFWjovxow98rIoRwKolrYdCcknNwMekCXRnWEUvgu5soYV8QXtVsrUD8B95MBOZGPvr6KQ=="],
|
|
18
38
|
|
|
39
|
+
"typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],
|
|
40
|
+
|
|
19
41
|
"undici-types": ["undici-types@8.3.0", "", {}, "sha512-j375ScV60dom+YkPFIfTLcOiPxkN/buHz5GobjLhixFuANaNs3C9l4GmrWqejgXWJ7BbJcFYpTEUkS1Ge8bpZQ=="],
|
|
20
42
|
}
|
|
21
43
|
}
|
package/docs/cli-program.md
CHANGED
|
@@ -136,6 +136,65 @@ Do **not** use `mcpTool.description` to paper over missing `--yes`, non-standard
|
|
|
136
136
|
|
|
137
137
|
If help text and MCP behavior match after your fixes, **omit `mcpTool` entirely**.
|
|
138
138
|
|
|
139
|
+
## Value formats
|
|
140
|
+
|
|
141
|
+
On **string options**, optional metadata improves validation, MCP `inputSchema`, and handler reads:
|
|
142
|
+
|
|
143
|
+
| Field | Purpose |
|
|
144
|
+
| --- | --- |
|
|
145
|
+
| `format: CliValueFormat.Duration` | Values like `30s`, `20m`, `1h`; read with `ctx.durationOpt(name)` (milliseconds) |
|
|
146
|
+
| `format: CliValueFormat.CommaList` | Single-flag lists (`--services a,b`); MCP may pass string or array; read with `ctx.commaListOpt(name)` |
|
|
147
|
+
| `format: CliValueFormat.Date` | `YYYY-MM-DD`; read with `ctx.dateOpt(name)` |
|
|
148
|
+
| `format: CliValueFormat.DateTime` | RFC 3339 instant; read with `ctx.dateTimeOpt(name)` |
|
|
149
|
+
| `default: "..."` | Applied in post-parse when the option is omitted (not valid with `required: true`) |
|
|
150
|
+
| `pattern: "..."` | Regex validation (mutually exclusive with `format`) |
|
|
151
|
+
|
|
152
|
+
`format` applies to **string options only** — not positionals. Post-parse keeps raw strings in `ctx.opts`; typed readers return coerced values.
|
|
153
|
+
|
|
154
|
+
**Example** (duration with default, comma-list flag):
|
|
155
|
+
|
|
156
|
+
```typescript
|
|
157
|
+
import { CliOptionKind, CliValueFormat } from "argsbarg";
|
|
158
|
+
|
|
159
|
+
options: [
|
|
160
|
+
{
|
|
161
|
+
name: "timeout",
|
|
162
|
+
description: "Maximum wait time.",
|
|
163
|
+
kind: CliOptionKind.String,
|
|
164
|
+
format: CliValueFormat.Duration,
|
|
165
|
+
default: "20m",
|
|
166
|
+
},
|
|
167
|
+
{
|
|
168
|
+
name: "services",
|
|
169
|
+
description: "Service names to reset (single env only).",
|
|
170
|
+
kind: CliOptionKind.String,
|
|
171
|
+
format: CliValueFormat.CommaList,
|
|
172
|
+
},
|
|
173
|
+
],
|
|
174
|
+
handler: async (ctx) => {
|
|
175
|
+
const timeoutMs = ctx.durationOpt("timeout")!; // always set via default
|
|
176
|
+
const services = ctx.commaListOpt("services"); // string[] | undefined
|
|
177
|
+
},
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
**Varargs positionals** (`argMax: 0`):
|
|
181
|
+
|
|
182
|
+
| Surface | Multiple values |
|
|
183
|
+
| --- | --- |
|
|
184
|
+
| CLI | Space-separated words: `myapp uids uid-a uid-b` |
|
|
185
|
+
| MCP | JSON array on the positional key: `{ "uids": ["uid-a", "uid-b"] }` |
|
|
186
|
+
|
|
187
|
+
Read varargs with `ctx.positional("uids")` (returns `string[]`) or `ctx.args`. Do not comma-split argv tokens or use `format` on positionals.
|
|
188
|
+
|
|
189
|
+
**`readLeafInputs()`** — for leaves with several flags, one schema-driven read instead of hand-rolled `hasFlag` / `stringOpt` lines:
|
|
190
|
+
|
|
191
|
+
```typescript
|
|
192
|
+
const { limit, "skip-readiness": skipReadiness, timeout } = ctx.readLeafInputs();
|
|
193
|
+
// duration → number (ms); comma-list → string[]; presence → boolean; number → number
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
Cross-field rules (e.g. `--match-remote` requires `--branch`) stay in consumer `resolve*` layers — argsbarg does not validate those.
|
|
197
|
+
|
|
139
198
|
## Headless-capable handlers
|
|
140
199
|
|
|
141
200
|
Simple leaves (read args, print stdout) are already headless — no extra work. **Any handler that might mount Ink, prompt, or open a browser should also implement a scriptable fast path** for:
|
|
@@ -219,7 +278,22 @@ Do not declare user commands named `completion`, `install`, `mcp`, `version`, or
|
|
|
219
278
|
|
|
220
279
|
## Cursor rule for consumer repos
|
|
221
280
|
|
|
222
|
-
|
|
281
|
+
Argsbarg ships framework docs under `node_modules/argsbarg/docs/` (same files as this repo’s `docs/`). **This file is the authoritative guide** — the Cursor rule is a thin tripwire that tells agents to read it.
|
|
282
|
+
|
|
283
|
+
Agents do **not** discover package docs automatically. Wire them in after `bun add argsbarg`:
|
|
284
|
+
|
|
285
|
+
1. **Copy the Cursor rule** (recommended):
|
|
286
|
+
|
|
287
|
+
```bash
|
|
288
|
+
mkdir -p .cursor/rules
|
|
289
|
+
cp node_modules/argsbarg/docs/templates/cursor/rules/cli-program.mdc .cursor/rules/cli-program.mdc
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
The template is ~25 lines: when to read which doc, plus hard rules agents often get wrong. It does **not** duplicate this guide — re-copy after upgrading argsbarg when the template changes.
|
|
293
|
+
|
|
294
|
+
2. **Optional:** a second rule for app-only conventions (e.g. `src/cli/shared.ts` flag names, JSON-only handlers, Ink patterns).
|
|
295
|
+
|
|
296
|
+
3. **Optional:** `.cursor/argsbarg.mdc` or `AGENTS.md` pointing at `node_modules/argsbarg/docs/cli-program.md` for broader context.
|
|
223
297
|
|
|
224
298
|
## See also
|
|
225
299
|
|
package/docs/install.md
CHANGED
|
@@ -31,7 +31,7 @@ myapp install --uninstall --all --yes
|
|
|
31
31
|
| Fish completion | `--completions` | `~/.config/fish/completions/<key>.fish` |
|
|
32
32
|
| Cursor skill | `--skill` | `~/.cursor/skills/<dir>/` when `~/.cursor` exists |
|
|
33
33
|
| Claude skill | `--skill` | `~/.claude/skills/<dir>/` when `~/.claude` exists |
|
|
34
|
-
| MCP config | `--mcp` |
|
|
34
|
+
| MCP config | `--mcp` | Cursor, Claude Code/Desktop, OpenCode (`~/.config/opencode`), Codex (`codex` on PATH), ChatGPT desktop (when app data exists). ChatGPT web uses Connectors — see `docs mcp` |
|
|
35
35
|
|
|
36
36
|
`--all` expands to `--bin`, `--completions`, `--skill`, and `--mcp` (when `mcpServer.enabled` is `true`) for both install and uninstall. Missing targets are skipped silently (no error if nothing is on disk or a shell/agent directory does not exist).
|
|
37
37
|
|
package/docs/mcp.md
CHANGED
|
@@ -75,6 +75,50 @@ Use your real binary or script path. For a compiled CLI, `command` can be the in
|
|
|
75
75
|
|
|
76
76
|
Restart Claude Desktop after config changes. You can also install a **`.mcpb`** bundle via **`mcp bundle`** (see [MCP Bundle](#mcp-bundle-mcp-bundle)).
|
|
77
77
|
|
|
78
|
+
### OpenCode
|
|
79
|
+
|
|
80
|
+
When `~/.config/opencode` exists, **`install --mcp`** merges a local server under the top-level **`mcp`** key (not `mcpServers`):
|
|
81
|
+
|
|
82
|
+
```json
|
|
83
|
+
{
|
|
84
|
+
"$schema": "https://opencode.ai/config.json",
|
|
85
|
+
"mcp": {
|
|
86
|
+
"myapp": {
|
|
87
|
+
"type": "local",
|
|
88
|
+
"command": ["myapp", "mcp"],
|
|
89
|
+
"enabled": true
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
OpenCode reads `opencode.jsonc`, `opencode.json`, or `config.json` in that directory. Argsbarg updates the first existing file, or creates `config.json`. JSON-with-comments (`.jsonc`) is not auto-edited — add the block manually or use a `.json` config file.
|
|
96
|
+
|
|
97
|
+
### OpenAI Codex
|
|
98
|
+
|
|
99
|
+
When **`codex`** is on PATH, **`install --mcp`** runs `codex mcp add <server> -- <binary> mcp`, which writes **`~/.codex/config.toml`**. Otherwise add manually:
|
|
100
|
+
|
|
101
|
+
```toml
|
|
102
|
+
[mcp_servers.myapp]
|
|
103
|
+
command = "myapp"
|
|
104
|
+
args = ["mcp"]
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Use **`codex mcp`** to list/add/remove servers, or **Settings → MCP → Open config.toml** in the Codex app. CLI and IDE extension share the same file.
|
|
108
|
+
|
|
109
|
+
### ChatGPT
|
|
110
|
+
|
|
111
|
+
**Web / Connectors (OpenAI’s documented path)** — **Settings → Connectors → Developer mode** with a **remote HTTPS MCP URL**. ChatGPT does not spawn local stdio binaries; bridge and tunnel local servers when needed.
|
|
112
|
+
|
|
113
|
+
**Desktop JSON (gated auto-install)** — when ChatGPT app data exists, **`install --mcp`** also merges `mcpServers` into:
|
|
114
|
+
|
|
115
|
+
| Platform | Path |
|
|
116
|
+
| --- | --- |
|
|
117
|
+
| macOS | `~/Library/Application Support/ChatGPT/chatgpt_mcp_config.json` |
|
|
118
|
+
| Windows | `%APPDATA%\OpenAI\ChatGPT\chatgpt_mcp_config.json` |
|
|
119
|
+
|
|
120
|
+
Local JSON support varies by desktop build. Prefer **Connectors** for ChatGPT web or when tools do not appear after install.
|
|
121
|
+
|
|
78
122
|
### Other MCP hosts
|
|
79
123
|
|
|
80
124
|
Any host that spawns a subprocess and wires stdin/stdout works the same way: the **command** is your app, and **`mcp`** starts the server.
|
|
@@ -321,7 +365,7 @@ just build
|
|
|
321
365
|
|
|
322
366
|
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`).
|
|
323
367
|
|
|
324
|
-
Bare **`myapp mcp`** still runs the stdio MCP server (unchanged for `install --mcp` and MCP hosts). Use **`install --mcp`** for Cursor, Claude Code,
|
|
368
|
+
Bare **`myapp mcp`** still runs the stdio MCP server (unchanged for `install --mcp` and MCP hosts). Use **`install --mcp`** for Cursor, Claude Code, Claude Desktop, and OpenCode JSON config.
|
|
325
369
|
|
|
326
370
|
## Hidden commands and options
|
|
327
371
|
|
|
@@ -1,29 +1,23 @@
|
|
|
1
1
|
---
|
|
2
|
-
description: Argsbarg
|
|
3
|
-
globs: "
|
|
2
|
+
description: Argsbarg schema — read framework docs before editing CLI commands
|
|
3
|
+
globs: "src/**/commands/**/*.{ts,tsx},src/index.{ts,tsx}"
|
|
4
4
|
alwaysApply: false
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
When adding or changing argsbarg schema, leaf handlers, or MCP exposure:
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
- Reserved root commands (do not declare): `completion`, `install`, `mcp`, `version`, `docs`, `update`
|
|
9
|
+
1. **Read** `node_modules/argsbarg/docs/cli-program.md` (required — authoritative guide).
|
|
10
|
+
2. MCP tools, varargs, `inputSchema` → also `node_modules/argsbarg/docs/mcp.md`.
|
|
11
|
+
3. `install`, completions, skills → `node_modules/argsbarg/docs/install.md`.
|
|
12
|
+
4. Bundled `docs` built-in → `node_modules/argsbarg/docs/bundled-docs.md`.
|
|
14
13
|
|
|
15
|
-
|
|
16
|
-
- **Inline** options, positionals, and handler schema; extract to `export const …Command = { … } satisfies CliLeaf` (or router type) when shared flags, `mcpTool` spreads, or large handlers justify a module — not zero-arg wrapper functions
|
|
17
|
-
- Leaf descriptions: action-oriented, not UI jargon
|
|
18
|
-
- Prefer option names `yes`, `dry-run`, `json` when semantics match; describe non-interactive use on the option
|
|
14
|
+
**Hard rules** (details and examples are in the docs above — do not contradict them):
|
|
19
15
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
16
|
+
- Reserved root commands: `completion`, `install`, `mcp`, `version`, `docs`, `update`.
|
|
17
|
+
- `satisfies CliProgram` / `CliLeaf`; action-oriented `description` on root, commands, options, and positionals.
|
|
18
|
+
- Omit `mcpTool` unless genuinely CLI-only (`enabled: false`), `requiresEnv`, or an irreducible wire limit — fix schema and headless handlers first.
|
|
19
|
+
- Interactive leaves: one headless path for MCP, non-TTY CLI, and `--yes` / `--dry-run` / `--json` (`shouldRunHeadless*`, `requireYesInNonTty`); not raw `isTTY`.
|
|
20
|
+
- String options: `format` / `default` / `pattern` per `cli-program.md`; `readLeafInputs()` for multi-flag leaves.
|
|
21
|
+
- Varargs (`argMax: 0`): CLI space-separated; MCP JSON array only — no comma-splitting positionals.
|
|
23
22
|
|
|
24
|
-
|
|
25
|
-
Interactive commands need one fast path for MCP, non-TTY CLI, and `--yes` / `--dry-run` / `--json`.
|
|
26
|
-
- Mutators: `requireYesInNonTty`, `shouldRunHeadlessWithYes`
|
|
27
|
-
- Queries: `shouldRunHeadless`, `wantsExplicitJson`
|
|
28
|
-
- Varargs/positionals: `shouldRunHeadlessWithPositionals`
|
|
29
|
-
- `ctx.invocation === "mcp"` only for subprocess/TTY wire behavior; use argsbarg headless helpers, not raw `isTTY`
|
|
23
|
+
**App-specific conventions:** add below or in a separate `.cursor/rules/` file (shared flags path, Ink vs JSON-only, etc.).
|
package/index.d.ts
CHANGED
|
@@ -1,33 +1,5 @@
|
|
|
1
1
|
// Generated by dts-bundle-generator v9.5.1
|
|
2
2
|
|
|
3
|
-
/**
|
|
4
|
-
* Values passed to a leaf command handler after parsing: app name, routed path, args, and merged options.
|
|
5
|
-
*/
|
|
6
|
-
export declare class CliContext {
|
|
7
|
-
readonly appName: string;
|
|
8
|
-
readonly commandPath: string[];
|
|
9
|
-
readonly args: string[];
|
|
10
|
-
readonly program: CliProgram;
|
|
11
|
-
readonly opts: Record<string, string>;
|
|
12
|
-
readonly invocation: CliInvocation;
|
|
13
|
-
/** Captures the program root, routed path, positional words, and option map for a leaf handler. */
|
|
14
|
-
constructor(appName: string, commandPath: string[], args: string[], opts: Record<string, string>, program: CliProgram, invocation?: CliInvocation);
|
|
15
|
-
/** Returns whether a presence flag was set (including implicit "1" for boolean options). */
|
|
16
|
-
hasFlag(name: string): boolean;
|
|
17
|
-
/** Returns the string value for a string-valued option, if present. */
|
|
18
|
-
stringOpt(name: string): string | undefined;
|
|
19
|
-
/** Parses a stored string as a number; returns null if missing or not a strict double string. */
|
|
20
|
-
numberOpt(name: string): number | null;
|
|
21
|
-
/**
|
|
22
|
-
* Generic typed accessor: parses a stored string using the provided parse function.
|
|
23
|
-
* This is the TypeScript-native advantage over the Swift version.
|
|
24
|
-
*/
|
|
25
|
-
typedOpt<T>(name: string, parse: (s: string) => T): T | null;
|
|
26
|
-
/** Returns the value(s) for a named positional slot. Varargs slots return string[]; single slots return string | undefined. */
|
|
27
|
-
positional(name: string): string | string[] | undefined;
|
|
28
|
-
private _posMap;
|
|
29
|
-
private _positionalMap;
|
|
30
|
-
}
|
|
31
3
|
/**
|
|
32
4
|
* How a leaf handler was dispatched.
|
|
33
5
|
*/
|
|
@@ -45,6 +17,20 @@ export declare enum CliOptionKind {
|
|
|
45
17
|
/** Fixed set of allowed string values. Requires non-empty `choices` on the option. */
|
|
46
18
|
Enum = "enum"
|
|
47
19
|
}
|
|
20
|
+
/**
|
|
21
|
+
* Named validation/coercion for string options (`format` on `CliOption`).
|
|
22
|
+
* Positionals do not use `format`; varargs use space-separated CLI tokens and JSON arrays over MCP.
|
|
23
|
+
*/
|
|
24
|
+
export declare enum CliValueFormat {
|
|
25
|
+
/** Duration text such as `30s`, `20m`, `1h`, `2d` (default unit minutes when omitted). */
|
|
26
|
+
Duration = "duration",
|
|
27
|
+
/** Comma-separated list on a single option value (`--services a,b`). */
|
|
28
|
+
CommaList = "comma-list",
|
|
29
|
+
/** Calendar date `YYYY-MM-DD`. */
|
|
30
|
+
Date = "date",
|
|
31
|
+
/** RFC 3339 instant with `Z` or numeric offset. */
|
|
32
|
+
DateTime = "date-time"
|
|
33
|
+
}
|
|
48
34
|
/**
|
|
49
35
|
* When `fallbackCommand` is used for missing or unknown subcommand tokens at a routing node.
|
|
50
36
|
*/
|
|
@@ -84,6 +70,15 @@ export interface CliOption {
|
|
|
84
70
|
* Must be a non-empty array of distinct non-empty strings.
|
|
85
71
|
*/
|
|
86
72
|
choices?: string[];
|
|
73
|
+
/**
|
|
74
|
+
* Named string validation for `kind: String` options. Mutually exclusive with `pattern`.
|
|
75
|
+
* Not supported on positionals.
|
|
76
|
+
*/
|
|
77
|
+
format?: CliValueFormat;
|
|
78
|
+
/** Default value applied in post-parse when the option is omitted. */
|
|
79
|
+
default?: string;
|
|
80
|
+
/** Regex pattern for string options. Mutually exclusive with `format`. */
|
|
81
|
+
pattern?: string;
|
|
87
82
|
}
|
|
88
83
|
/**
|
|
89
84
|
* An ordered positional argument slot, listed on leaf `positionals`.
|
|
@@ -308,30 +303,56 @@ export declare class CliSchemaValidationError extends Error {
|
|
|
308
303
|
/** Creates a schema validation error with a human-readable rule violation. */
|
|
309
304
|
constructor(message: string);
|
|
310
305
|
}
|
|
311
|
-
/**
|
|
312
|
-
export type
|
|
313
|
-
/** Result of cliInvoke: captured output and exit metadata without process.exit. */
|
|
314
|
-
export interface CliInvokeResult {
|
|
315
|
-
/** Invocation outcome. */
|
|
316
|
-
kind: CliInvokeKind;
|
|
317
|
-
/** Simulated exit code. */
|
|
318
|
-
exitCode: number;
|
|
319
|
-
/** Captured stdout during handler execution. */
|
|
320
|
-
stdout: string;
|
|
321
|
-
/** Captured stderr during handler execution. */
|
|
322
|
-
stderr: string;
|
|
323
|
-
/** Set when kind === "error" (parse/validation message). */
|
|
324
|
-
errorMsg?: string;
|
|
325
|
-
}
|
|
306
|
+
/** Coerced leaf inputs keyed by option and positional names. */
|
|
307
|
+
export type CliLeafInputs = Record<string, boolean | number | string | string[] | undefined>;
|
|
326
308
|
/**
|
|
327
|
-
*
|
|
328
|
-
* Never calls process.exit.
|
|
309
|
+
* Values passed to a leaf command handler after parsing: app name, routed path, args, and merged options.
|
|
329
310
|
*/
|
|
330
|
-
export declare
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
311
|
+
export declare class CliContext {
|
|
312
|
+
readonly appName: string;
|
|
313
|
+
readonly commandPath: string[];
|
|
314
|
+
readonly args: string[];
|
|
315
|
+
readonly program: CliProgram;
|
|
316
|
+
readonly opts: Record<string, string>;
|
|
317
|
+
readonly invocation: CliInvocation;
|
|
318
|
+
/** Captures the program root, routed path, positional words, and option map for a leaf handler. */
|
|
319
|
+
constructor(appName: string, commandPath: string[], args: string[], opts: Record<string, string>, program: CliProgram, invocation?: CliInvocation);
|
|
320
|
+
/** Returns whether a presence flag was set (including implicit "1" for boolean options). */
|
|
321
|
+
hasFlag(name: string): boolean;
|
|
322
|
+
/** Returns the string value for a string-valued option, if present. */
|
|
323
|
+
stringOpt(name: string): string | undefined;
|
|
324
|
+
/** Parses a stored string as a number; returns null if missing or not a strict double string. */
|
|
325
|
+
numberOpt(name: string): number | null;
|
|
326
|
+
/**
|
|
327
|
+
* Generic typed accessor: parses a stored string using the provided parse function.
|
|
328
|
+
* This is the TypeScript-native advantage over the Swift version.
|
|
329
|
+
*/
|
|
330
|
+
typedOpt<T>(name: string, parse: (s: string) => T): T | null;
|
|
331
|
+
/** Duration option in milliseconds (post-parse validated). */
|
|
332
|
+
durationOpt(name: string): number | undefined;
|
|
333
|
+
/** Comma-list option as a string array (post-parse validated). */
|
|
334
|
+
commaListOpt(name: string): string[] | undefined;
|
|
335
|
+
/** Date option as canonical YYYY-MM-DD (post-parse validated). */
|
|
336
|
+
dateOpt(name: string): string | undefined;
|
|
337
|
+
/** Date-time option as normalized ISO 8601 UTC (post-parse validated). */
|
|
338
|
+
dateTimeOpt(name: string): string | undefined;
|
|
339
|
+
/** Returns the value(s) for a named positional slot. Varargs slots return string[]; single slots return string | undefined. */
|
|
340
|
+
positional(name: string): string | string[] | undefined;
|
|
341
|
+
/** Reads coerced option and positional values for the current leaf from schema metadata. */
|
|
342
|
+
readLeafInputs(): CliLeafInputs;
|
|
343
|
+
private _readOptionValue;
|
|
344
|
+
private _leafNode;
|
|
345
|
+
private _posMap;
|
|
346
|
+
private _positionalMap;
|
|
347
|
+
}
|
|
348
|
+
/** Parses a duration string (e.g. 20m, 1h, 30s) into milliseconds. */
|
|
349
|
+
export declare function parseDurationMs(durationStr: string): number;
|
|
350
|
+
/** Splits a comma-separated string into trimmed non-empty tokens. */
|
|
351
|
+
export declare function parseCommaList(s: string): string[];
|
|
352
|
+
/** Returns canonical YYYY-MM-DD after validation. */
|
|
353
|
+
export declare function parseDate(s: string): string;
|
|
354
|
+
/** Returns normalized ISO 8601 UTC after validation. */
|
|
355
|
+
export declare function parseDateTime(s: string): string;
|
|
335
356
|
/** Minimal context for headless routing helpers. */
|
|
336
357
|
export type HeadlessContext = Pick<CliContext, "invocation">;
|
|
337
358
|
/** True when `--json` was passed or the handler was invoked via MCP. */
|
|
@@ -405,6 +426,26 @@ export declare function createGhVersionCheck(config: GhVersionCheckConfig): {
|
|
|
405
426
|
};
|
|
406
427
|
/** Shared `gh release view` fetcher for hooks and version-check refresh. */
|
|
407
428
|
export declare function createGhFetchLatest(config: Pick<GhReleaseUpdateConfig, "repo" | "repoEnvHint">): () => Promise<string>;
|
|
429
|
+
/** Outcome of a non-exiting CLI invocation. */
|
|
430
|
+
export type CliInvokeKind = "ok" | "help" | "error";
|
|
431
|
+
/** Result of cliInvoke: captured output and exit metadata without process.exit. */
|
|
432
|
+
export interface CliInvokeResult {
|
|
433
|
+
/** Invocation outcome. */
|
|
434
|
+
kind: CliInvokeKind;
|
|
435
|
+
/** Simulated exit code. */
|
|
436
|
+
exitCode: number;
|
|
437
|
+
/** Captured stdout during handler execution. */
|
|
438
|
+
stdout: string;
|
|
439
|
+
/** Captured stderr during handler execution. */
|
|
440
|
+
stderr: string;
|
|
441
|
+
/** Set when kind === "error" (parse/validation message). */
|
|
442
|
+
errorMsg?: string;
|
|
443
|
+
}
|
|
444
|
+
/**
|
|
445
|
+
* Parses argv against the user root, runs the leaf handler, and returns captured output.
|
|
446
|
+
* Never calls process.exit.
|
|
447
|
+
*/
|
|
448
|
+
export declare function cliInvoke(root: CliProgram, argv: string[]): Promise<CliInvokeResult>;
|
|
408
449
|
/** Resolved paths for `mcp bundle`. */
|
|
409
450
|
export interface McpBundlePaths {
|
|
410
451
|
binaryPath: string;
|
|
@@ -425,5 +466,9 @@ export interface PackMcpBundleOpts {
|
|
|
425
466
|
* Requires the compiled binary to exist.
|
|
426
467
|
*/
|
|
427
468
|
export declare function packMcpBundle(program: CliProgram, opts?: PackMcpBundleOpts): string;
|
|
469
|
+
export declare function cliRun(program: CliProgram, argv?: string[]): Promise<never>;
|
|
470
|
+
export declare function cliErrWithHelp(ctx: CliContext, msg: string): never;
|
|
471
|
+
/** True when stdin is a TTY. */
|
|
472
|
+
export declare const isInteractiveTty: boolean;
|
|
428
473
|
|
|
429
474
|
export {};
|