argsbarg 4.1.0 → 5.0.1

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.
Files changed (119) hide show
  1. package/CHANGELOG.md +74 -1
  2. package/README.md +91 -85
  3. package/docs/README.md +8 -8
  4. package/docs/ai-skills.md +9 -9
  5. package/docs/bundled-docs.md +5 -5
  6. package/docs/cli-program.md +13 -11
  7. package/docs/config-schema.md +36 -9
  8. package/docs/configure.md +177 -0
  9. package/docs/developing.md +7 -7
  10. package/docs/distribution-homebrew.md +104 -0
  11. package/docs/mcp.md +11 -12
  12. package/docs/output-schema.md +1 -1
  13. package/examples/full-example/Formula/.gitkeep +0 -0
  14. package/examples/full-example/README.md +98 -0
  15. package/examples/full-example/biome.json +22 -0
  16. package/examples/{consumer-app → full-example}/bun.lock +2 -0
  17. package/examples/full-example/justfile +134 -0
  18. package/examples/{consumer-app → full-example}/package.json +10 -3
  19. package/examples/{consumer-app → full-example}/schemas/generated/app-config.json +1 -1
  20. package/examples/{consumer-app → full-example}/schemas/generated/status.json +1 -1
  21. package/examples/full-example/scripts/create-identity.ts +11 -0
  22. package/examples/full-example/scripts/formula-shared.ts +73 -0
  23. package/examples/full-example/scripts/gen-dev-formula.ts +26 -0
  24. package/examples/full-example/scripts/print-identity.ts +27 -0
  25. package/examples/full-example/src/commands/echo/command.ts +21 -0
  26. package/examples/full-example/src/commands/status/command.test.ts +10 -0
  27. package/examples/full-example/src/commands/status/command.ts +36 -0
  28. package/examples/{consumer-app → full-example}/src/commands/status/types.ts +1 -1
  29. package/examples/full-example/src/index.ts +10 -0
  30. package/examples/full-example/src/program.ts +57 -0
  31. package/examples/{consumer-app → full-example}/src/types.ts +1 -1
  32. package/examples/nested.ts +1 -3
  33. package/index.d.ts +49 -81
  34. package/package.json +2 -2
  35. package/src/builtins/builtins.test.ts +84 -64
  36. package/src/builtins/completion-group.ts +17 -17
  37. package/src/builtins/configure-copy.ts +86 -0
  38. package/src/builtins/configure.ts +70 -0
  39. package/src/builtins/dispatch.ts +13 -9
  40. package/src/builtins/index.ts +1 -1
  41. package/src/builtins/mcp.ts +2 -2
  42. package/src/builtins/registry.ts +6 -4
  43. package/src/capabilities.ts +22 -15
  44. package/src/cli-tool/cli-smoke.test.ts +29 -0
  45. package/src/cli-tool/create.test.ts +141 -0
  46. package/src/cli-tool/create.ts +402 -0
  47. package/{examples/consumer-app/capabilities.test.ts → src/cli-tool/full-example-capabilities.test.ts} +16 -15
  48. package/src/cli-tool/main.ts +8 -0
  49. package/src/cli-tool/post-create.ts +111 -0
  50. package/src/cli-tool/program.ts +97 -0
  51. package/src/cli-tool/prompt.ts +28 -0
  52. package/src/cli-tool/run-create.ts +138 -0
  53. package/src/cli.ts +0 -2
  54. package/src/config/bootstrap.ts +27 -18
  55. package/src/config/file.test.ts +1 -1
  56. package/src/config/resolve.test.ts +167 -0
  57. package/src/config/resolve.ts +52 -8
  58. package/src/configure/configure.test.ts +148 -0
  59. package/src/configure/index.ts +284 -0
  60. package/src/configure/prompt.ts +40 -0
  61. package/src/docs/api-guide.test.ts +4 -5
  62. package/src/docs/builtin.ts +3 -5
  63. package/src/docs/docs.test.ts +6 -5
  64. package/src/docs/mcp-guide.ts +11 -12
  65. package/src/index.ts +5 -12
  66. package/src/install/binary-placement.test.ts +101 -0
  67. package/src/install/binary-placement.ts +47 -0
  68. package/src/install/install-validate.test.ts +5 -5
  69. package/src/install/normalize-uninstall.ts +11 -0
  70. package/src/install/normalize.ts +4 -19
  71. package/src/install/opts.ts +17 -0
  72. package/src/install/paths.ts +0 -22
  73. package/src/install/plan.ts +14 -6
  74. package/src/install/shell.ts +0 -14
  75. package/src/install/status.test.ts +6 -6
  76. package/src/install/status.ts +0 -6
  77. package/src/install/target-effective.ts +8 -10
  78. package/src/install/target-scope.ts +26 -36
  79. package/src/install/target-types.ts +0 -16
  80. package/src/install/targets/app.ts +19 -28
  81. package/src/install/targets/configure.ts +6 -2
  82. package/src/install/targets/index.ts +0 -3
  83. package/src/install/targets.test.ts +26 -44
  84. package/src/invoke.test.ts +1 -1
  85. package/src/mcp/env.test.ts +92 -0
  86. package/src/mcp/env.ts +15 -14
  87. package/src/mcp/tools.ts +1 -1
  88. package/src/mcp.integration.test.ts +4 -4
  89. package/src/parse.test.ts +13 -14
  90. package/src/prompt.ts +10 -0
  91. package/src/schema.ts +1 -1
  92. package/src/skill/hint.ts +2 -2
  93. package/src/types.ts +48 -22
  94. package/src/validate.ts +22 -28
  95. package/docs/install.md +0 -290
  96. package/docs/templates/cursor/rules/cli-program.mdc +0 -31
  97. package/examples/config-app/main.ts +0 -20
  98. package/examples/config-app/program.ts +0 -78
  99. package/examples/config-app/schema.ts +0 -37
  100. package/examples/config-app/types.ts +0 -19
  101. package/examples/consumer-app/README.md +0 -56
  102. package/examples/consumer-app/src/main.ts +0 -15
  103. package/examples/consumer-app/src/program.ts +0 -108
  104. package/src/builtins/install.ts +0 -136
  105. package/src/install/app.ts +0 -94
  106. package/src/install/bootstrap.ts +0 -22
  107. package/src/install/completions.ts +0 -56
  108. package/src/install/index.ts +0 -415
  109. package/src/install/install.test.ts +0 -333
  110. package/src/install/targets/completions.ts +0 -133
  111. package/src/install/update.test.ts +0 -123
  112. package/src/install/update.ts +0 -54
  113. /package/examples/{consumer-app → full-example}/schemas/configSchemas.ts +0 -0
  114. /package/examples/{consumer-app → full-example}/schemas/outputSchemas.ts +0 -0
  115. /package/examples/{consumer-app → full-example}/scripts/schemagen/discover-schema-roots.test.ts +0 -0
  116. /package/examples/{consumer-app → full-example}/scripts/schemagen/discover-schema-roots.ts +0 -0
  117. /package/examples/{consumer-app → full-example}/scripts/schemagen/naming.ts +0 -0
  118. /package/examples/{consumer-app → full-example}/scripts/schemagen.ts +0 -0
  119. /package/examples/{consumer-app → full-example}/tsconfig.json +0 -0
@@ -39,7 +39,7 @@ await cli.run();
39
39
  | Where argsbarg uses it | Purpose |
40
40
  | --- | --- |
41
41
  | Config file | Flat JSON keyed by schema names; strict load (unknown keys rejected) |
42
- | `install --configure` / `--status` | Interactive setup and status |
42
+ | Interactive `configure` / `--status` | Auto-runs config wizard when `entries` is non-empty; `--status` for read-only inventory |
43
43
  | Built-in `config get` / `config set` | Read/write resolved values (opt-out via `commands: false`) |
44
44
  | MCP bundle / Claude plugin | `userConfig` for entries with `env` set |
45
45
  | `ctx.appConfig` in handlers | `get`, `require`, `set`, `read`, `path`, `dir` — prefer over `process.env` |
@@ -60,6 +60,7 @@ export interface CliAppConfigEntry {
60
60
  required?: boolean; // default: true (can override jsonSchema required)
61
61
  sensitive?: boolean; // default: name heuristic
62
62
  env?: string; // env override + export to process.env after resolve
63
+ resolve?: CliAppConfigResolveFn; // fallback after file; must be synchronous
63
64
  }
64
65
 
65
66
  export interface CliAppConfig {
@@ -92,13 +93,40 @@ No nested `env` bag. No extra keys — rejected on load.
92
93
 
93
94
  ## Resolution order (per schema key)
94
95
 
95
- | Key has `env`? | Resolved value |
96
- | --- | --- |
97
- | **Yes** | non-empty `process.env[env]` → else file[key] → else default |
98
- | **No** | file[key] → else default |
96
+ | Step | Source | Notes |
97
+ | --- | --- | --- |
98
+ | 1 | **Env** (`entry.env`) | Non-empty host env wins over file and `resolve` |
99
+ | 2 | **File** | `config.json` value for the key |
100
+ | 3 | **`resolve()`** | Optional synchronous callback (e.g. `gh auth token`); return `undefined` to continue. Async/Promise return values are ignored. |
101
+ | 4 | **Env** (`entry.env`) | Fallback when `resolve` returned `undefined` |
102
+ | 5 | **Default** | `jsonSchema` / `entry.default` |
99
103
 
100
104
  Empty string in env or file counts as **missing** for required entries. After resolution, mapped values are exported to `process.env`.
101
105
 
106
+ Example — GitHub token with `env: "GH_TOKEN"` and `resolve` calling `gh auth token`:
107
+
108
+ ```typescript
109
+ githubToken: {
110
+ description: "GitHub API token.",
111
+ env: "GH_TOKEN",
112
+ sensitive: true,
113
+ resolve: () => {
114
+ try {
115
+ const r = Bun.spawnSync(["gh", "auth", "token"], { stdout: "pipe", stderr: "ignore" });
116
+ if (r.exitCode === 0) {
117
+ const token = new TextDecoder().decode(r.stdout).trim();
118
+ return token.length > 0 ? token : undefined;
119
+ }
120
+ } catch {
121
+ // `gh` not installed
122
+ }
123
+ return undefined;
124
+ },
125
+ },
126
+ ```
127
+
128
+ Interactive `configure` does not persist values supplied only by env or `resolve` when you press Enter to accept the current value.
129
+
102
130
  ## Hand-written vs generated
103
131
 
104
132
  | Approach | When |
@@ -180,10 +208,9 @@ Object/array/`$ref` properties require `--json` on `config set`.
180
208
 
181
209
  | Example | Role |
182
210
  | --- | --- |
183
- | [`examples/config-app/`](../examples/config-app/) | **Learn** — hand-written schema, minimal setup |
184
- | [`examples/consumer-app/`](../examples/consumer-app/) | **Copy** — schemagen discovery, `APP_CONFIG_JSON_SCHEMA` bridge |
211
+ | [`examples/full-example/`](../examples/full-example/) | **Copy template** — schemagen discovery, `APP_CONFIG_JSON_SCHEMA` bridge, `program.appConfig`, built-in `config get`/`set` |
185
212
 
186
213
  ```bash
187
- cd examples/consumer-app && bun install && bun run schemagen
188
- CONSUMER_APP_API_TOKEN=dev bun run start config get apiToken --json
214
+ cd examples/full-example && just setup && just schemagen
215
+ FULL_EXAMPLE_API_TOKEN=dev just run config get apiToken --json
189
216
  ```
@@ -0,0 +1,177 @@
1
+ # Configure command
2
+
3
+ The `configure` built-in manages **agent artifacts** (skills, MCP config, app config). The **binary and shell completions** ship via Homebrew — see [distribution-homebrew.md](distribution-homebrew.md).
4
+
5
+ Opt out with `configure: { enabled: false }` on the program root.
6
+
7
+ ## End-user install (Homebrew)
8
+
9
+ ```bash
10
+ brew tap <org>/<repo>
11
+ brew install <tap>/<key>
12
+ <key> configure # interactive: per-target prompts; run when app config is required
13
+ ```
14
+
15
+ Upgrade with `brew upgrade <key>`. Shell completions are installed by Homebrew during `brew install`. Users must configure their shell per [Homebrew Shell Completion](https://docs.brew.sh/Shell-Completion).
16
+
17
+ **Uninstall the binary:** remove agent artifacts first (while the CLI is still on PATH), then `brew uninstall`:
18
+
19
+ ```bash
20
+ <key> configure --remove-all --yes
21
+ brew uninstall <tap>/<key>
22
+ ```
23
+
24
+ ## Developer install
25
+
26
+ ```bash
27
+ just build
28
+ just install-local # same formula as production; gen-dev-formula uses file:// URL (`just install` is an alias)
29
+ ```
30
+
31
+ Dev flow matches release: formula `install` copies the binary and generates completions; `post_install` runs `<key> configure --sync --yes` for skills/MCP. Use `just reinstall-local` to swap the binary into Cellar during tight edit cycles (skips completions and `post_install`). Use `just sync-artifacts` to refresh agent artifacts without touching the binary.
32
+
33
+ ## Quick reference
34
+
35
+ ```bash
36
+ # Refresh skills/MCP after upgrade (Homebrew post_install runs this automatically)
37
+ <key> configure --sync --yes
38
+
39
+ # See what is installed
40
+ <key> configure --status
41
+
42
+ # Interactive per-target setup (default when run with a TTY)
43
+ <key> configure
44
+
45
+ # Remove all agent artifacts
46
+ <key> configure --remove-all --yes
47
+
48
+ # Remove app config only (not skills/MCP)
49
+ <key> configure --remove-config --yes
50
+ ```
51
+
52
+ Non-interactive / CI: pass **`--yes`** (or **`--json`**, **`--sync`**, **`--remove-all`**, **`--remove-config`**) — see [Confirmation](#confirmation).
53
+
54
+ ## What gets configured
55
+
56
+ | Target | Interactive | Mechanism |
57
+ | --- | --- | --- |
58
+ | Binary | skipped (read-only) | Homebrew formula `bin.install` |
59
+ | Shell completions | skipped | Homebrew `generate_completions_from_executable` |
60
+ | Cursor skill | Y/n prompt | `~/.cursor/skills/<dir>/` when `~/.cursor` exists |
61
+ | Claude skill | Y/n prompt | `~/.claude/skills/<dir>/` when `~/.claude` exists |
62
+ | Codex / OpenCode / OpenClaw skills | Y/n prompt | Agent-specific dirs when available |
63
+ | MCP config | Y/n prompt | Cursor, Claude Code/Desktop, OpenCode, Codex, OpenClaw, ChatGPT desktop |
64
+ | App config | auto-runs wizard | Interactive wizard writes `~/.local/lib/<key>/config.json` |
65
+
66
+ ### Externally managed binary (Homebrew)
67
+
68
+ When **`PATH`** resolves the program key to the **running executable** (e.g. after `brew install`):
69
+
70
+ - **`configure --status`** shows `app: system (PATH)`
71
+ - **`--sync`** refreshes skills and MCP only — not the binary or completions
72
+
73
+ MCP config uses the command name on **`PATH`**, not a Cellar path.
74
+
75
+ ### Interactive default
76
+
77
+ Bare **`configure`** (TTY required) walks enabled install targets in order. For each target:
78
+
79
+ - **Not installed:** `[Y/n]` — default install; `n` skips.
80
+ - **Installed:** `[y/N]` — default keep; `n` uninstalls.
81
+ - **App config** (`program.appConfig` with entries): runs the config wizard automatically (no Y/n gate). Remove the config file with **`configure --remove-config --yes`**.
82
+
83
+ The **`app`** target (binary on PATH) is shown in `--status` only — never mutated by `configure`.
84
+
85
+ ### `configure.targets`
86
+
87
+ Configure which artifacts participate in `--sync`:
88
+
89
+ ```typescript
90
+ configure: {
91
+ agentIntegration: "mcp", // | "skill" | "both" — default from mcpServer.enabled
92
+ targets: {
93
+ chatgptMcp: false,
94
+ cursorSkill: { includedInAll: true },
95
+ },
96
+ },
97
+ ```
98
+
99
+ `ConfigureTargetSpec` is `boolean` or `{ enabled?: boolean; includedInAll?: boolean }`.
100
+
101
+ Artifact keys: `chatgptMcp`, `claudeCodeMcp`, `claudeDesktopMcp`, `claudeSkill`, `codexMcp`, `codexSkill`, `configure`, `cursorMcp`, `cursorSkill`, `openclawMcp`, `openclawSkill`, `opencodeMcp`, `opencodeSkill`.
102
+
103
+ ## App config (`program.appConfig`)
104
+
105
+ When `program.appConfig` is set, ArgsBarg manages a flat JSON config file at `~/.local/lib/<sanitized-key>/config.json`.
106
+
107
+ | Mode | Description |
108
+ | --- | --- |
109
+ | Interactive `configure` | Config wizard when you accept the configure target |
110
+ | `--status` | Shows config path and which required keys are set or missing |
111
+ | `--remove-config --yes` | Removes the config directory |
112
+
113
+ Export helpers from `argsbarg`: `resolveAppConfigPath`, `displayAppConfigPath`.
114
+
115
+ ## Flags
116
+
117
+ ### Operation flags
118
+
119
+ | Flag | Description |
120
+ | --- | --- |
121
+ | `--status` | Read-only inventory |
122
+ | `--sync` | Refresh installed agent artifacts (Homebrew `post_install`; greenfield → full sync plan) |
123
+ | `--remove-all` | Remove all detected agent artifacts |
124
+ | `--remove-config` | Remove app config directory only |
125
+
126
+ ### Behavior flags
127
+
128
+ | Flag | Description |
129
+ | --- | --- |
130
+ | `--yes`, `-y` | Skip confirmation (required for non-interactive modes) |
131
+ | `--dry` | Preview changes |
132
+ | `--json` | Machine-readable output (implies `--yes`) |
133
+
134
+ ## Confirmation
135
+
136
+ Interactive `configure` prints a **`{app} Setup`** banner and per-target prompts. Non-interactive modes (`--sync`, `--remove-all`, `--remove-config`) require **`--yes`** unless `--dry`.
137
+
138
+ ## MCP merge behavior
139
+
140
+ When MCP targets are installed, entries are merged into host config with:
141
+
142
+ ```json
143
+ { "command": "<root.key>", "args": ["mcp"] }
144
+ ```
145
+
146
+ If an existing entry differs, the command exits with an error unless `--yes` is passed.
147
+
148
+ ## Formula `post_install`
149
+
150
+ Release formulae should run:
151
+
152
+ ```ruby
153
+ def post_install
154
+ system bin/"myapp", "configure", "--sync", "--yes"
155
+ end
156
+ ```
157
+
158
+ This refreshes skills/MCP without running the configure wizard (app config is opt-in via interactive `configure`).
159
+
160
+ ## Bootstrapping a new CLI
161
+
162
+ ```bash
163
+ bunx argsbarg create my-cli --key my-cli --class-name MyCli --tap org/repo --yes
164
+ bunx argsbarg create --check .
165
+ ```
166
+
167
+ See [distribution-homebrew.md](distribution-homebrew.md) and [../examples/full-example/README.md](../examples/full-example/README.md).
168
+
169
+ ## Opt out
170
+
171
+ ```typescript
172
+ configure: { enabled: false },
173
+ ```
174
+
175
+ ## Completion
176
+
177
+ The `completion` built-in remains callable for Homebrew `generate_completions_from_executable` but is **hidden** from help and exported schema.
@@ -33,15 +33,15 @@ Sibling repos under `../../ss/` (paths are machine-specific; adjust in `justfile
33
33
  | Recipe | When | Effect |
34
34
  | --- | --- | --- |
35
35
  | `just consumers-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) |
36
+ | `just consumers-sync` | After release | Sets `"argsbarg": "^<this package.json version>"`, `bun install`, merge **argsbarg Cursor rule**, `just build`, `just docgen`, `just install-local` (Homebrew dev formula + agent artifacts; `just install` is an alias) |
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
- **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.
40
+ **Argsbarg authoring rule** — `scripts/merge-cli-program-rule.ts` copies `examples/full-example/.cursor/rules/cli-program.mdc` into each consumer’s `.cursor/rules/cli-program.mdc`, preserving any existing `**… conventions:**` footer block.
41
41
 
42
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
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.
44
+ **Consumer app skill** — `just install-local` in each consumer (part of `consumers-sync`) runs Homebrew dev install then `myapp configure --sync --yes`, which updates `~/.cursor/skills/<app>/` from that app’s schema — not the argsbarg framework rule.
45
45
 
46
46
  ## npm package contents
47
47
 
@@ -49,14 +49,14 @@ 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).
52
+ Exclude `examples/full-example/node_modules/` from the npm tarball via [`.npmignore`](../.npmignore).
53
53
 
54
- ## Kitchen-sink example
54
+ ## Full example
55
55
 
56
- [`examples/consumer-app/`](../examples/consumer-app/) must enable every builtin (`capabilities.test.ts`). After builtin or schemagen doc changes:
56
+ [`examples/full-example/`](../examples/full-example/) must enable every builtin (`capabilities.test.ts`). After builtin or schemagen doc changes:
57
57
 
58
58
  ```bash
59
- just consumer-app-schemagen
59
+ just full-example-schemagen
60
60
  just test
61
61
  ```
62
62
 
@@ -0,0 +1,104 @@
1
+ # Shipping via Homebrew (tap-from-repo)
2
+
3
+ Argsbarg apps distribute the **binary and shell completions** through Homebrew, and **agent artifacts** (skills, MCP config) through `configure --sync`.
4
+
5
+ ## Distribution model
6
+
7
+ | Layer | Mechanism |
8
+ | --- | --- |
9
+ | Binary + completions | Formula `install` block |
10
+ | Skills + MCP | Formula `post_install` → `{key} configure --sync --yes` |
11
+ | App config | User opt-in: `{key} configure` (interactive; not run from formula `post_install`) |
12
+
13
+ **Only tap-from-repo** — in-repo `Formula/` or GitHub tap. Not Homebrew core.
14
+
15
+ ### End-user install
16
+
17
+ ```bash
18
+ brew tap <org>/<repo>
19
+ brew install <tap>/{key}
20
+ {key} configure # when app config is required
21
+ ```
22
+
23
+ ### Developer install
24
+
25
+ ```bash
26
+ just build
27
+ just install-local # or `just install` (alias)
28
+ just reinstall-local # fast binary swap (`install -m 755` into Cellar; run install-local first)
29
+ just uninstall # undo formula + agent artifacts (not app config)
30
+ ```
31
+
32
+ Dev and release use the **same formula** (`Formula/{key}.rb`, class name, install/post_install/test). `gen-dev-formula.ts` only changes `url`, `version`, and `sha256` to point at the local binary in `Formula/.staging/`. Release bumps restore the GitHub URL via `scripts/release.ts`.
33
+
34
+ ### Developer uninstall
35
+
36
+ | Recipe | Removes |
37
+ | --- | --- |
38
+ | `just uninstall` | Formula `{key}` + tap symlink + skills/MCP |
39
+ | `just uninstall-config` | App config file only (`configure --remove-config --yes`) |
40
+ | `just uninstall-release` | Release formula from `{tap}` (keeps tap) |
41
+ | `just uninstall-release-tap` | Release formula + `brew untap {tap}` |
42
+ | `just test-release` | Install release formula and run formula test |
43
+
44
+ End users: `<key> configure --remove-all --yes` then `brew uninstall <tap>/<key>`.
45
+
46
+ ## Formula pattern
47
+
48
+ ```ruby
49
+ def install
50
+ bin.install "{key}"
51
+ generate_completions_from_executable(bin/"{key}", "completion", base_name: "{key}")
52
+ end
53
+
54
+ def post_install
55
+ system bin/"{key}", "configure", "--sync", "--yes"
56
+ end
57
+ ```
58
+
59
+ Completions require users to configure their shell per [Homebrew Shell Completion](https://docs.brew.sh/Shell-Completion).
60
+
61
+ **Why configure is separate from `post_install`:** the wizard is interactive (TTY + prompts for secrets). Formula `post_install` runs non-interactively during `brew install` and in CI (`brew test`). Apps with `appConfig` print a one-line configure hint in formula `caveats` instead.
62
+
63
+ ## Bootstrap CLI (`argsbarg create`)
64
+
65
+ Copy the shipped `examples/full-example` template into a new directory with identity substitutions, then run install, schemagen, tests, and git init (when appropriate):
66
+
67
+ ```bash
68
+ bunx argsbarg create my-cli \
69
+ --key my-cli --class-name MyCli --tap org/my-cli \
70
+ --homepage https://github.com/org/my-cli --release-repo org/my-cli \
71
+ --yes
72
+ ```
73
+
74
+ On a TTY, omit flags to use the interactive wizard. Verify an existing tree:
75
+
76
+ ```bash
77
+ bunx argsbarg create --check .
78
+ ```
79
+
80
+ Template source: [`examples/full-example/`](../examples/full-example/) in the argsbarg package (also under `node_modules/argsbarg/examples/full-example` after `bun add argsbarg`).
81
+
82
+ **Git bootstrap skip rules:** post-create skips `git init` when the target already has a `.git` directory, or when the target sits inside an existing git work tree (e.g. a monorepo subfolder). Standalone new directories get an `Initial commit`.
83
+
84
+ ## Release workflow
85
+
86
+ 1. `just build` → `dist/{key}`
87
+ 2. `scripts/release.ts` → writes `Formula/{key}.rb` (GitHub URL + sha256), commits, tags, uploads `dist/{key}` to GitHub Releases
88
+ 3. Users `brew upgrade {key}` from the tap
89
+
90
+ ## Removed (breaking)
91
+
92
+ - Self-install to `~/.local/bin`
93
+ - Top-level `install` and `uninstall` commands (use `configure`)
94
+ - `install --update` / `updateGetLatest`
95
+ - Homebrew completion installer via CLI (Homebrew owns completions)
96
+ - Bare-argv install bootstrap
97
+ - Auto configure wizard after sync
98
+ - Separate `{key}-local` formula and `{key}/dev` tap
99
+
100
+ ## Config path
101
+
102
+ Default: `~/.local/lib/<sanitized-key>/config.json`
103
+
104
+ Export helpers: `resolveAppConfigPath`, `displayAppConfigPath` from `argsbarg`.
package/docs/mcp.md CHANGED
@@ -61,11 +61,11 @@ Use your real binary or script path. For a compiled CLI, `command` can be the in
61
61
 
62
62
  ### Claude Code
63
63
 
64
- `install --mcp` merges into `~/.claude.json` under `mcpServers`.
64
+ `configure` (MCP targets) merges into `~/.claude.json` under `mcpServers`.
65
65
 
66
66
  ### Claude Desktop
67
67
 
68
- `install --mcp` also merges into Claude Desktop config when app data is present:
68
+ `configure` (MCP targets) also merges into Claude Desktop config when app data is present:
69
69
 
70
70
  | Platform | Path |
71
71
  | --- | --- |
@@ -77,7 +77,7 @@ Restart Claude Desktop after config changes. You can also install a **`.mcpb`**
77
77
 
78
78
  ### OpenCode
79
79
 
80
- When `~/.config/opencode` exists, **`install --mcp`** merges a local server under the top-level **`mcp`** key (not `mcpServers`):
80
+ When `~/.config/opencode` exists, **`configure`** (MCP targets) merges a local server under the top-level **`mcp`** key (not `mcpServers`):
81
81
 
82
82
  ```json
83
83
  {
@@ -96,7 +96,7 @@ OpenCode reads `opencode.jsonc`, `opencode.json`, or `config.json` in that direc
96
96
 
97
97
  ### OpenAI Codex
98
98
 
99
- When **`codex`** is on PATH, **`install --mcp`** runs `codex mcp add <server> -- <binary> mcp`, which writes **`~/.codex/config.toml`**. Otherwise add manually:
99
+ When **`codex`** is on PATH, **`configure`** (MCP targets) runs `codex mcp add <server> -- <binary> mcp`, which writes **`~/.codex/config.toml`**. Otherwise add manually:
100
100
 
101
101
  ```toml
102
102
  [mcp_servers.myapp]
@@ -110,7 +110,7 @@ Use **`codex mcp`** to list/add/remove servers, or **Settings → MCP → Open c
110
110
 
111
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
112
 
113
- **Desktop JSON (gated auto-install)** — when ChatGPT app data exists, **`install --mcp`** also merges `mcpServers` into:
113
+ **Desktop JSON (gated auto-install)** — when ChatGPT app data exists, **`configure`** (MCP targets) also merges `mcpServers` into:
114
114
 
115
115
  | Platform | Path |
116
116
  | --- | --- |
@@ -131,7 +131,7 @@ Set `mcpServer` on the **program root only** (the `CliProgram` passed to `new Cl
131
131
  | --- | --- | --- |
132
132
  | `enabled` | *(required)* | Must be `true` when `mcpServer` is set |
133
133
  | `schemaResourceUri` | `<sanitized root key>://schema` | URI for the built-in schema resource |
134
- | `shellEnv` | off | Capture login-shell `env` at startup (`true` uses `$SHELL`, or pass a shell path) |
134
+ | `shellEnv` | on (opt-out with `false`) | Capture login-shell `env` at startup (`true` uses `$SHELL`, or pass a shell path) |
135
135
  | `resources` | `[]` | Custom `CliMcpResource` entries (additive; schema resource is always included) |
136
136
 
137
137
  MCP `serverInfo.name` and the default schema URI use the sanitized program `key` (non-alphanumeric characters become `_`). Program `version` comes from `CliProgram.version` (also used by the `version` built-in).
@@ -141,7 +141,7 @@ Example with optional fields:
141
141
  ```typescript
142
142
  mcpServer: {
143
143
  enabled: true,
144
- shellEnv: true,
144
+ shellEnv: false, // opt out of login-shell capture
145
145
  }
146
146
  ```
147
147
 
@@ -254,7 +254,7 @@ When both **`docs.enabled`** and **`mcpServer.enabled`** are true, each user key
254
254
  | MIME type | `text/markdown` |
255
255
  | Contents | Same body as `myapp docs <topicKey>` |
256
256
 
257
- Built-in docs subcommands (`schema`, `api`, `skill`, `mcp`) are **not** auto-exposed — use the schema resource, `install --skill`, or CLI `docs` instead. `docs` subcommands remain hidden from MCP `tools/list`.
257
+ Built-in docs subcommands (`schema`, `api`, `skill`, `mcp`) are **not** auto-exposed — use the schema resource, `configure`, or CLI `docs` instead. `docs` subcommands remain hidden from MCP `tools/list`.
258
258
 
259
259
  Custom `mcpServer.resources` URIs must not collide with the schema URI or any auto docs topic URI (validated at program compile time).
260
260
 
@@ -326,7 +326,7 @@ At server start (`Cli.serveMcp()`), before the NDJSON loop:
326
326
  - JSON shape: flat object keyed by schema names — `{ "apiToken": "…" }`. Unknown keys rejected on load.
327
327
  - Loaded at MCP startup; host `process.env` wins for mapped env vars already set.
328
328
  - Missing required config does **not** exit the MCP server — enforced at `tools/call` with a helpful error.
329
- - Configure interactively: `myapp install --configure` (see [install.md](install.md)).
329
+ - Configure interactively: `myapp configure` (see [configure.md](configure.md)).
330
330
  - Built-in `config get` / `config set` when `program.appConfig.commands` is enabled (default). Hosts inject `user_config` → env at spawn; they never write the argsbarg config file.
331
331
 
332
332
  Example:
@@ -339,7 +339,6 @@ appConfig: {
339
339
  },
340
340
  mcpServer: {
341
341
  enabled: true,
342
- shellEnv: true,
343
342
  },
344
343
  ```
345
344
 
@@ -412,11 +411,11 @@ skills/<dirName>/SKILL.md
412
411
 
413
412
  `plugin.json` references `.mcp.json` so Claude Desktop and Claude Code load the bundled MCP server when the plugin is enabled. The plugin zip preserves the executable bit on `bin/<key>`.
414
413
 
415
- The bundled `SKILL.md` is an **MCP routing stub** — it tells Claude to use the plugin’s MCP toolset (server id, `tools/list`, schema resource). It is not a shell CLI catalog and does not include `reference.md`. Use **`install --skill`** for a persisted shell-oriented skill bundle.
414
+ The bundled `SKILL.md` is an **MCP routing stub** — it tells Claude to use the plugin’s MCP toolset (server id, `tools/list`, schema resource). It is not a shell CLI catalog and does not include `reference.md`. Use **`configure`** for a persisted shell-oriented skill bundle.
416
415
 
417
416
  Load locally with `claude --plugin-dir ./dist/claude-plugin/myapp.zip`.
418
417
 
419
- 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.
418
+ Bare **`myapp mcp`** still runs the stdio MCP server (unchanged for `configure` MCP targets and MCP hosts). Use **`configure --sync --yes`** for Cursor, Claude Code, Claude Desktop, and OpenCode JSON config.
420
419
 
421
420
  ## Hidden commands and options
422
421
 
@@ -186,7 +186,7 @@ Per repo:
186
186
 
187
187
  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.
188
188
 
189
- **Reference implementation:** [`examples/consumer-app/`](../examples/consumer-app/) in this repo (shipped in npm as `node_modules/argsbarg/examples/consumer-app/`) — discovery script, bridges, and `status` leaf with `outputSchema`.
189
+ **Reference implementation:** [`examples/full-example/`](../examples/full-example/) in this repo (shipped in npm as `node_modules/argsbarg/examples/full-example/`) — discovery script, bridges, and `status` leaf with `outputSchema`.
190
190
 
191
191
  ## Out of scope
192
192
 
File without changes
@@ -0,0 +1,98 @@
1
+ # full-example
2
+
3
+ **Full argsbarg reference app** — bootstrap new production CLIs with `bunx argsbarg create`.
4
+
5
+ ## What this demonstrates
6
+
7
+ | Area | Files / wiring |
8
+ | --- | --- |
9
+ | All builtins | `completion`, `version`, `install`, `docs`, `mcp`, `config get`/`set` |
10
+ | `program.appConfig` | `src/types.ts` (`AppConfig`) → `schemas/configSchemas.ts` |
11
+ | `outputSchema` | `src/commands/status/types.ts` (`StatusJsonOutput`) → `schemas/outputSchemas.ts` |
12
+ | Schemagen | `scripts/schemagen.ts` + `scripts/schemagen/discover-schema-roots.ts` |
13
+ | Command layout | `src/commands/<name>/command.ts`; registration in `src/program.ts` |
14
+ | MCP doc topics | `docs.topics` auto-exposed as `<key>://docs/<topic>` resources when docs + MCP enabled |
15
+ | Package import | `from "argsbarg"` (not relative to argsbarg `src/`) |
16
+ | Homebrew distribution | `scripts/formula-shared.ts`, `scripts/gen-dev-formula.ts`, `Formula/`, `justfile` |
17
+ | Dev tooling | Biome (`just format` / `just lint`), TypeScript, colocated tests |
18
+ | Cursor rules | `.cursor/rules/cli-program.mdc`, `.cursor/rules/code.mdc` |
19
+
20
+ ## Bootstrap a new CLI
21
+
22
+ Interactive (TTY):
23
+
24
+ ```bash
25
+ bunx argsbarg create my-cli
26
+ ```
27
+
28
+ Non-interactive:
29
+
30
+ ```bash
31
+ bunx argsbarg create my-cli \
32
+ --key my-cli --release-repo org/my-cli --yes
33
+ ```
34
+
35
+ Edit `scripts/create-identity.ts` to set `desc` (used by `program.description` and the Homebrew formula).
36
+
37
+ `create` copies this template (including `.cursor/rules/cli-program.mdc`), substitutes identity placeholders, runs `bun install`, schemagen, `bun test`, and `git init` + Initial commit when appropriate.
38
+
39
+ **Git bootstrap:** skipped when `{target}/.git` already exists, or when the target is inside an existing git work tree (monorepo subfolder). Standalone new directories get `Initial commit`.
40
+
41
+ To refresh the Cursor rule in an existing consumer: `bun scripts/merge-cli-program-rule.ts .` from an argsbarg checkout (or pass the npm package path to the template).
42
+
43
+ ## Quick start (in this repo)
44
+
45
+ ```bash
46
+ cd examples/full-example
47
+ just setup
48
+ just schemagen # after changing src/**/types.ts
49
+ FULL_EXAMPLE_API_TOKEN=dev just run status --json
50
+ FULL_EXAMPLE_API_TOKEN=dev just run config get apiToken --json
51
+ FULL_EXAMPLE_API_TOKEN=dev just run docs readme
52
+ ```
53
+
54
+ ## Homebrew dev install
55
+
56
+ Requires [Homebrew](https://brew.sh) and a compiled binary at `dist/full-example`:
57
+
58
+ ```bash
59
+ just build
60
+ just install-local # first-time dev formula (`just install` is an alias)
61
+ just reinstall-local # fast binary swap during development
62
+ just install-production # uninstall local dev, install from GitHub tap
63
+ just test-release
64
+ ```
65
+
66
+ Undo a local dev install:
67
+
68
+ ```bash
69
+ just uninstall # dev formula + agent artifacts
70
+ just uninstall-config # app config only
71
+ just uninstall-release # release formula (keeps tap)
72
+ ```
73
+
74
+ See [docs/distribution-homebrew.md](../../docs/distribution-homebrew.md).
75
+
76
+ ## Schemagen markers
77
+
78
+ | Marker in interface JSDoc | Artifact |
79
+ | --- | --- |
80
+ | `Config schema` | `schemas/configSchemas.ts` + `schemas/generated/*-config.json` |
81
+ | `JSON payload` | `schemas/outputSchemas.ts` + `schemas/generated/*.json` |
82
+
83
+ Discovery walks `src/**/types.ts` only.
84
+
85
+ ## Environment
86
+
87
+ | Variable | Purpose |
88
+ | --- | --- |
89
+ | `FULL_EXAMPLE_API_TOKEN` | Overrides `apiToken` via `program.appConfig` env mapping |
90
+
91
+ ## Maintainers (argsbarg repo)
92
+
93
+ When adding or changing builtins, update this example and run:
94
+
95
+ ```bash
96
+ just check-full-example # from argsbarg repo root
97
+ just test # from examples/full-example
98
+ ```
@@ -0,0 +1,22 @@
1
+ {
2
+ "$schema": "https://biomejs.dev/schemas/2.5.0/schema.json",
3
+ "assist": { "actions": { "source": { "organizeImports": "on" } } },
4
+ "linter": {
5
+ "enabled": true,
6
+ "rules": {
7
+ "preset": "recommended"
8
+ }
9
+ },
10
+ "formatter": {
11
+ "enabled": true,
12
+ "indentStyle": "space",
13
+ "lineWidth": 120
14
+ },
15
+ "overrides": [
16
+ {
17
+ "includes": ["**/*.json"],
18
+ "formatter": { "enabled": false },
19
+ "linter": { "enabled": false }
20
+ }
21
+ ]
22
+ }
@@ -8,6 +8,8 @@
8
8
  "argsbarg": "file:../..",
9
9
  },
10
10
  "devDependencies": {
11
+ "@biomejs/biome": "^2.5.0",
12
+ "@types/bun": "^1.3.12",
11
13
  "ts-json-schema-generator": "^2.3.0",
12
14
  "typescript": "^5.9.3",
13
15
  },