argsbarg 3.6.1 → 3.6.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +23 -1
- package/README.md +6 -2
- package/docs/README.md +32 -0
- package/docs/bundled-docs.md +13 -0
- package/docs/cli-program.md +102 -1
- package/docs/developing.md +50 -0
- package/docs/mcp.md +1 -1
- package/docs/templates/cursor/rules/cli-program.mdc +1 -0
- package/examples/formats.ts +66 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,26 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [3.6.3] - 2026-06-23
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- **`docs/README.md`** — documentation map (framework vs consumer docgen).
|
|
15
|
+
- **`docs/developing.md`** — maintainer workflow (`consumer-dev`, `consumers-sync`, npm `files`).
|
|
16
|
+
- **`examples/formats.ts`** — `CliValueFormat`, `default`, and `readLeafInputs()` demo.
|
|
17
|
+
|
|
18
|
+
### Changed
|
|
19
|
+
|
|
20
|
+
- **`cli-program.md`** — `CliLeafInputs` / `readLeafInputs()` semantics, upgrading to 3.6+, read-once-resolve-once cross-links.
|
|
21
|
+
- **`bundled-docs.md`** — framework docs vs consumer docgen.
|
|
22
|
+
- **`docs/mcp.md`** — varargs JSON array only (fixes stale comma-string guidance).
|
|
23
|
+
|
|
24
|
+
## [3.6.2] - 2026-06-23
|
|
25
|
+
|
|
26
|
+
### Added
|
|
27
|
+
|
|
28
|
+
- **`cli-program.md`** — “Read flags once, resolve once” pattern for multi-surface leaves (`read*Flags` + `resolve*Input`).
|
|
29
|
+
|
|
10
30
|
## [3.6.1] - 2026-06-23
|
|
11
31
|
|
|
12
32
|
### Fixed
|
|
@@ -393,7 +413,9 @@ const cli = { ... } satisfies CliProgram; // or : CliProgram
|
|
|
393
413
|
- 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`).
|
|
394
414
|
- Imports: use `CliPositional` where needed; replace `CliOptionDef` with `CliOption` or `CliPositional` as appropriate.
|
|
395
415
|
|
|
396
|
-
[Unreleased]: https://github.com/bdombro/bun-argsbarg/compare/v3.6.
|
|
416
|
+
[Unreleased]: https://github.com/bdombro/bun-argsbarg/compare/v3.6.3...HEAD
|
|
417
|
+
[3.6.3]: https://github.com/bdombro/bun-argsbarg/releases/tag/v3.6.3
|
|
418
|
+
[3.6.2]: https://github.com/bdombro/bun-argsbarg/releases/tag/v3.6.2
|
|
397
419
|
[3.6.1]: https://github.com/bdombro/bun-argsbarg/releases/tag/v3.6.1
|
|
398
420
|
[3.6.0]: https://github.com/bdombro/bun-argsbarg/releases/tag/v3.6.0
|
|
399
421
|
[3.5.0]: https://github.com/bdombro/bun-argsbarg/releases/tag/v3.5.0
|
package/README.md
CHANGED
|
@@ -155,7 +155,7 @@ mkdir -p .cursor/rules
|
|
|
155
155
|
cp node_modules/argsbarg/docs/templates/cursor/rules/cli-program.mdc .cursor/rules/cli-program.mdc
|
|
156
156
|
```
|
|
157
157
|
|
|
158
|
-
Add app-specific conventions in a second rule if needed.
|
|
158
|
+
Add app-specific conventions in a second rule if needed. Documentation map: **[docs/README.md](docs/README.md)**. Authoring guide: **[docs/cli-program.md](docs/cli-program.md)**.
|
|
159
159
|
|
|
160
160
|
|
|
161
161
|
## How it works
|
|
@@ -214,6 +214,7 @@ Check the `examples/` directory for full working scripts:
|
|
|
214
214
|
| --- | --- | --- |
|
|
215
215
|
| `ArgsBargMinimal` | `examples/minimal.ts` | String + presence flags, `MissingOrUnknown` fallback. |
|
|
216
216
|
| `ArgsBargNested` | `examples/nested.ts` | Nested command tree, positional tails, async handlers. |
|
|
217
|
+
| `ArgsBargFormats` | `examples/formats.ts` | `CliValueFormat`, `default`, `readLeafInputs()`. |
|
|
217
218
|
|
|
218
219
|
```bash
|
|
219
220
|
export PATH="$PATH:$(pwd)/examples"
|
|
@@ -225,6 +226,8 @@ minimal.ts hello --name world
|
|
|
225
226
|
eval "$(nested.ts completion zsh)"
|
|
226
227
|
nested.ts stat owner lookup -u alice ./README.md
|
|
227
228
|
nested.ts read ./README.md
|
|
229
|
+
|
|
230
|
+
bun ./examples/formats.ts run --tags demo,docs --on 2026-06-22
|
|
228
231
|
```
|
|
229
232
|
|
|
230
233
|
|
|
@@ -238,7 +241,8 @@ The package root (`argsbarg` / `src/index.ts`) exports the types and runtime you
|
|
|
238
241
|
| `CliProgram`, `CliOption`, `CliPositional`, `CliHandler` | Schema and handler types. |
|
|
239
242
|
| `CliOptionKind`, `CliValueFormat`, `CliFallbackMode` | Option kinds, value formats (`duration`, `comma-list`, `date`, `date-time`), and root fallback behavior. |
|
|
240
243
|
| `CliSchemaValidationError` | Thrown when the static command tree violates schema rules. |
|
|
241
|
-
| `CliContext` | Handler context (`ctx.
|
|
244
|
+
| `CliContext` | Handler context (`ctx.hasFlag`, `ctx.stringOpt`, `ctx.durationOpt`, `ctx.readLeafInputs`, `ctx.invocation`, …). |
|
|
245
|
+
| `CliLeafInputs` | Record type returned by `readLeafInputs()` — coerced option/positional values keyed by schema name. |
|
|
242
246
|
| `cliRun(root, [argv])` | Validate, parse argv, dispatch, exit. |
|
|
243
247
|
| `cliInvoke(root, argv)` | Parse and dispatch without exiting; returns captured stdout/stderr. |
|
|
244
248
|
| `cliErrWithHelp(ctx, msg)` | Print error + scoped help on stderr, exit 1. |
|
package/docs/README.md
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# Argsbarg documentation
|
|
2
|
+
|
|
3
|
+
Start here to pick the right guide.
|
|
4
|
+
|
|
5
|
+
| If you are… | Read |
|
|
6
|
+
| --- | --- |
|
|
7
|
+
| **New to argsbarg** | [../README.md](../README.md) — install, minimal usage, public API |
|
|
8
|
+
| **Authoring a `CliProgram`** (humans or agents) | [cli-program.md](cli-program.md) — schema, formats, headless, `read*Flags` |
|
|
9
|
+
| **Exposing MCP tools** | [mcp.md](mcp.md) — stdio server, `inputSchema`, varargs, `install --mcp` |
|
|
10
|
+
| **Shipping install / completions / skills** | [install.md](install.md) — `myapp install`, shell completions |
|
|
11
|
+
| **Bundling `myapp docs` topics** | [bundled-docs.md](bundled-docs.md) — consumer docgen vs framework docs |
|
|
12
|
+
| **Agent skills** | [ai-skills.md](ai-skills.md) — `install --skill`, `docs skill` |
|
|
13
|
+
| **Maintaining the argsbarg repo** | [developing.md](developing.md) — release, consumers, npm `files` |
|
|
14
|
+
| **Cursor / IDE agents in a consumer app** | Copy [templates/cursor/rules/cli-program.mdc](templates/cursor/rules/cli-program.mdc) to `.cursor/rules/` |
|
|
15
|
+
|
|
16
|
+
## Framework docs vs consumer docgen
|
|
17
|
+
|
|
18
|
+
| Source | What it is | Where it lives |
|
|
19
|
+
| --- | --- | --- |
|
|
20
|
+
| **Framework docs** | How argsbarg works; authoring conventions | This directory — shipped in `node_modules/argsbarg/docs/` after `bun add argsbarg` |
|
|
21
|
+
| **Consumer docgen** | *Your* command tree, API, MCP guide for *your* app | `myapp docs api`, `docs schema`, `docs mcp` — written to `./docs/` with `--save` |
|
|
22
|
+
| **Cursor rule** | Thin tripwire telling agents to read framework docs | `node_modules/argsbarg/docs/templates/cursor/rules/cli-program.mdc` — copy into your repo and append app conventions |
|
|
23
|
+
|
|
24
|
+
Agents do **not** load `node_modules/argsbarg/docs/` unless your repo references them (Cursor rule, `AGENTS.md`, or an `alwaysApply` project rule). Generated `./docs/api.md` in a consumer repo describes **your** CLI, not argsbarg itself.
|
|
25
|
+
|
|
26
|
+
## Examples
|
|
27
|
+
|
|
28
|
+
| Example | Shows |
|
|
29
|
+
| --- | --- |
|
|
30
|
+
| [../examples/minimal.ts](../examples/minimal.ts) | Presence + string flags, fallback routing |
|
|
31
|
+
| [../examples/nested.ts](../examples/nested.ts) | Nested commands, varargs, MCP + `docs` |
|
|
32
|
+
| [../examples/formats.ts](../examples/formats.ts) | `CliValueFormat`, `default`, `readLeafInputs()` |
|
package/docs/bundled-docs.md
CHANGED
|
@@ -2,6 +2,19 @@
|
|
|
2
2
|
|
|
3
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
4
|
|
|
5
|
+
## Framework docs vs your app's docgen
|
|
6
|
+
|
|
7
|
+
Two documentation layers often coexist in a consumer repo:
|
|
8
|
+
|
|
9
|
+
| Layer | Contents | How agents/humans get it |
|
|
10
|
+
| --- | --- | --- |
|
|
11
|
+
| **Argsbarg framework** | How to author `CliProgram`, MCP varargs policy, headless patterns | `node_modules/argsbarg/docs/` — wire via [Cursor rule](templates/cursor/rules/cli-program.mdc) or `AGENTS.md` |
|
|
12
|
+
| **Your CLI (docgen)** | Your command tree, options, MCP tool list, install notes | `myapp docs api`, `docs schema`, `docs mcp` — save with `--save` to `./docs/` |
|
|
13
|
+
|
|
14
|
+
Do not confuse them: editing `./docs/api.md` after docgen updates **your** app reference; it does not change argsbarg's framework guides. When MCP behavior changes (e.g. varargs arrays in 3.6+), update consumer `docs/mcp.md` via **`myapp docs mcp --save`** and bump the `argsbarg` dependency.
|
|
15
|
+
|
|
16
|
+
See [docs/README.md](README.md) for the full documentation map.
|
|
17
|
+
|
|
5
18
|
## Quick start
|
|
6
19
|
|
|
7
20
|
```typescript
|
package/docs/cli-program.md
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
ArgsBarg turns your schema into help, shell completions, MCP tools, and agent skills. **The same `description` fields you write for humans are the agent contract** for basic apps.
|
|
4
4
|
|
|
5
|
+
**Documentation map:** [docs/README.md](README.md) — which guide to read for MCP, install, consumer docgen, and Cursor setup.
|
|
6
|
+
|
|
5
7
|
## Minimal app (MCP is free)
|
|
6
8
|
|
|
7
9
|
```typescript
|
|
@@ -193,8 +195,105 @@ const { limit, "skip-readiness": skipReadiness, timeout } = ctx.readLeafInputs()
|
|
|
193
195
|
// duration → number (ms); comma-list → string[]; presence → boolean; number → number
|
|
194
196
|
```
|
|
195
197
|
|
|
198
|
+
**`CliLeafInputs`** — return type of `readLeafInputs()` (exported from `"argsbarg"`). A flat record keyed by **schema option and positional names** (hyphens preserved, e.g. `"skip-readiness"`). Values are coerced per kind/format:
|
|
199
|
+
|
|
200
|
+
| Schema | Value in `CliLeafInputs` |
|
|
201
|
+
| --- | --- |
|
|
202
|
+
| Presence | `boolean` |
|
|
203
|
+
| Number | `number` or `undefined` if omitted |
|
|
204
|
+
| String (plain) | `string` or `undefined` |
|
|
205
|
+
| `format: duration` | `number` (milliseconds) |
|
|
206
|
+
| `format: comma-list` | `string[]` |
|
|
207
|
+
| `format: date` | `string` (`YYYY-MM-DD`) |
|
|
208
|
+
| `format: date-time` | `string` (normalized UTC ISO) |
|
|
209
|
+
| Single positional | `string` or `undefined` |
|
|
210
|
+
| Varargs positional | `string[]` or `undefined` |
|
|
211
|
+
|
|
212
|
+
Omitted options appear as `undefined` (not absent keys). Options with `default` are filled in post-parse before handlers run, so `readLeafInputs()` and `durationOpt` see defaults. **`ctx.opts` always holds raw strings** — use typed accessors or `readLeafInputs()` for coerced values.
|
|
213
|
+
|
|
214
|
+
`CliLeafInputs` is intentionally untyped at the framework level. Narrow in your app (`read*Flags(ctx)` returning a typed struct) rather than expecting inference from `satisfies CliLeaf`.
|
|
215
|
+
|
|
216
|
+
See [examples/formats.ts](../examples/formats.ts) for a runnable demo.
|
|
217
|
+
|
|
196
218
|
Cross-field rules (e.g. `--match-remote` requires `--branch`) stay in consumer `resolve*` layers — argsbarg does not validate those.
|
|
197
219
|
|
|
220
|
+
## Read flags once, resolve once
|
|
221
|
+
|
|
222
|
+
For apps with **Ink + headless + MCP** (multiple surfaces per leaf), avoid scattering `ctx.hasFlag` / `ctx.stringOpt` through the handler. Use two layers:
|
|
223
|
+
|
|
224
|
+
| Layer | Responsibility |
|
|
225
|
+
| --- | --- |
|
|
226
|
+
| **`read*Flags(ctx)`** | Read coerced values from `ctx` (`readLeafInputs()`, `durationOpt`, `commaListOpt`, shared mutator flags) into one typed struct |
|
|
227
|
+
| **`resolve*Input(flags)`** | Cross-field validation and defaults; returns `{ ok, input }` or `{ ok: false, error }` |
|
|
228
|
+
|
|
229
|
+
The handler calls **`read*Flags` once**, passes the struct to **`resolve*Input`**, then branches to Ink, headless, or MCP with the same resolved input.
|
|
230
|
+
|
|
231
|
+
**Shared reads** — when many leaves share options (`yes`, `dry-run`, `json`), one app-level helper (e.g. `readMutatingFlags(ctx)`) plus per-command extensions:
|
|
232
|
+
|
|
233
|
+
```typescript
|
|
234
|
+
// cli/flags.ts
|
|
235
|
+
export function readMutatingFlags(ctx: CliContext) {
|
|
236
|
+
const dryRun = ctx.hasFlag("dry-run");
|
|
237
|
+
return {
|
|
238
|
+
dryRun,
|
|
239
|
+
yes: ctx.hasFlag("yes"),
|
|
240
|
+
explicitJson: wantsExplicitJson(ctx, ctx.hasFlag("json")),
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
// commands/reset/resolve.ts
|
|
245
|
+
export function readResetFlags(ctx: CliContext) {
|
|
246
|
+
return {
|
|
247
|
+
...readMutatingFlags(ctx),
|
|
248
|
+
env: ctx.args[0],
|
|
249
|
+
force: ctx.hasFlag("force"),
|
|
250
|
+
services: ctx.commaListOpt("services"),
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
export function resolveResetInput(flags: ReturnType<typeof readResetFlags>) {
|
|
255
|
+
if (!flags.env) return { ok: false, error: "…" };
|
|
256
|
+
return { ok: true, input: { env: flags.env, force: flags.force, services: flags.services } };
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
// command handler
|
|
260
|
+
handler: async (ctx) => {
|
|
261
|
+
const flags = readResetFlags(ctx);
|
|
262
|
+
await dispatchMutatingCommand({
|
|
263
|
+
dryRun: flags.dryRun,
|
|
264
|
+
headless: shouldRunHeadlessWithYes(ctx, { yes: flags.yes, hasRequiredArgs: !!flags.env, dryRun: flags.dryRun }),
|
|
265
|
+
resolve: () => resolveResetInput(flags),
|
|
266
|
+
/* … */
|
|
267
|
+
});
|
|
268
|
+
};
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
**JSON-only CLIs** — a single `readCommandOptions(ctx)` wrapping `readLeafInputs()` per shared option set is usually enough; full `resolve*` layering is optional.
|
|
272
|
+
|
|
273
|
+
## Upgrading to 3.6+
|
|
274
|
+
|
|
275
|
+
### MCP varargs (breaking)
|
|
276
|
+
|
|
277
|
+
Varargs positionals (`argMax: 0`) must be a **JSON array** in `tools/call` — comma-separated strings are no longer accepted.
|
|
278
|
+
|
|
279
|
+
```json
|
|
280
|
+
// before (removed)
|
|
281
|
+
{ "uids": "a,b,c" }
|
|
282
|
+
|
|
283
|
+
// after
|
|
284
|
+
{ "uids": ["a", "b", "c"] }
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
CLI argv is unchanged: space-separated words. Use `format: comma-list` on an **option** when a single flag should accept `a,b` or `["a","b"]` over MCP.
|
|
288
|
+
|
|
289
|
+
### Value formats (optional)
|
|
290
|
+
|
|
291
|
+
Add `format`, `default`, or `pattern` on string **options**; read with `ctx.durationOpt`, `ctx.commaListOpt`, `ctx.readLeafInputs()`, etc. Replace hand-rolled `split(",")` / `parseDurationMs` try/catch where the schema can declare the shape.
|
|
292
|
+
|
|
293
|
+
### Handler layering (optional)
|
|
294
|
+
|
|
295
|
+
Ink + headless + MCP apps benefit from `read*Flags(ctx)` + `resolve*Input(flags)` — see above.
|
|
296
|
+
|
|
198
297
|
## Headless-capable handlers
|
|
199
298
|
|
|
200
299
|
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:
|
|
@@ -297,6 +396,8 @@ The template is ~25 lines: when to read which doc, plus hard rules agents often
|
|
|
297
396
|
|
|
298
397
|
## See also
|
|
299
398
|
|
|
399
|
+
- [Documentation map](README.md) — which doc to read when
|
|
400
|
+
- [Developing argsbarg](developing.md) — release, consumer sync, npm `files`
|
|
300
401
|
- [MCP server](mcp.md) — tools, schema resource, env bootstrapping
|
|
301
402
|
- [Agent skills](ai-skills.md) — `install --skill`
|
|
302
|
-
- [Bundled docs](bundled-docs.md) — `docs` topics
|
|
403
|
+
- [Bundled docs](bundled-docs.md) — `docs` topics, consumer docgen vs framework docs
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# Developing argsbarg
|
|
2
|
+
|
|
3
|
+
Notes for maintainers of this repository. Also shipped under `node_modules/argsbarg/docs/` for fork maintainers.
|
|
4
|
+
|
|
5
|
+
## Prerequisites
|
|
6
|
+
|
|
7
|
+
- [Bun](https://bun.sh) ≥ 1.3
|
|
8
|
+
- [just](https://github.com/casey/just) — `just` lists recipes
|
|
9
|
+
- `gh` and `npm` logged in for release
|
|
10
|
+
|
|
11
|
+
## Day-to-day
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
just check # typecheck + format
|
|
15
|
+
just test # check + unit tests
|
|
16
|
+
just typegen # regenerate index.d.ts
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Release
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
just release patch # or minor | major
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
The release script bumps `package.json`, promotes `[Unreleased]` in `CHANGELOG.md`, commits, tags, pushes, creates a GitHub release, and publishes to npm. Run `just test` first (the `just release` recipe does).
|
|
26
|
+
|
|
27
|
+
Update `CHANGELOG.md` under `[Unreleased]` before releasing.
|
|
28
|
+
|
|
29
|
+
## Local consumer apps
|
|
30
|
+
|
|
31
|
+
Sibling repos under `../../ss/` (paths are machine-specific; adjust in `justfile` if needed):
|
|
32
|
+
|
|
33
|
+
| Recipe | When | Effect |
|
|
34
|
+
| --- | --- | --- |
|
|
35
|
+
| `just consumer-dev` | Before publish; hacking on argsbarg locally | `bun add argsbarg@file:<relative>` in each consumer |
|
|
36
|
+
| `just consumers-sync` | After release | Sets `"argsbarg": "^<this package.json version>"`, `bun install`, `just build`, `just docgen`, `just install` |
|
|
37
|
+
|
|
38
|
+
`consumers-sync` reads the version from **this repo’s** `package.json` — not npm. Run it **after** `just release` so consumers pin a version that exists on the registry.
|
|
39
|
+
|
|
40
|
+
Re-copy `docs/templates/cursor/rules/cli-program.mdc` into consumer repos when the template changes (append app-specific conventions; do not fork the whole guide).
|
|
41
|
+
|
|
42
|
+
## npm package contents
|
|
43
|
+
|
|
44
|
+
`npm publish` does **not** honor `.gitignore`. Only paths listed in `package.json` `files` are included in the tarball (plus always-excluded defaults like `node_modules`).
|
|
45
|
+
|
|
46
|
+
When adding docs or examples intended for consumers, ensure they live under whitelisted paths (`docs/`, `examples/`, `src/`, etc.).
|
|
47
|
+
|
|
48
|
+
## Docs
|
|
49
|
+
|
|
50
|
+
See [README.md](README.md) for the documentation map. Framework authoring guide: [cli-program.md](cli-program.md).
|
package/docs/mcp.md
CHANGED
|
@@ -208,7 +208,7 @@ Set **`outputSchema` on the leaf** (not under `mcpTool`) — see [cli-program.md
|
|
|
208
208
|
Each tool’s `inputSchema` is a JSON Schema object built from your CLI definition:
|
|
209
209
|
|
|
210
210
|
- **Options** — parent-scoped flags are included (e.g. `stat`’s `--json` appears on `stat_owner_lookup`). Presence options are `boolean`; string, number, and **enum** options match their `CliOptionKind` (`Enum` uses JSON Schema `enum`). Required options are listed in `required`.
|
|
211
|
-
- **Positionals** — one property per `CliPositional` on the leaf. Single-slot positionals are `string`; varargs tails (`argMax: 0`) are `string[]`. Required positionals are listed in `required`.
|
|
211
|
+
- **Positionals** — one property per `CliPositional` on the leaf. Single-slot positionals are `string`; varargs tails (`argMax: 0`) are `string[]`. Required positionals are listed in `required`. **Varargs must be a JSON array** — comma-separated strings are not accepted (use `format: comma-list` on an option when a single flag should accept `"a,b"` or `["a","b"]`).
|
|
212
212
|
|
|
213
213
|
Arguments are a **flat JSON object** keyed by option and positional names (same names as in your schema, including hyphenated option names like `"user-name"`).
|
|
214
214
|
|
|
@@ -19,5 +19,6 @@ When adding or changing argsbarg schema, leaf handlers, or MCP exposure:
|
|
|
19
19
|
- Interactive leaves: one headless path for MCP, non-TTY CLI, and `--yes` / `--dry-run` / `--json` (`shouldRunHeadless*`, `requireYesInNonTty`); not raw `isTTY`.
|
|
20
20
|
- String options: `format` / `default` / `pattern` per `cli-program.md`; `readLeafInputs()` for multi-flag leaves.
|
|
21
21
|
- Varargs (`argMax: 0`): CLI space-separated; MCP JSON array only — no comma-splitting positionals.
|
|
22
|
+
- Multi-surface leaves (Ink + headless + MCP): one **`read*Flags(ctx)`** per command (or shared family helper + extensions); one **`resolve*Input(flags)`** for cross-field rules — handler reads ctx once, all paths share the struct.
|
|
22
23
|
|
|
23
24
|
**App-specific conventions:** add below or in a separate `.cursor/rules/` file (shared flags path, Ink vs JSON-only, etc.).
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
/*
|
|
3
|
+
* Value formats demo: duration, comma-list, date, default, and readLeafInputs().
|
|
4
|
+
* Run: bun ./examples/formats.ts run --tags alpha,beta --on 2026-06-22
|
|
5
|
+
* MCP: pass comma-list as string or array; varargs N/A on this leaf.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import pkg from "../package.json" with { type: "json" };
|
|
9
|
+
import { cliRun, CliFallbackMode, CliOptionKind, CliValueFormat, type CliProgram } from "../src/index.ts";
|
|
10
|
+
|
|
11
|
+
const cli = {
|
|
12
|
+
key: "formats.ts",
|
|
13
|
+
version: pkg.version,
|
|
14
|
+
description: "Value formats and readLeafInputs demo.",
|
|
15
|
+
fallbackCommand: "run",
|
|
16
|
+
fallbackMode: CliFallbackMode.MissingOnly,
|
|
17
|
+
mcpServer: { enabled: true },
|
|
18
|
+
commands: [
|
|
19
|
+
{
|
|
20
|
+
key: "run",
|
|
21
|
+
description: "Print coerced option values from readLeafInputs().",
|
|
22
|
+
options: [
|
|
23
|
+
{
|
|
24
|
+
name: "timeout",
|
|
25
|
+
description: "Wait budget (default 30s).",
|
|
26
|
+
kind: CliOptionKind.String,
|
|
27
|
+
format: CliValueFormat.Duration,
|
|
28
|
+
default: "30s",
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
name: "tags",
|
|
32
|
+
description: "Comma-separated labels.",
|
|
33
|
+
kind: CliOptionKind.String,
|
|
34
|
+
format: CliValueFormat.CommaList,
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
name: "on",
|
|
38
|
+
description: "Calendar day (YYYY-MM-DD).",
|
|
39
|
+
kind: CliOptionKind.String,
|
|
40
|
+
format: CliValueFormat.Date,
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
name: "verbose",
|
|
44
|
+
description: "Also print raw ctx.opts strings.",
|
|
45
|
+
kind: CliOptionKind.Presence,
|
|
46
|
+
shortName: "v",
|
|
47
|
+
},
|
|
48
|
+
],
|
|
49
|
+
handler: (ctx) => {
|
|
50
|
+
const inputs = ctx.readLeafInputs();
|
|
51
|
+
const out = {
|
|
52
|
+
readLeafInputs: inputs,
|
|
53
|
+
durationMs: ctx.durationOpt("timeout"),
|
|
54
|
+
tags: ctx.commaListOpt("tags"),
|
|
55
|
+
on: ctx.dateOpt("on"),
|
|
56
|
+
};
|
|
57
|
+
if (ctx.hasFlag("verbose")) {
|
|
58
|
+
Object.assign(out, { rawOpts: ctx.opts });
|
|
59
|
+
}
|
|
60
|
+
process.stdout.write(`${JSON.stringify(out, null, 2)}\n`);
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
],
|
|
64
|
+
} satisfies CliProgram;
|
|
65
|
+
|
|
66
|
+
await cliRun(cli);
|