argsbarg 3.6.4 → 4.0.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 -2
- package/README.md +21 -9
- package/docs/README.md +12 -8
- package/docs/bundled-docs.md +1 -1
- package/docs/cli-program.md +62 -2
- package/docs/config-schema.md +192 -0
- package/docs/developing.md +13 -0
- package/docs/install.md +38 -1
- package/docs/mcp.md +43 -19
- package/docs/output-schema.md +74 -52
- package/docs/templates/cursor/rules/cli-program.mdc +10 -5
- package/examples/config-app/main.ts +20 -0
- package/examples/config-app/program.ts +81 -0
- package/examples/config-app/schema.ts +37 -0
- package/examples/config-app/types.ts +19 -0
- package/examples/consumer-app/README.md +56 -0
- package/examples/consumer-app/bun.lock +75 -0
- package/examples/consumer-app/capabilities.test.ts +69 -0
- package/examples/consumer-app/package.json +17 -0
- package/examples/consumer-app/schemas/configSchemas.ts +6 -0
- package/examples/consumer-app/schemas/generated/app-config.json +40 -0
- package/examples/consumer-app/schemas/generated/status.json +28 -0
- package/examples/consumer-app/schemas/outputSchemas.ts +6 -0
- package/examples/consumer-app/scripts/schemagen/discover-schema-roots.test.ts +25 -0
- package/examples/consumer-app/scripts/schemagen/discover-schema-roots.ts +93 -0
- package/examples/consumer-app/scripts/schemagen/naming.ts +82 -0
- package/examples/consumer-app/scripts/schemagen.ts +76 -0
- package/examples/consumer-app/src/commands/status/types.ts +11 -0
- package/examples/consumer-app/src/main.ts +15 -0
- package/examples/consumer-app/src/program.ts +116 -0
- package/examples/consumer-app/src/types.ts +23 -0
- package/examples/consumer-app/tsconfig.json +14 -0
- package/examples/formats.ts +10 -3
- package/examples/mcp-test.ts +27 -8
- package/examples/minimal.ts +4 -3
- package/examples/nested.ts +5 -4
- package/examples/option-required.ts +8 -4
- package/index.d.ts +152 -75
- package/package.json +1 -1
- package/src/builtins/builtins.test.ts +13 -0
- package/src/builtins/config.test.ts +82 -0
- package/src/builtins/config.ts +220 -0
- package/src/builtins/dispatch.ts +18 -9
- package/src/builtins/export.ts +8 -33
- package/src/builtins/index.ts +1 -0
- package/src/builtins/install.ts +13 -0
- package/src/builtins/mcp.ts +1 -1
- package/src/builtins/presentation.ts +2 -17
- package/src/builtins/registry.ts +40 -0
- package/src/capabilities.ts +46 -0
- package/src/cli-errors.ts +15 -0
- package/src/cli.ts +389 -0
- package/src/config/bootstrap.ts +265 -0
- package/src/config/context.test.ts +61 -0
- package/src/config/context.ts +98 -0
- package/src/config/entry.ts +81 -0
- package/src/config/file.test.ts +112 -0
- package/src/config/file.ts +120 -0
- package/src/config/manifest.ts +62 -0
- package/src/config/resolve.test.ts +88 -0
- package/src/config/resolve.ts +167 -0
- package/src/config/schema.ts +101 -0
- package/src/config/validate.test.ts +63 -0
- package/src/config/validate.ts +292 -0
- package/src/config.integration.test.ts +100 -0
- package/src/context.ts +5 -0
- package/src/docs/docs.test.ts +16 -16
- package/src/docs/mcp-guide.ts +35 -11
- package/src/hidden-mcpb.test.ts +40 -2
- package/src/index.ts +4 -3
- package/src/install/index.ts +46 -3
- package/src/install/paths.ts +5 -20
- package/src/install/plan.ts +6 -0
- package/src/install/status.ts +12 -0
- package/src/install/uninstall.ts +11 -0
- package/src/install/update.test.ts +5 -5
- package/src/invoke.test.ts +207 -0
- package/src/mcp/bundle.ts +9 -116
- package/src/mcp/claude.test.ts +73 -0
- package/src/mcp/claude.ts +168 -0
- package/src/mcp/env.ts +3 -37
- package/src/mcp/server.ts +18 -10
- package/src/mcp/tools.ts +3 -7
- package/src/mcp/zip.ts +82 -0
- package/src/mcp.integration.test.ts +502 -0
- package/src/{index.test.ts → parse.test.ts} +24 -935
- package/src/paths/host.ts +40 -0
- package/src/schema.ts +1 -1
- package/src/skill/generate.ts +18 -5
- package/src/skill/hint.ts +18 -0
- package/src/skill/install.ts +1 -5
- package/src/test-fixtures.ts +192 -0
- package/src/types.ts +39 -13
- package/src/validate.ts +70 -0
- package/src/completion.ts +0 -13
- package/src/invoke.ts +0 -217
- package/src/mcp.ts +0 -28
- package/src/runtime.ts +0 -134
package/CHANGELOG.md
CHANGED
|
@@ -7,11 +7,36 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [4.0.0] - 2026-06-24
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- **`Cli` class** — single runtime entry: eager `cliValidateProgram` + `Object.freeze(program)` in constructor; `run()`, `invoke()`, `serveMcp()`; lazy `cli.appConfig` getter (refreshed on dispatch); `exportCommandSchema()` and `exportAppConfigSchema()`.
|
|
15
|
+
- **`program.appConfig` + `CliAppConfig` / `CliAppConfigEntry`** — config-first model: flat JSON file, block `jsonSchema` (or all-string fallback), metadata overlay per key (`entries`), strict load (reject unknown keys), `ctx.appConfig` (`get`, `require`, `set`, `read`), built-in `config get`/`set`, zero-deps draft-07 subset validation.
|
|
16
|
+
- **`docs/config-schema.md`** — recommended TypeScript → JSON Schema codegen for `program.appConfig.jsonSchema` (parallel to output-schema guide).
|
|
17
|
+
- **`examples/consumer-app/`** — kitchen-sink copy template: all builtins, schemagen discovery, `outputSchema`, `from "argsbarg"`.
|
|
18
|
+
- **`mcp bundle` Claude Code plugin** — writes `dist/<key>-plugin/` (`.claude-plugin/plugin.json`, `.mcp.json`, `bin/<key>`, skills) alongside `dist/<key>.mcpb`.
|
|
19
|
+
|
|
20
|
+
### Changed
|
|
21
|
+
|
|
22
|
+
- **Breaking:** **`cliRun`, `cliInvoke`, `cliMcpServeStdio` removed** — use `new Cli(program).run()`, `.invoke(argv)`, `.serveMcp()` instead.
|
|
23
|
+
- **Breaking:** **`program.config` → `program.appConfig`**, **`schema` → `entries`**, **`CliConfig` → `CliAppConfig`**, **`ctx.config` → `ctx.appConfig`**.
|
|
24
|
+
- **Breaking:** **`program.env` + `CliEnvVarConfig` removed** — use `program.appConfig.entries`; root `configFile` → `appConfig.path`; nested env bag → flat schema keys; no extra file keys / `raw()`.
|
|
25
|
+
- **Breaking:** Handler config access — prefer `ctx.appConfig.get/require` over `process.env` for app config (env export remains for subprocesses).
|
|
26
|
+
- **`mcp bundle`** — stdout prints both `.mcpb` and plugin directory paths (one line each).
|
|
27
|
+
- **MCP config enforcement** — required keys from `program.appConfig` checked at `tools/call` (MCP) or before leaf dispatch (CLI).
|
|
28
|
+
|
|
29
|
+
### Removed
|
|
30
|
+
|
|
31
|
+
- **`mcpTool.requiresEnv`** — use `program.appConfig` schema entries with `env` instead.
|
|
32
|
+
- **`mcpServer.envFile`** — use `program.appConfig` + JSON config file instead.
|
|
33
|
+
- **`loadAppConfigEnv`, `ensureProgramEnv`** — replaced internally by `ensureAppConfig`, `exportConfigToEnv`.
|
|
34
|
+
|
|
10
35
|
## [3.6.4] - 2026-06-23
|
|
11
36
|
|
|
12
37
|
### Added
|
|
13
38
|
|
|
14
|
-
- **`docs/output-schema.md`** — recommended TypeScript → JSON Schema codegen
|
|
39
|
+
- **`docs/output-schema.md`** — recommended TypeScript → JSON Schema codegen for leaf `outputSchema`: `JSON payload` JSDoc discovery in `src/**/types.ts`, auto-generated `outputSchemas.ts` bridge, naming suffixes, JSDoc quality bar, narrowing, CI.
|
|
15
40
|
|
|
16
41
|
### Changed
|
|
17
42
|
|
|
@@ -424,7 +449,8 @@ const cli = { ... } satisfies CliProgram; // or : CliProgram
|
|
|
424
449
|
- 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`).
|
|
425
450
|
- Imports: use `CliPositional` where needed; replace `CliOptionDef` with `CliOption` or `CliPositional` as appropriate.
|
|
426
451
|
|
|
427
|
-
[Unreleased]: https://github.com/bdombro/bun-argsbarg/compare/
|
|
452
|
+
[Unreleased]: https://github.com/bdombro/bun-argsbarg/compare/v4.0.0...HEAD
|
|
453
|
+
[4.0.0]: https://github.com/bdombro/bun-argsbarg/releases/tag/v4.0.0
|
|
428
454
|
[3.6.4]: https://github.com/bdombro/bun-argsbarg/releases/tag/v3.6.4
|
|
429
455
|
[3.6.3]: https://github.com/bdombro/bun-argsbarg/releases/tag/v3.6.3
|
|
430
456
|
[3.6.2]: https://github.com/bdombro/bun-argsbarg/releases/tag/v3.6.2
|
package/README.md
CHANGED
|
@@ -35,9 +35,9 @@ Shell completions! -->
|
|
|
35
35
|
## Usage
|
|
36
36
|
|
|
37
37
|
```typescript
|
|
38
|
-
import {
|
|
38
|
+
import { Cli, type CliProgram, CliOptionKind } from "argsbarg";
|
|
39
39
|
|
|
40
|
-
const
|
|
40
|
+
const program = {
|
|
41
41
|
key: "helloapp",
|
|
42
42
|
version: "1.0.0",
|
|
43
43
|
description: "Tiny demo.",
|
|
@@ -67,10 +67,11 @@ const cli = {
|
|
|
67
67
|
},
|
|
68
68
|
} satisfies CliProgram;
|
|
69
69
|
|
|
70
|
-
|
|
70
|
+
const cli = new Cli(program);
|
|
71
|
+
await cli.run();
|
|
71
72
|
```
|
|
72
73
|
|
|
73
|
-
`
|
|
74
|
+
`Cli.run()` parses `process.argv`, prints help or errors, dispatches the leaf handler, and **exits the process**.
|
|
74
75
|
|
|
75
76
|
|
|
76
77
|
|
|
@@ -95,7 +96,7 @@ Everything you need for a first-class CLI:
|
|
|
95
96
|
Every app gets:
|
|
96
97
|
|
|
97
98
|
- `-h` / `--help` at any routing depth (scoped help).
|
|
98
|
-
- **`completion bash` / `completion zsh` / `completion fish`** — print shell completion scripts to stdout (injected by `
|
|
99
|
+
- **`completion bash` / `completion zsh` / `completion fish`** — print shell completion scripts to stdout (injected by `Cli.run()`).
|
|
99
100
|
- **`version`** — print `CliProgram.version` (`myapp version`).
|
|
100
101
|
- **`mcp`** — when `mcpServer.enabled` is `true`, run as an MCP stdio server (`myapp mcp`).
|
|
101
102
|
- **`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).
|
|
@@ -108,7 +109,7 @@ When **`docs.enabled`** is `true`, do not declare a top-level command named **`d
|
|
|
108
109
|
|
|
109
110
|
### MCP (AI agents)
|
|
110
111
|
|
|
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
|
|
112
|
+
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`; use `cli.invoke(argv)` for headless testing.
|
|
112
113
|
|
|
113
114
|
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
115
|
|
|
@@ -161,7 +162,7 @@ Add app-specific conventions in a second rule if needed. Copy the rule from the
|
|
|
161
162
|
## How it works
|
|
162
163
|
|
|
163
164
|
1. Build a **program root** with `satisfies CliProgram` (or `: CliProgram`): `key` is the app/binary name, `commands` are top-level subcommands, `options` are global flags. A router root must not set `handler` or declare `positionals` (validated at startup). A leaf root may set `handler` and `positionals` directly. Use `fallbackCommand` / `fallbackMode` on any **routing node** for default subcommand routing (not root-only).
|
|
164
|
-
2. Call `await
|
|
165
|
+
2. Call `await new Cli(program).run()` — validates, parses argv, renders help or errors, invokes the leaf handler, and `process.exit`s with status **0** on success, **1** on implicit help or error (explicit `--help` → **0**).
|
|
165
166
|
3. From a handler, `cliErrWithHelp(ctx, "message")` prints a red error line plus contextual help on stderr and exits **1**.
|
|
166
167
|
|
|
167
168
|
### Fallback modes (`CliFallbackMode`)
|
|
@@ -215,6 +216,10 @@ Check the `examples/` directory for full working scripts:
|
|
|
215
216
|
| `ArgsBargMinimal` | `examples/minimal.ts` | String + presence flags, `MissingOrUnknown` fallback. |
|
|
216
217
|
| `ArgsBargNested` | `examples/nested.ts` | Nested command tree, positional tails, async handlers. |
|
|
217
218
|
| `ArgsBargFormats` | `examples/formats.ts` | `CliValueFormat`, `default`, `readLeafInputs()`. |
|
|
219
|
+
| `ArgsBargConfigApp` | `examples/config-app/` | `program.appConfig`, `ctx.appConfig`, built-in `config get`/`set`, inline JSON Schema. |
|
|
220
|
+
| `ArgsBargConsumerApp` | `examples/consumer-app/` | **Copy template:** all builtins, schemagen discovery, `outputSchema`, `from "argsbarg"`. |
|
|
221
|
+
|
|
222
|
+
Examples ship in the npm package under `node_modules/argsbarg/examples/`. Agents should read **`config-app`** for concepts and **`consumer-app`** when scaffolding a full CLI.
|
|
218
223
|
|
|
219
224
|
```bash
|
|
220
225
|
export PATH="$PATH:$(pwd)/examples"
|
|
@@ -228,6 +233,12 @@ nested.ts stat owner lookup -u alice ./README.md
|
|
|
228
233
|
nested.ts read ./README.md
|
|
229
234
|
|
|
230
235
|
bun ./examples/formats.ts run --tags demo,docs --on 2026-06-22
|
|
236
|
+
|
|
237
|
+
CONFIG_APP_API_TOKEN=dev bun ./examples/config-app/main.ts show --json
|
|
238
|
+
CONFIG_APP_API_TOKEN=dev bun ./examples/config-app/main.ts config get
|
|
239
|
+
|
|
240
|
+
cd examples/consumer-app && bun install && bun run schemagen
|
|
241
|
+
CONSUMER_APP_API_TOKEN=dev bun run start status --json
|
|
231
242
|
```
|
|
232
243
|
|
|
233
244
|
|
|
@@ -243,8 +254,9 @@ The package root (`argsbarg` / `src/index.ts`) exports the types and runtime you
|
|
|
243
254
|
| `CliSchemaValidationError` | Thrown when the static command tree violates schema rules. |
|
|
244
255
|
| `CliContext` | Handler context (`ctx.hasFlag`, `ctx.stringOpt`, `ctx.durationOpt`, `ctx.readLeafInputs`, `ctx.invocation`, …). |
|
|
245
256
|
| `CliLeafInputs` | Record type returned by `readLeafInputs()` — coerced option/positional values keyed by schema name. |
|
|
246
|
-
| `
|
|
247
|
-
| `
|
|
257
|
+
| `Cli` | Runtime: validate + freeze program, `run()`, `invoke()`, `serveMcp()`, `appConfig` getter, `exportCommandSchema()`, `exportAppConfigSchema()`. |
|
|
258
|
+
| `CliInvokeResult`, `CliInvokeKind` | Result types from `cli.invoke()`. |
|
|
259
|
+
| `CliAppConfig`, `CliAppConfigEntry` | App config block on the program root (`entries` metadata overlay + optional `jsonSchema`). |
|
|
248
260
|
| `cliErrWithHelp(ctx, msg)` | Print error + scoped help on stderr, exit 1. |
|
|
249
261
|
| `parseDurationMs`, `parseCommaList`, `parseDate`, `parseDateTime` | Optional format parsers for use outside handlers. |
|
|
250
262
|
|
package/docs/README.md
CHANGED
|
@@ -7,12 +7,24 @@ Start here to pick the right guide.
|
|
|
7
7
|
| **New to argsbarg** | [../README.md](../README.md) — install, minimal usage, public API |
|
|
8
8
|
| **Authoring a `CliProgram`** (humans or agents) | [cli-program.md](cli-program.md) — schema, formats, headless, `read*Flags` |
|
|
9
9
|
| **JSON stdout / `outputSchema`** | [output-schema.md](output-schema.md) — codegen pipeline, JSDoc, narrowing |
|
|
10
|
+
| **App config / `program.appConfig`** | [config-schema.md](config-schema.md) — flat JSON file, `ctx.appConfig`, codegen |
|
|
10
11
|
| **Exposing MCP tools** | [mcp.md](mcp.md) — stdio server, `inputSchema`, varargs, `install --mcp` |
|
|
11
12
|
| **Shipping install / completions / skills** | [install.md](install.md) — `myapp install`, shell completions |
|
|
12
13
|
| **Bundling `myapp docs` topics** | [bundled-docs.md](bundled-docs.md) — consumer docgen vs framework docs |
|
|
13
14
|
| **Agent skills** | [ai-skills.md](ai-skills.md) — `install --skill`, `docs skill` |
|
|
14
15
|
| **Maintaining the argsbarg repo** | [developing.md](developing.md) — release, consumers, npm `files` |
|
|
15
16
|
| **Cursor / IDE agents in a consumer app** | Copy [templates/cursor/rules/cli-program.mdc](templates/cursor/rules/cli-program.mdc) to `.cursor/rules/` |
|
|
17
|
+
| **Runnable examples** (shipped in npm) | [examples/](examples/) — see table below |
|
|
18
|
+
|
|
19
|
+
## Examples (agents: read these)
|
|
20
|
+
|
|
21
|
+
Examples are included in the npm tarball (`package.json` `files`). After `bun add argsbarg`, open `node_modules/argsbarg/examples/`.
|
|
22
|
+
|
|
23
|
+
| Tier | Path | Use when |
|
|
24
|
+
| --- | --- | --- |
|
|
25
|
+
| Learn | [examples/minimal.ts](../examples/minimal.ts), [config-app/](../examples/config-app/) | One feature at a time |
|
|
26
|
+
| Reference | [examples/nested.ts](../examples/nested.ts), [formats.ts](../examples/formats.ts) | Routing, formats, MCP snippet |
|
|
27
|
+
| **Copy** | [examples/consumer-app/](../examples/consumer-app/) | Bootstrapping a production CLI (all builtins + schemagen) |
|
|
16
28
|
|
|
17
29
|
## Framework docs vs consumer docgen
|
|
18
30
|
|
|
@@ -23,11 +35,3 @@ Start here to pick the right guide.
|
|
|
23
35
|
| **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 |
|
|
24
36
|
|
|
25
37
|
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.
|
|
26
|
-
|
|
27
|
-
## Examples
|
|
28
|
-
|
|
29
|
-
| Example | Shows |
|
|
30
|
-
| --- | --- |
|
|
31
|
-
| [../examples/minimal.ts](../examples/minimal.ts) | Presence + string flags, fallback routing |
|
|
32
|
-
| [../examples/nested.ts](../examples/nested.ts) | Nested commands, varargs, MCP + `docs` |
|
|
33
|
-
| [../examples/formats.ts](../examples/formats.ts) | `CliValueFormat`, `default`, `readLeafInputs()` |
|
package/docs/bundled-docs.md
CHANGED
|
@@ -87,7 +87,7 @@ When `docs.enabled` is `true`:
|
|
|
87
87
|
|
|
88
88
|
## MCP guide (`docs mcp`)
|
|
89
89
|
|
|
90
|
-
When both `docs.enabled` and `mcpServer.enabled` are `true`, ArgsBarg injects a **`docs mcp`** topic with an auto-generated guide: tool list, `
|
|
90
|
+
When both `docs.enabled` and `mcpServer.enabled` are `true`, ArgsBarg injects a **`docs mcp`** topic with an auto-generated guide: tool list, `program.appConfig`, schema resource URI, `install --mcp`, and protocol notes.
|
|
91
91
|
|
|
92
92
|
There is no override API in v1 — customize behavior via `mcpTool.description` on leaf commands.
|
|
93
93
|
|
package/docs/cli-program.md
CHANGED
|
@@ -112,7 +112,6 @@ Many "MCP problems" are schema or handler gaps. Prefer these over escape hatches
|
|
|
112
112
|
| Field | Use when |
|
|
113
113
|
| --- | --- |
|
|
114
114
|
| `enabled: false` | Command is **genuinely** CLI-only (open browser, Ink-only flow with no scriptable equivalent) |
|
|
115
|
-
| `requiresEnv: [...]` | Runtime secrets; appended to MCP description and enforced at `tools/call` |
|
|
116
115
|
| `description: "..."` | **Irreducible** MCP limitation (e.g. live tail / `--watch` cannot be streamed on the MCP wire yet) |
|
|
117
116
|
|
|
118
117
|
### Structured stdout
|
|
@@ -373,9 +372,70 @@ handler: async (ctx) => {
|
|
|
373
372
|
|
|
374
373
|
Basic synchronous handlers do not need this structure — only commands with an interactive branch.
|
|
375
374
|
|
|
375
|
+
## Configuration (`program.appConfig`)
|
|
376
|
+
|
|
377
|
+
Declare app configuration on the **program root** (not on leaves). Values persist in a flat JSON file; handlers read resolved values via `ctx.appConfig`.
|
|
378
|
+
|
|
379
|
+
```typescript
|
|
380
|
+
import { Cli, type CliProgram } from "argsbarg";
|
|
381
|
+
import { APP_CONFIG_JSON_SCHEMA } from "./schemas/configSchemas.js";
|
|
382
|
+
|
|
383
|
+
const program = {
|
|
384
|
+
key: "myapp",
|
|
385
|
+
version: "1.0.0",
|
|
386
|
+
description: "…",
|
|
387
|
+
appConfig: {
|
|
388
|
+
path: "~/.config/myapp/config", // optional override
|
|
389
|
+
jsonSchema: APP_CONFIG_JSON_SCHEMA, // optional; omit for all-string mode
|
|
390
|
+
entries: {
|
|
391
|
+
apiToken: {
|
|
392
|
+
description: "Create at https://example.com/settings/tokens",
|
|
393
|
+
env: "API_TOKEN",
|
|
394
|
+
sensitive: true,
|
|
395
|
+
},
|
|
396
|
+
defaultRegion: {
|
|
397
|
+
title: "Default region",
|
|
398
|
+
description: "AWS region (default us-east-1).",
|
|
399
|
+
required: false,
|
|
400
|
+
},
|
|
401
|
+
maxRetries: { description: "Retry count." },
|
|
402
|
+
},
|
|
403
|
+
},
|
|
404
|
+
handler: (ctx) => {
|
|
405
|
+
const token = ctx.appConfig.require("apiToken");
|
|
406
|
+
const region = ctx.appConfig.get("defaultRegion");
|
|
407
|
+
},
|
|
408
|
+
} satisfies CliProgram;
|
|
409
|
+
|
|
410
|
+
const cli = new Cli(program);
|
|
411
|
+
await cli.run();
|
|
412
|
+
```
|
|
413
|
+
|
|
414
|
+
| Field | Default | Purpose |
|
|
415
|
+
| --- | --- | --- |
|
|
416
|
+
| `description` | *(required)* | Shown in prompts, `config get`, and bundle manifests |
|
|
417
|
+
| `title` | config key | Short label in `install --configure` |
|
|
418
|
+
| `default` | — | Used when `jsonSchema` omitted (all-string mode) |
|
|
419
|
+
| `required` | `true` | When `false`, optional unless required by `jsonSchema` |
|
|
420
|
+
| `sensitive` | name heuristic (`token`, `secret`, …) | Redact in prompts, `config get`, and status |
|
|
421
|
+
| `env` | — | When set: non-empty host env overrides file; exported to `process.env` after resolve |
|
|
422
|
+
|
|
423
|
+
**Config file** (created on demand):
|
|
424
|
+
|
|
425
|
+
- Default: `$XDG_CONFIG_HOME/<sanitized-key>/config` or `%APPDATA%/<key>/config`.
|
|
426
|
+
- JSON: flat object keyed by schema names — `{ "apiToken": "…", "maxRetries": 5 }`.
|
|
427
|
+
- **Strict:** unknown keys rejected on load.
|
|
428
|
+
- **CLI:** missing required config exits 1 before the leaf handler (TTY prompt when interactive). Built-in `config get`/`set` skip this exit.
|
|
429
|
+
- **MCP:** server stays up; missing config returns `isError: true` at `tools/call`.
|
|
430
|
+
- **Configure:** `myapp install --configure` (not part of `--all`).
|
|
431
|
+
|
|
432
|
+
See [config-schema.md](config-schema.md) for codegen, [install.md](install.md), and [mcp.md](mcp.md).
|
|
433
|
+
|
|
434
|
+
**Handler access (`ctx.appConfig`):** `get`, `require`, `set`, `read` — prefer over `process.env` in handlers; env export remains for subprocess inheritance.
|
|
435
|
+
|
|
376
436
|
## Reserved names
|
|
377
437
|
|
|
378
|
-
Do not declare user commands named `completion`, `install`, `mcp`, `version`, or `
|
|
438
|
+
Do not declare user commands named `completion`, `install`, `mcp`, `version`, `docs`, or `config` at the root — ArgsBarg injects these when configured.
|
|
379
439
|
|
|
380
440
|
## Cursor rule for consumer repos
|
|
381
441
|
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
# Config schema (`program.appConfig`)
|
|
2
|
+
|
|
3
|
+
How to declare app configuration — flat JSON file, env overrides, handler access via `ctx.appConfig`, and a **recommended codegen pipeline** for typed config.
|
|
4
|
+
|
|
5
|
+
## Argsbarg contract
|
|
6
|
+
|
|
7
|
+
On the **program root**, set `appConfig` with metadata `entries` and optional block `jsonSchema`:
|
|
8
|
+
|
|
9
|
+
```typescript
|
|
10
|
+
import { Cli, type CliProgram } from "argsbarg";
|
|
11
|
+
import { APP_CONFIG_JSON_SCHEMA } from "./schemas/configSchemas.js";
|
|
12
|
+
|
|
13
|
+
const program = {
|
|
14
|
+
key: "myapp",
|
|
15
|
+
version: "1.0.0",
|
|
16
|
+
description: "…",
|
|
17
|
+
appConfig: {
|
|
18
|
+
jsonSchema: APP_CONFIG_JSON_SCHEMA,
|
|
19
|
+
entries: {
|
|
20
|
+
apiToken: {
|
|
21
|
+
description: "Create at https://example.com/settings/tokens",
|
|
22
|
+
env: "API_TOKEN",
|
|
23
|
+
sensitive: true,
|
|
24
|
+
},
|
|
25
|
+
defaultRegion: { description: "AWS region.", required: false },
|
|
26
|
+
maxRetries: { description: "Retry count." },
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
handler: (ctx) => {
|
|
30
|
+
const token = ctx.appConfig.require("apiToken");
|
|
31
|
+
const region = ctx.appConfig.get("defaultRegion"); // default already applied
|
|
32
|
+
},
|
|
33
|
+
} satisfies CliProgram;
|
|
34
|
+
|
|
35
|
+
const cli = new Cli(program);
|
|
36
|
+
await cli.run();
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
| Where argsbarg uses it | Purpose |
|
|
40
|
+
| --- | --- |
|
|
41
|
+
| Config file | Flat JSON keyed by schema names; strict load (unknown keys rejected) |
|
|
42
|
+
| `install --configure` / `--status` | Interactive setup and status |
|
|
43
|
+
| Built-in `config get` / `config set` | Read/write resolved values (opt-out via `commands: false`) |
|
|
44
|
+
| MCP bundle / Claude plugin | `userConfig` for entries with `env` set |
|
|
45
|
+
| `ctx.appConfig` in handlers | `get`, `require`, `set`, `read` — prefer over `process.env` |
|
|
46
|
+
|
|
47
|
+
**Validation at runtime** — argsbarg validates the config file and `config set` / `ctx.appConfig.set` against the effective JSON Schema (block `jsonSchema` or synthesized all-string schema).
|
|
48
|
+
|
|
49
|
+
**No public config I/O exports** — consumers use `program.appConfig` for authoring and `ctx.appConfig` in handlers.
|
|
50
|
+
|
|
51
|
+
See [cli-program.md — Configuration](cli-program.md#configuration-programappconfig) for resolution order, bootstrap timing, and reserved `config` command.
|
|
52
|
+
|
|
53
|
+
## `CliAppConfig` and `CliAppConfigEntry`
|
|
54
|
+
|
|
55
|
+
```typescript
|
|
56
|
+
export interface CliAppConfigEntry {
|
|
57
|
+
description: string;
|
|
58
|
+
title?: string; // default: config key
|
|
59
|
+
default?: string; // all-string mode only
|
|
60
|
+
required?: boolean; // default: true (can override jsonSchema required)
|
|
61
|
+
sensitive?: boolean; // default: name heuristic
|
|
62
|
+
env?: string; // env override + export to process.env after resolve
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export interface CliAppConfig {
|
|
66
|
+
path?: string; // default: ~/.config/<key>/config (OS rules)
|
|
67
|
+
commands?: boolean | { enabled?: boolean; mcpSet?: boolean };
|
|
68
|
+
jsonSchema?: Record<string, unknown>; // draft-07 block schema
|
|
69
|
+
entries: Record<string, CliAppConfigEntry>;
|
|
70
|
+
}
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
**Conventions:**
|
|
74
|
+
|
|
75
|
+
- Secrets: `env: "API_TOKEN"` on entry; file key `apiToken`
|
|
76
|
+
- Prefs without env: local-file only; excluded from MCP/plugin manifests
|
|
77
|
+
- MCP manifests: only entries with `env` set (sanitized to snake_case keys)
|
|
78
|
+
|
|
79
|
+
## Config file shape
|
|
80
|
+
|
|
81
|
+
Flat JSON at `config.path` (default OS path unchanged):
|
|
82
|
+
|
|
83
|
+
```json
|
|
84
|
+
{
|
|
85
|
+
"apiToken": "xxx",
|
|
86
|
+
"defaultRegion": "eu-west-1",
|
|
87
|
+
"maxRetries": 5,
|
|
88
|
+
"prefs": { "ttl": 3600 }
|
|
89
|
+
}
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
No nested `env` bag. No extra keys — rejected on load.
|
|
93
|
+
|
|
94
|
+
## Resolution order (per schema key)
|
|
95
|
+
|
|
96
|
+
| Key has `env`? | Resolved value |
|
|
97
|
+
| --- | --- |
|
|
98
|
+
| **Yes** | non-empty `process.env[env]` → else file[key] → else default |
|
|
99
|
+
| **No** | file[key] → else default |
|
|
100
|
+
|
|
101
|
+
Empty string in env or file counts as **missing** for required entries. After resolution, mapped values are exported to `process.env`.
|
|
102
|
+
|
|
103
|
+
## Hand-written vs generated
|
|
104
|
+
|
|
105
|
+
| Approach | When |
|
|
106
|
+
| --- | --- |
|
|
107
|
+
| **Omit `jsonSchema`** | Simple apps; all values stored as strings; use `entry.default` |
|
|
108
|
+
| **Codegen from TypeScript** | Typed config, nested objects, shared with JSON Schema CI |
|
|
109
|
+
|
|
110
|
+
## Recommended pipeline (copy per repo)
|
|
111
|
+
|
|
112
|
+
Mirror the [output-schema.md](output-schema.md) pattern for config:
|
|
113
|
+
|
|
114
|
+
```mermaid
|
|
115
|
+
flowchart LR
|
|
116
|
+
subgraph types [Schema-facing TS + JSDoc]
|
|
117
|
+
TypesTs["src/**/types.ts"]
|
|
118
|
+
Marker["JSDoc contains Config schema"]
|
|
119
|
+
end
|
|
120
|
+
subgraph gen [just schemagen]
|
|
121
|
+
Script["scripts/generate-config-schemas.ts"]
|
|
122
|
+
Gen["ts-json-schema-generator"]
|
|
123
|
+
end
|
|
124
|
+
subgraph artifacts [Committed]
|
|
125
|
+
Json["src/schemas/generated/app-config.json"]
|
|
126
|
+
Bridge["src/schemas/configSchemas.ts"]
|
|
127
|
+
end
|
|
128
|
+
subgraph runtime [Runtime]
|
|
129
|
+
Program["program.appConfig.jsonSchema"]
|
|
130
|
+
Validate["argsbarg runtime subset validator"]
|
|
131
|
+
end
|
|
132
|
+
TypesTs --> Marker --> Script --> Gen --> Json
|
|
133
|
+
Script --> Bridge --> Program --> Validate
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
| Piece | Convention |
|
|
137
|
+
| --- | --- |
|
|
138
|
+
| Generator | [`ts-json-schema-generator`](https://github.com/vega/ts-json-schema-generator) |
|
|
139
|
+
| Discovery | JSDoc marker **`Config schema`** on the root config interface |
|
|
140
|
+
| Artifacts | Commit `app-config.json` and `configSchemas.ts` bridge exporting `APP_CONFIG_JSON_SCHEMA` |
|
|
141
|
+
| Consumer CI | Optional: `ajv` + `ajv-formats` against the same committed JSON (not an argsbarg runtime dep) |
|
|
142
|
+
|
|
143
|
+
### Supported AppConfig shapes (argsbarg runtime validator)
|
|
144
|
+
|
|
145
|
+
| Supported (v1) | Deferred |
|
|
146
|
+
| --- | --- |
|
|
147
|
+
| `type`, `properties`, `required`, `additionalProperties` | remote `$ref` |
|
|
148
|
+
| `enum`, `const`, `default` | complex `if`/`then`/`else` |
|
|
149
|
+
| local `#/definitions` + `$ref` | full draft-2020-12 |
|
|
150
|
+
| `anyOf` / `oneOf` (basic) | |
|
|
151
|
+
| `items`, `minItems`, `maxItems` | |
|
|
152
|
+
| `minimum`, `maximum`, `minLength`, `maxLength`, `pattern` | |
|
|
153
|
+
|
|
154
|
+
## Minimal example (no schemagen)
|
|
155
|
+
|
|
156
|
+
```typescript
|
|
157
|
+
appConfig: {
|
|
158
|
+
entries: {
|
|
159
|
+
apiToken: { description: "Token.", env: "API_TOKEN", sensitive: true },
|
|
160
|
+
greeting: { description: "Greeting.", default: "hello", required: false },
|
|
161
|
+
},
|
|
162
|
+
},
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
All file values are strings. Defaults come from `entry.default`.
|
|
166
|
+
|
|
167
|
+
## Built-in `config` command
|
|
168
|
+
|
|
169
|
+
When `program.appConfig` is set and `commands !== false`:
|
|
170
|
+
|
|
171
|
+
| Subcommand | Purpose |
|
|
172
|
+
| --- | --- |
|
|
173
|
+
| `config get [key]` | Resolved value(s); `--json`; `--json --pretty` |
|
|
174
|
+
| `config set <key> <value>` | One key; full document re-validated after merge |
|
|
175
|
+
|
|
176
|
+
`config get`/`set` skip required-config exit and TTY prompts. Sensitive values redact on `get` (`REDACTED` / `{ "set": true }` with `--json`).
|
|
177
|
+
|
|
178
|
+
Object/array/`$ref` properties require `--json` on `config set`.
|
|
179
|
+
|
|
180
|
+
## Example in this repo
|
|
181
|
+
|
|
182
|
+
| Example | Role |
|
|
183
|
+
| --- | --- |
|
|
184
|
+
| [`examples/config-app/`](../examples/config-app/) | **Learn** — hand-written schema, minimal setup |
|
|
185
|
+
| [`examples/consumer-app/`](../examples/consumer-app/) | **Copy** — schemagen discovery, `APP_CONFIG_JSON_SCHEMA` bridge |
|
|
186
|
+
|
|
187
|
+
```bash
|
|
188
|
+
cd examples/consumer-app && bun install && bun run schemagen
|
|
189
|
+
CONSUMER_APP_API_TOKEN=dev bun run start config get apiToken --json
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
Set `CONSUMER_APP_CONFIG_FILE` to override the config file path.
|
package/docs/developing.md
CHANGED
|
@@ -49,6 +49,19 @@ Sibling repos under `../../ss/` (paths are machine-specific; adjust in `justfile
|
|
|
49
49
|
|
|
50
50
|
When adding docs or examples intended for consumers, ensure they live under whitelisted paths (`docs/`, `examples/`, `src/`, etc.).
|
|
51
51
|
|
|
52
|
+
Exclude `examples/consumer-app/node_modules/` from the npm tarball via [`.npmignore`](../.npmignore).
|
|
53
|
+
|
|
54
|
+
## Kitchen-sink example
|
|
55
|
+
|
|
56
|
+
[`examples/consumer-app/`](../examples/consumer-app/) must enable every builtin (`capabilities.test.ts`). After builtin or schemagen doc changes:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
just consumer-app-schemagen
|
|
60
|
+
just test
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
See [`.cursor/rules/examples.mdc`](../.cursor/rules/examples.mdc) for maintainer guidance.
|
|
64
|
+
|
|
52
65
|
## Docs
|
|
53
66
|
|
|
54
67
|
See [README.md](README.md) for the documentation map. Framework authoring guide: [cli-program.md](cli-program.md).
|
package/docs/install.md
CHANGED
|
@@ -32,6 +32,7 @@ myapp install --uninstall --all --yes
|
|
|
32
32
|
| Cursor skill | `--skill` | `~/.cursor/skills/<dir>/` when `~/.cursor` exists |
|
|
33
33
|
| Claude skill | `--skill` | `~/.claude/skills/<dir>/` when `~/.claude` exists |
|
|
34
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
|
+
| App config | `--config` | JSON config file for `program.appConfig` (with `--uninstall`; included in `--uninstall --all`) |
|
|
35
36
|
|
|
36
37
|
`--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
38
|
|
|
@@ -95,6 +96,42 @@ Environment:
|
|
|
95
96
|
|
|
96
97
|
- `INSTALL_PREFIX` — same as `install.prefix` / `--prefix`
|
|
97
98
|
|
|
99
|
+
## App config (`program.appConfig`)
|
|
100
|
+
|
|
101
|
+
When `program.appConfig` is set on the program root, ArgsBarg manages a flat JSON config file:
|
|
102
|
+
|
|
103
|
+
```typescript
|
|
104
|
+
appConfig: {
|
|
105
|
+
entries: {
|
|
106
|
+
apiToken: {
|
|
107
|
+
description: "Create at https://example.com/settings/tokens",
|
|
108
|
+
env: "API_TOKEN",
|
|
109
|
+
sensitive: true,
|
|
110
|
+
},
|
|
111
|
+
},
|
|
112
|
+
path: "~/.config/myapp/config", // optional; default is OS-specific
|
|
113
|
+
},
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
Default path: `$XDG_CONFIG_HOME/<sanitized-key>/config` (Linux/macOS) or `%APPDATA%/<key>/config` (Windows).
|
|
117
|
+
|
|
118
|
+
| Flag | Description |
|
|
119
|
+
| --- | --- |
|
|
120
|
+
| `--configure` | Interactive prompt for each schema entry; writes or updates the config file (standalone — not part of `--all`) |
|
|
121
|
+
| `--uninstall --config` | Remove the config file (included in `--uninstall --all`) |
|
|
122
|
+
| `--status` | Shows config path and which required keys are set or missing |
|
|
123
|
+
|
|
124
|
+
**Configure UX** (TTY):
|
|
125
|
+
|
|
126
|
+
```
|
|
127
|
+
API token
|
|
128
|
+
Create at https://example.com/settings/tokens
|
|
129
|
+
Current: REDACTED
|
|
130
|
+
Value (Enter to keep):
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
Non-sensitive vars show the current value; first-time setup omits the `Current:` line.
|
|
134
|
+
|
|
98
135
|
## Flags
|
|
99
136
|
|
|
100
137
|
| Flag | Description |
|
|
@@ -108,7 +145,7 @@ Environment:
|
|
|
108
145
|
| `--update` | Download latest release and reinstall installed artifacts (requires `install.updateGetLatest`; implies `--yes`) |
|
|
109
146
|
| `--from <path>` | Binary to copy with `--reinstall` (default: running executable) |
|
|
110
147
|
| `--status` | Read-only inventory |
|
|
111
|
-
| `--uninstall` | Remove artifacts in scope (`--all`, `--bin`, `--completions`, `--skill`, `--mcp`); skips targets not installed |
|
|
148
|
+
| `--uninstall` | Remove artifacts in scope (`--all`, `--bin`, `--completions`, `--skill`, `--mcp`, `--config`); skips targets not installed |
|
|
112
149
|
|
|
113
150
|
## MCP merge behavior
|
|
114
151
|
|