argsbarg 3.6.3 → 3.6.4

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 CHANGED
@@ -7,6 +7,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [3.6.4] - 2026-06-23
11
+
12
+ ### Added
13
+
14
+ - **`docs/output-schema.md`** — recommended TypeScript → JSON Schema codegen pipeline for leaf `outputSchema` (manifest, bridge, JSDoc, narrowing, CI).
15
+
16
+ ### Changed
17
+
18
+ - **`docs/README.md`**, **`cli-program.md`**, **`bundled-docs.md`**, Cursor rule template — cross-links to output-schema guide.
19
+
10
20
  ## [3.6.3] - 2026-06-23
11
21
 
12
22
  ### Added
@@ -20,6 +30,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
20
30
  - **`cli-program.md`** — `CliLeafInputs` / `readLeafInputs()` semantics, upgrading to 3.6+, read-once-resolve-once cross-links.
21
31
  - **`bundled-docs.md`** — framework docs vs consumer docgen.
22
32
  - **`docs/mcp.md`** — varargs JSON array only (fixes stale comma-string guidance).
33
+ - **`consumers-dev` / `consumers-sync`** — refresh consumer `.cursor/rules/cli-program.mdc` from template via `scripts/merge-cli-program-rule.ts`.
23
34
 
24
35
  ## [3.6.2] - 2026-06-23
25
36
 
@@ -413,7 +424,8 @@ const cli = { ... } satisfies CliProgram; // or : CliProgram
413
424
  - 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`).
414
425
  - Imports: use `CliPositional` where needed; replace `CliOptionDef` with `CliOption` or `CliPositional` as appropriate.
415
426
 
416
- [Unreleased]: https://github.com/bdombro/bun-argsbarg/compare/v3.6.3...HEAD
427
+ [Unreleased]: https://github.com/bdombro/bun-argsbarg/compare/v3.6.4...HEAD
428
+ [3.6.4]: https://github.com/bdombro/bun-argsbarg/releases/tag/v3.6.4
417
429
  [3.6.3]: https://github.com/bdombro/bun-argsbarg/releases/tag/v3.6.3
418
430
  [3.6.2]: https://github.com/bdombro/bun-argsbarg/releases/tag/v3.6.2
419
431
  [3.6.1]: https://github.com/bdombro/bun-argsbarg/releases/tag/v3.6.1
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. Documentation map: **[docs/README.md](docs/README.md)**. Authoring guide: **[docs/cli-program.md](docs/cli-program.md)**.
158
+ Add app-specific conventions in a second rule if needed. Copy the rule from the template, then add a `**<your-app> conventions:**` block at the bottom (see **Cursor rule** in [docs/cli-program.md](docs/cli-program.md)). Documentation map: **[docs/README.md](docs/README.md)**.
159
159
 
160
160
 
161
161
  ## How it works
package/docs/README.md CHANGED
@@ -6,6 +6,7 @@ Start here to pick the right guide.
6
6
  | --- | --- |
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
+ | **JSON stdout / `outputSchema`** | [output-schema.md](output-schema.md) — codegen pipeline, JSDoc, narrowing |
9
10
  | **Exposing MCP tools** | [mcp.md](mcp.md) — stdio server, `inputSchema`, varargs, `install --mcp` |
10
11
  | **Shipping install / completions / skills** | [install.md](install.md) — `myapp install`, shell completions |
11
12
  | **Bundling `myapp docs` topics** | [bundled-docs.md](bundled-docs.md) — consumer docgen vs framework docs |
@@ -11,6 +11,8 @@ Two documentation layers often coexist in a consumer repo:
11
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
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
13
 
14
+ `docs api` and `docs schema` embed each leaf’s `outputSchema` when set — see [output-schema.md](output-schema.md) for how to generate and wire schemas.
15
+
14
16
  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
17
 
16
18
  See [docs/README.md](README.md) for the full documentation map.
@@ -134,6 +134,8 @@ On **leaf commands**, set `outputSchema` to a JSON Schema describing stdout when
134
134
 
135
135
  Exported in `docs schema`, `docs api`, skill `reference.md`, and MCP `tools/list`. Not validated at runtime yet. Pair with `notes` for prose examples; do not duplicate the full schema in `notes`.
136
136
 
137
+ For a **outputSchema codegen guidelines** (TypeScript types → JSON Schema → `outputSchema` constants), see [output-schema.md](output-schema.md).
138
+
137
139
  Do **not** use `mcpTool.description` to paper over missing `--yes`, non-standard flag names, or handlers that only work interactively — fix those instead.
138
140
 
139
141
  If help text and MCP behavior match after your fixes, **omit `mcpTool` entirely**.
@@ -388,15 +390,27 @@ mkdir -p .cursor/rules
388
390
  cp node_modules/argsbarg/docs/templates/cursor/rules/cli-program.mdc .cursor/rules/cli-program.mdc
389
391
  ```
390
392
 
391
- 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.
393
+ The template is ~25 lines: when to read which doc, plus hard rules agents often get wrong. It does **not** duplicate this guide.
394
+
395
+ 2. **Add an app-specific block at the bottom** (recommended). Replace the template placeholder with a heading like `**myapp conventions:**` and short bullets — shared flag modules, `read*Flags` / `resolve*` paths, Ink vs JSON-only, etc. Example:
396
+
397
+ ```markdown
398
+ **sqsp-qa conventions:**
399
+
400
+ - Shared mutator flags: `readQaMutatingFlags(ctx)` in `src/cli/shared.ts`.
401
+ - Per command: `read*Flags` + `resolve*Input` in `commands/<name>/resolve.ts`.
402
+ ```
403
+
404
+ If you maintain argsbarg from a sibling checkout, `just consumer-dev` / `just consumers-sync` refresh the shared template and **keep** this footer (matched by the `**… conventions:**` heading). Commit `.cursor/rules/cli-program.mdc` in your repo.
392
405
 
393
- 2. **Optional:** a second rule for app-only conventions (e.g. `src/cli/shared.ts` flag names, JSON-only handlers, Ink patterns).
406
+ 3. **Optional:** a separate rule (e.g. `.cursor/argsbarg.mdc` or `AGENTS.md`) for broader package API notes.
394
407
 
395
- 3. **Optional:** `.cursor/argsbarg.mdc` or `AGENTS.md` pointing at `node_modules/argsbarg/docs/cli-program.md` for broader context.
408
+ **Not this file:** `myapp install --skill` writes the **app** skill (`SKILL.md` under `~/.cursor/skills/`) from your command schema — how to *invoke* the CLI. The rule above is for *authoring* argsbarg schema.
396
409
 
397
410
  ## See also
398
411
 
399
412
  - [Documentation map](README.md) — which doc to read when
413
+ - [Output schemas](output-schema.md) — codegen pipeline for leaf `outputSchema`
400
414
  - [Developing argsbarg](developing.md) — release, consumer sync, npm `files`
401
415
  - [MCP server](mcp.md) — tools, schema resource, env bootstrapping
402
416
  - [Agent skills](ai-skills.md) — `install --skill`
@@ -32,12 +32,16 @@ Sibling repos under `../../ss/` (paths are machine-specific; adjust in `justfile
32
32
 
33
33
  | Recipe | When | Effect |
34
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` |
35
+ | `just consumer-dev` | Before publish; hacking on argsbarg locally | `bun add argsbarg@file:<relative>`; refresh `.cursor/rules/cli-program.mdc` from template (keeps app-specific suffix) |
36
+ | `just consumers-sync` | After release | Sets `"argsbarg": "^<this package.json version>"`, `bun install`, merge **argsbarg Cursor rule**, `just build`, `just docgen`, `just install` (consumer app binary, completions, and **app** skill) |
37
37
 
38
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
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).
40
+ **Argsbarg authoring rule** — `scripts/merge-cli-program-rule.ts` copies `docs/templates/cursor/rules/cli-program.mdc` into each consumer’s `.cursor/rules/cli-program.mdc`, preserving any existing `**… conventions:**` footer block.
41
+
42
+ **Recommended in each consumer:** replace the template placeholder with `**<app> conventions:**` bullets (paths to `read*Flags`, shared flags, Ink vs JSON-only). Commit that file; merges refresh the shared top, not your footer.
43
+
44
+ **Consumer app skill** — `just install` in each consumer (part of `consumers-sync`) runs `myapp install --skill`, which updates `~/.cursor/skills/<app>/` from that app’s schema — not the argsbarg framework rule.
41
45
 
42
46
  ## npm package contents
43
47
 
@@ -0,0 +1,181 @@
1
+ # Output schemas (`outputSchema`)
2
+
3
+ How to describe JSON stdout on leaf commands — and a **recommended codegen pipeline** used in production argsbarg apps.
4
+
5
+ ## Argsbarg contract
6
+
7
+ On **leaf commands**, set `outputSchema` to a JSON Schema object when the handler emits JSON (typically with `--json`, always for JSON-only commands, or on the MCP headless path).
8
+
9
+ ```typescript
10
+ import { STATUS_OUTPUT_SCHEMA } from "../schemas/outputSchemas.js";
11
+
12
+ export const status = {
13
+ key: "status",
14
+ description: "Show environment status.",
15
+ outputSchema: STATUS_OUTPUT_SCHEMA,
16
+ handler: async (ctx) => { /* writes JSON to stdout */ },
17
+ } satisfies CliLeaf;
18
+ ```
19
+
20
+ | Where argsbarg uses it | Purpose |
21
+ | --- | --- |
22
+ | `myapp docs schema` | Full command tree JSON export |
23
+ | `myapp docs api` | Markdown per-command **Output** section |
24
+ | `myapp docs skill` | `reference.md` for agent skills |
25
+ | MCP `tools/list` | Optional `outputSchema` on each tool |
26
+
27
+ **Not validated at runtime** — argsbarg does not parse or reject handler stdout against the schema today. The schema is documentation and MCP metadata.
28
+
29
+ **Set on the leaf only** — not under `mcpTool` (legacy `mcpTool.outputSchema` still resolves but is deprecated).
30
+
31
+ **Draft version** — argsbarg accepts any JSON Schema object (`type`, `properties`, `definitions`, etc.). Generators may emit draft-07 or draft 2020-12; docgen embeds the object as-is.
32
+
33
+ See [cli-program.md — Structured stdout](cli-program.md#structured-stdout) for when to use `outputSchema` vs `notes`, and [mcp.md](mcp.md) for how MCP returns parsed JSON as `structuredContent`.
34
+
35
+ ## Hand-written vs generated
36
+
37
+ | Approach | When |
38
+ | --- | --- |
39
+ | **Inline object** on the leaf | One-off commands, spikes, very small shapes |
40
+ | **Codegen from TypeScript** | Multiple commands share a shape, nested objects, or you want rich `description` fields in `docs api` / skills |
41
+
42
+ Production CLIs with several JSON commands tend to use **codegen** so types, handlers, and schemas stay aligned.
43
+
44
+ ## Recommended pipeline (copy per repo)
45
+
46
+ No shared npm package — each app copies the same **contract**. Reference implementations: **sqsp-qa-tools**, **idp-trees**, **sqsp-i18n-tools** (see each repo’s `docs/architecture.md` for manifest tables).
47
+
48
+ ```mermaid
49
+ flowchart LR
50
+ subgraph types [Schema-facing TS + JSDoc]
51
+ Roots["Manifest root interfaces"]
52
+ Narrow["Narrowed types where needed"]
53
+ end
54
+ subgraph gen [just schemagen]
55
+ Script["scripts/generate-output-schemas.ts"]
56
+ Gen["ts-json-schema-generator"]
57
+ end
58
+ subgraph artifacts [Committed]
59
+ Json["src/schemas/generated/*.json"]
60
+ end
61
+ subgraph runtime [Runtime]
62
+ Bridge["src/schemas/outputSchemas.ts"]
63
+ Leaves["leaf outputSchema"]
64
+ Docgen["just docgen"]
65
+ end
66
+ Roots --> Script
67
+ Narrow --> Script
68
+ Script --> Gen --> Json --> Bridge --> Leaves --> Docgen
69
+ ```
70
+
71
+ | Piece | Convention |
72
+ | --- | --- |
73
+ | Generator | [`ts-json-schema-generator`](https://github.com/vega/ts-json-schema-generator) (e.g. `createGenerator` with `jsDoc: "extended"`) |
74
+ | Config | `tsconfig: "tsconfig.json"`, `topRef: false`, `skipTypeCheck: false` |
75
+ | Manifest | Explicit `{ typeName, path, outfile }[]` — only **roots** become schema files |
76
+ | Artifacts | Commit `src/schemas/generated/*.json` |
77
+ | Bridge | `src/schemas/outputSchemas.ts` imports JSON → `*_OUTPUT_SCHEMA` constants |
78
+ | tsconfig | `"resolveJsonModule": true` |
79
+ | CI | `just check`: run `schemagen` → `git diff --exit-code src/schemas/generated/` → typecheck |
80
+ | Docgen | `docgen` depends on `schemagen` so saved `./docs/api.md` and `./docs/schema.json` are fresh |
81
+
82
+ Type files can live anywhere the manifest points (`commands/<cmd>/types.ts`, `resolve.ts`, `core/types.ts`, `ui/runHeadless.ts`).
83
+
84
+ ### Example manifest + generator
85
+
86
+ ```typescript
87
+ const MANIFEST = [
88
+ { typeName: "StatusJsonOutput", path: "src/commands/status/resolve.ts", outfile: "status.json" },
89
+ { typeName: "HeadlessOpResult", path: "src/ui/runHeadless.ts", outfile: "headless-op-result.json" },
90
+ ];
91
+
92
+ for (const entry of MANIFEST) {
93
+ const generator = createGenerator({
94
+ path: path.join(ROOT, entry.path),
95
+ type: entry.typeName,
96
+ tsconfig: path.join(ROOT, "tsconfig.json"),
97
+ topRef: false,
98
+ skipTypeCheck: false,
99
+ jsDoc: "extended",
100
+ });
101
+ fs.writeFileSync(
102
+ path.join(OUT_DIR, entry.outfile),
103
+ `${JSON.stringify(generator.createSchema(entry.typeName), null, 2)}\n`,
104
+ );
105
+ }
106
+ ```
107
+
108
+ ### Example bridge
109
+
110
+ ```typescript
111
+ import statusJson from "./generated/status.json";
112
+
113
+ export const STATUS_JSON_OUTPUT_SCHEMA = statusJson as Record<string, unknown>;
114
+ ```
115
+
116
+ Wire the constant on each leaf that emits that shape (several commands may share one schema, e.g. mutating ops sharing `HeadlessOpResult`).
117
+
118
+ ## Schema-facing types
119
+
120
+ **Goal:** generated schemas match what handlers actually print, with descriptions agents can read in `docs api`.
121
+
122
+ 1. **Manifest roots** — `export interface` (preferred) or documented type alias; top-level JSDoc names which command(s) emit it.
123
+ 2. **Per property** — `/** … */` on every field that should appear in JSON Schema `properties` (including nested named types).
124
+ 3. **Unions / enums** — document the alias; generator emits `enum` / `anyOf` with type-level description.
125
+ 4. **Formats** — property JSDoc can include `@format date-time` for ISO timestamps; add a smoke test that the generated property has `format: "date-time"`.
126
+ 5. **Do not hand-edit** `src/schemas/generated/` — change types/JSDoc, run `just schemagen`, commit JSON.
127
+
128
+ ### Narrowing when runtime ≠ stdout
129
+
130
+ When a shared runtime type is **wider** than one command’s JSON, add a **schema-facing** type:
131
+
132
+ ```typescript
133
+ /** Runtime union across commands. */
134
+ export type ResultSource = TranslationReadinessSource | { kind: "uids"; uids: string[] };
135
+
136
+ /** JSON for `pr` and `file` only — no `uids` variant. */
137
+ export interface TranslationReadinessResult {
138
+ source: TranslationReadinessSource;
139
+ evaluatedAt: string;
140
+ // ...
141
+ }
142
+ ```
143
+
144
+ Patterns:
145
+
146
+ - **Shallow dashboard types** — separate interfaces from fat API types so generated schema stays readable.
147
+ - **Assignability tests** — `expectTypeOf<RuntimeRow>().toMatchTypeOf<SchemaFacingRow>()` or equivalent so refactors cannot drift.
148
+
149
+ Handlers keep using runtime types; only the manifest root (and its graph) feed codegen.
150
+
151
+ ## Tests
152
+
153
+ After wiring, add `src/schemas/outputSchemas.test.ts` (or similar):
154
+
155
+ - Each exported schema has `type: "object"` (or expected root).
156
+ - Key `properties` / `definitions` have non-empty `description` from JSDoc.
157
+ - Spot-check enums, required fields, and `@format date-time` where it matters.
158
+
159
+ ## Contributor workflow
160
+
161
+ 1. Edit schema-facing interfaces and JSDoc.
162
+ 2. `just schemagen` — refresh `src/schemas/generated/`.
163
+ 3. Commit generated JSON with the type changes.
164
+ 4. `just docgen` / `myapp docs api --save` — refresh consumer docs.
165
+ 5. Document app-specific manifest roots in **your** `docs/architecture.md` (not in argsbarg).
166
+
167
+ Add a bullet under your app’s `**… conventions:**` block in `.cursor/rules/cli-program.mdc` pointing at `node_modules/argsbarg/docs/output-schema.md` and your `src/schemas/` layout.
168
+
169
+ ## Out of scope
170
+
171
+ - Shared codegen package or monorepo tooling
172
+ - Runtime Zod / `.parse()` on stdout in argsbarg
173
+ - `outputSchema` for plain-text, streaming, or Ink-only commands
174
+ - Forcing identical file layout across repos — the **manifest** is authoritative
175
+
176
+ ## See also
177
+
178
+ - [cli-program.md](cli-program.md) — structured stdout, headless JSON, `read*Flags`
179
+ - [mcp.md](mcp.md) — `tools/list`, `structuredContent`
180
+ - [bundled-docs.md](bundled-docs.md) — `docs api` / `docs schema` docgen
181
+ - [docs/README.md](README.md) — documentation map
@@ -8,8 +8,9 @@ When adding or changing argsbarg schema, leaf handlers, or MCP exposure:
8
8
 
9
9
  1. **Read** `node_modules/argsbarg/docs/cli-program.md` (required — authoritative guide).
10
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`.
11
+ 3. JSON stdout / `outputSchema` guide and codegen → `node_modules/argsbarg/docs/output-schema.md`.
12
+ 4. `install`, completions, skills → `node_modules/argsbarg/docs/install.md`.
13
+ 5. Bundled `docs` built-in → `node_modules/argsbarg/docs/bundled-docs.md`.
13
14
 
14
15
  **Hard rules** (details and examples are in the docs above — do not contradict them):
15
16
 
@@ -20,5 +21,6 @@ When adding or changing argsbarg schema, leaf handlers, or MCP exposure:
20
21
  - String options: `format` / `default` / `pattern` per `cli-program.md`; `readLeafInputs()` for multi-flag leaves.
21
22
  - Varargs (`argMax: 0`): CLI space-separated; MCP JSON array only — no comma-splitting positionals.
22
23
  - 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.
24
+ - JSON stdout: `outputSchema` on the leaf from generated constants — see `output-schema.md`; do not hand-edit `src/schemas/generated/`.
23
25
 
24
- **App-specific conventions:** add below or in a separate `.cursor/rules/` file (shared flags path, Ink vs JSON-only, etc.).
26
+ **App-specific conventions:** replace this line with a `**<your-app> conventions:**` section (bullets only). Keep it at the bottom of this file — `just consumer-dev` / `just consumers-sync` in the argsbarg repo refresh the template above and preserve this block. Do not duplicate `cli-program.md` here; link paths and patterns only. For a second rule file (e.g. `.cursor/argsbarg.mdc`), that is fine too.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "argsbarg",
3
- "version": "3.6.3",
3
+ "version": "3.6.4",
4
4
  "type": "module",
5
5
  "engines": {
6
6
  "bun": ">=1.3"