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
package/src/types.ts CHANGED
@@ -202,6 +202,26 @@ export interface CliUpdateArtifact {
202
202
  /** Fetches the latest release binary for `install --update`. */
203
203
  export type CliUpdateGetLatest = (ctx: { version: string }) => Promise<CliUpdateArtifact>;
204
204
 
205
+ /** Context passed to {@link CliAppConfigEntry.resolve} for one config key. */
206
+ export interface CliAppConfigResolveContext {
207
+ /** Schema key being resolved. */
208
+ key: string;
209
+ /** Entry metadata for this key. */
210
+ entry: CliAppConfigEntry;
211
+ /** Program root (read-only). */
212
+ program: CliProgram;
213
+ /** Raw value from the config file, if any. */
214
+ fileValue: unknown;
215
+ /** Non-empty host env string when `entry.env` is set; otherwise `undefined`. */
216
+ envValue: string | undefined;
217
+ }
218
+
219
+ /**
220
+ * Optional fallback resolver for one config key (e.g. `gh auth token` when `GH_TOKEN` is unset).
221
+ * Return `undefined` to continue resolution (env, then default).
222
+ */
223
+ export type CliAppConfigResolveFn = (ctx: CliAppConfigResolveContext) => unknown;
224
+
205
225
  /**
206
226
  * Metadata overlay for one key in {@link CliAppConfig.entries}.
207
227
  * Types and validation come from {@link CliAppConfig.jsonSchema} when set; otherwise all values are strings.
@@ -222,6 +242,11 @@ export interface CliAppConfigEntry {
222
242
  sensitive?: boolean;
223
243
  /** When set: non-empty `process.env[env]` overrides file; value exported after resolve. */
224
244
  env?: string;
245
+ /**
246
+ * Optional fallback after file when env is empty.
247
+ * Return `undefined` to fall back to `env` (if set) and schema defaults.
248
+ */
249
+ resolve?: CliAppConfigResolveFn;
225
250
  }
226
251
 
227
252
  /**
@@ -236,23 +261,24 @@ export interface CliAppConfig {
236
261
  entries: Record<string, CliAppConfigEntry>;
237
262
  }
238
263
 
239
- export interface CliInstallConfig {
240
- /** When `false`, hide/disable `install` (default: enabled). */
264
+ /** Opt-out for the `completion` built-in (default: enabled). */
265
+ export interface CliCompletionConfig {
266
+ /** When `false`, hide/disable `completion` (default: enabled). */
267
+ enabled?: boolean;
268
+ }
269
+
270
+ export interface CliConfigureConfig {
271
+ /** When `false`, hide/disable `configure` (default: enabled). */
241
272
  enabled?: boolean;
242
273
  /**
243
- * Default agent integration for full install (`install --all`).
244
- * - `'mcp'` when `mcpServer.enabled` (default): MCP targets in `--all`; paired skills excluded.
245
- * - `'skill'` when MCP is off (default): skill targets in `--all`; paired MCP excluded.
246
- * - `'both'`: install MCP and skill for the same host when both are available.
274
+ * Default agent integration for sync (`configure --sync`).
275
+ * - `'mcp'` when `mcpServer.enabled` (default): MCP targets in sync; paired skills excluded.
276
+ * - `'skill'` when MCP is off (default): skill targets in sync; paired MCP excluded.
277
+ * - `'both'`: sync MCP and skill for the same host when both are available.
247
278
  */
248
279
  agentIntegration?: InstallAgentIntegration;
249
- /** Per-artifact gates for full install/uninstall. See {@link resolveEffectiveInstallTargets}. */
250
- targets?: CliInstallTargets;
251
- /**
252
- * When set, enables `install --update` on the program root.
253
- * Should download or locate the latest release binary and return its path.
254
- */
255
- updateGetLatest?: CliUpdateGetLatest;
280
+ /** Per-artifact gates for configure sync and interactive wizard. See {@link resolveEffectiveInstallTargets}. */
281
+ targets?: CliConfigureTargets;
256
282
  }
257
283
 
258
284
  /** Agent integration mode for install — MCP vs shell skill per host. */
@@ -264,7 +290,7 @@ export type InstallTargetSpec =
264
290
  | {
265
291
  /** When false, artifact is never installed (even with scoped CLI flags). Default true. */
266
292
  enabled?: boolean;
267
- /** When true, included in bare `install` / `install --all`. Default varies by key. */
293
+ /** When true, included in `configure --sync`. Default varies by key. */
268
294
  includedInAll?: boolean;
269
295
  };
270
296
 
@@ -273,9 +299,9 @@ export interface ResolvedInstallTarget {
273
299
  includedInAll: boolean;
274
300
  }
275
301
 
276
- /** Per-artifact gates for full install/uninstall. See {@link resolveEffectiveInstallTargets}. */
277
- export interface CliInstallTargets {
278
- /** Copy app to `~/.local/bin/<key>`. Default includedInAll true (opt-out). */
302
+ /** Per-artifact gates for configure. See {@link resolveEffectiveInstallTargets}. */
303
+ export interface CliConfigureTargets {
304
+ /** App binary status only (Homebrew PATH); no self-install. */
279
305
  app?: InstallTargetSpec;
280
306
  /** ChatGPT desktop MCP. Default false. */
281
307
  chatgptMcp?: InstallTargetSpec;
@@ -289,9 +315,7 @@ export interface CliInstallTargets {
289
315
  codexMcp?: InstallTargetSpec;
290
316
  /** Codex skill. Default false. */
291
317
  codexSkill?: InstallTargetSpec;
292
- /** Shell completions for detected shells. Default includedInAll true (opt-out). */
293
- completions?: InstallTargetSpec;
294
- /** App config: wizard on install, file removal on uninstall. Default includedInAll true. */
318
+ /** App config: interactive wizard step in `configure`. Default not in sync. */
295
319
  configure?: InstallTargetSpec;
296
320
  /** Cursor MCP. Default false. */
297
321
  cursorMcp?: InstallTargetSpec;
@@ -396,8 +420,10 @@ export type CliProgram = CliNode & {
396
420
  appConfig?: CliAppConfig;
397
421
  /** When set with `enabled: true`, enables the `mcp` built-in subcommand. */
398
422
  mcpServer?: CliMcpServerConfig;
399
- /** Opt-out and defaults for `install`. */
400
- install?: CliInstallConfig;
423
+ /** Opt-out and defaults for `configure`. */
424
+ configure?: CliConfigureConfig;
425
+ /** Opt-out for shell completion generation (`completion bash|zsh|fish`). */
426
+ completion?: CliCompletionConfig;
401
427
  /** When set with `enabled: true`, enables the `docs` built-in command group. */
402
428
  docs?: CliDocsConfig;
403
429
  };
package/src/validate.ts CHANGED
@@ -81,6 +81,11 @@ function validateConfigBlock(appConfigBlock: import("./types.ts").CliAppConfig):
81
81
  }
82
82
  envNames.add(entry.env);
83
83
  }
84
+ if (entry.resolve !== undefined && typeof entry.resolve !== "function") {
85
+ throw new CliSchemaValidationError(
86
+ `program.appConfig.entries['${key}'].resolve must be a function when set`,
87
+ );
88
+ }
84
89
  }
85
90
 
86
91
  const jsonSchema = appConfigBlock.jsonSchema;
@@ -122,28 +127,28 @@ function installTargetExplicitTruthy(spec: InstallTargetSpec | undefined): boole
122
127
  return spec.enabled !== false;
123
128
  }
124
129
 
125
- /** Validates `program.install` targets and agentIntegration. */
126
- function validateInstallConfig(program: CliProgram): void {
127
- const install = program.install;
128
- if (!install) return;
130
+ /** Validates `program.configure` targets and agentIntegration. */
131
+ function validateConfigureConfig(program: CliProgram): void {
132
+ const configure = program.configure;
133
+ if (!configure) return;
129
134
 
130
- if ("prefix" in install) {
135
+ if ("prefix" in configure) {
131
136
  throw new CliSchemaValidationError(
132
- "install.prefix removed; app installs to ~/.local/bin/<key>",
137
+ "configure.prefix removed; app binary installs via Homebrew",
133
138
  );
134
139
  }
135
140
 
136
- if (!install.targets) return;
141
+ if (!configure.targets) return;
137
142
 
138
- const targets = install.targets;
143
+ const targets = configure.targets;
139
144
  if ("allSkills" in targets || "allMcps" in targets) {
140
145
  throw new CliSchemaValidationError(
141
- "install.targets.allSkills/allMcps removed; use agentIntegration and per-key targets",
146
+ "configure.targets.allSkills/allMcps removed; use agentIntegration and per-key targets",
142
147
  );
143
148
  }
144
149
 
145
150
  const integration: InstallAgentIntegration =
146
- install.agentIntegration ?? (program.mcpServer?.enabled === true ? "mcp" : "skill");
151
+ configure.agentIntegration ?? (program.mcpServer?.enabled === true ? "mcp" : "skill");
147
152
 
148
153
  for (const [mcpKey, skillKey] of AGENT_PAIRS) {
149
154
  const mcpSpec = targets[mcpKey];
@@ -154,18 +159,18 @@ function validateInstallConfig(program: CliProgram): void {
154
159
 
155
160
  if (mcpOn && skillOn && integration !== "both") {
156
161
  throw new CliSchemaValidationError(
157
- `install.targets: ${host} has both MCP and skill configured; set agentIntegration: 'both' or disable one side`,
162
+ `configure.targets: ${host} has both MCP and skill configured; set agentIntegration: 'both' or disable one side`,
158
163
  );
159
164
  }
160
165
 
161
166
  if (integration === "skill" && mcpOn) {
162
167
  throw new CliSchemaValidationError(
163
- `install.targets.${mcpKey} requires agentIntegration: 'both' when agentIntegration is 'skill'`,
168
+ `configure.targets.${mcpKey} requires agentIntegration: 'both' when agentIntegration is 'skill'`,
164
169
  );
165
170
  }
166
171
  if (integration === "mcp" && skillOn) {
167
172
  throw new CliSchemaValidationError(
168
- `install.targets.${skillKey} requires agentIntegration: 'both' when agentIntegration is 'mcp'`,
173
+ `configure.targets.${skillKey} requires agentIntegration: 'both' when agentIntegration is 'mcp'`,
169
174
  );
170
175
  }
171
176
  }
@@ -197,19 +202,8 @@ export function cliValidateProgram(program: CliProgram): void {
197
202
  validateConfigBlock(program.appConfig);
198
203
  }
199
204
 
200
- if (program.install?.updateGetLatest !== undefined) {
201
- if (program.install.enabled === false) {
202
- throw new CliSchemaValidationError(
203
- "install.updateGetLatest requires install to be enabled (omit install.enabled: false)",
204
- );
205
- }
206
- if (typeof program.install.updateGetLatest !== "function") {
207
- throw new CliSchemaValidationError("install.updateGetLatest must be a function");
208
- }
209
- }
210
-
211
- if (program.install !== undefined) {
212
- validateInstallConfig(program);
205
+ if (program.configure !== undefined) {
206
+ validateConfigureConfig(program);
213
207
  }
214
208
 
215
209
  const caps = resolveCapabilities(program);
@@ -234,9 +228,9 @@ function walkNode(node: CliNode, program: CliProgram, isRoot: boolean): void {
234
228
  `mcpServer is only supported on the program root (not on ${node.key})`,
235
229
  );
236
230
  }
237
- if (rogue.install !== undefined) {
231
+ if (rogue.configure !== undefined) {
238
232
  throw new CliSchemaValidationError(
239
- `install is only supported on the program root (not on ${node.key})`,
233
+ `configure is only supported on the program root (not on ${node.key})`,
240
234
  );
241
235
  }
242
236
  if (rogue.docs !== undefined) {
package/docs/install.md DELETED
@@ -1,290 +0,0 @@
1
- # Install command
2
-
3
- The `install` built-in installs the app, shell completions, agent skills, and MCP config. Opt out with `install: { enabled: false }` on the program root.
4
-
5
- ## End-user install
6
-
7
- Ship a compiled binary (or app bundle). Users install interactively — no `--yes` required when stdin is a TTY:
8
-
9
- - **Terminal:** run `./myapp`, `myapp`, or `myapp install` (bare `install` is equivalent to `--all`).
10
- - **macOS app:** double-click the `.app`; when the binary is not yet on PATH and stdin is a TTY, launching with no arguments bootstraps to **`myapp install`**.
11
-
12
- Interactive flow prints a **`{app} Setup`** banner, a numbered plan, and a confirm prompt. When the app needs API keys or other settings, a **`Configuration Setup`** section runs after install (or immediately for **`install --configure`**).
13
-
14
- **Uninstall is CLI-only** — there is no GUI uninstaller. Users run:
15
-
16
- ```bash
17
- myapp install --uninstall # remove all detected artifacts
18
- myapp install --uninstall --app # scoped removal
19
- ```
20
-
21
- Non-interactive / CI: pass **`--yes`** (or **`--json`**, **`--reinstall`**, **`--update`**) — see [Confirmation](#confirmation).
22
-
23
- ## Quick start (automation)
24
-
25
- ```bash
26
- # First-time setup (bare `install` is equivalent to `--all`)
27
- myapp install --yes
28
-
29
- # Or explicitly
30
- myapp install --all --yes
31
-
32
- # Refresh after upgrading (re-copy running app + refresh detected artifacts in scope)
33
- myapp install --reinstall
34
-
35
- # Upgrade to latest release (when this app supports remote updates)
36
- myapp install --update
37
-
38
- # See what is installed
39
- myapp install --status
40
-
41
- # Remove everything detected on disk (bare `install --uninstall` is equivalent to `--uninstall --all`)
42
- myapp install --uninstall --yes
43
- ```
44
-
45
- ## What gets installed
46
-
47
- | Target | Flag | Destination |
48
- | --- | --- | --- |
49
- | App | `--app` | `~/.local/bin/<key>` |
50
- | Bash completion | `--completions` | `~/.bash_completion.d/<key>` + `.bashrc` PATH snippet |
51
- | Zsh completion | `--completions` | `~/.zsh/completions/_<key>` + `.zshrc` fpath snippet |
52
- | Fish completion | `--completions` | `~/.config/fish/completions/<key>.fish` |
53
- | Cursor skill | `--skill` | `~/.cursor/skills/<dir>/` when `~/.cursor` exists |
54
- | Claude skill | `--skill` | `~/.claude/skills/<dir>/` when `~/.claude` exists |
55
- | Codex / OpenCode / OpenClaw skills | `--skill` | Agent-specific dirs when the agent home or CLI is available |
56
- | MCP config | `--mcp` | Cursor, Claude Code/Desktop, OpenCode, Codex, OpenClaw, ChatGPT desktop (when app data exists). ChatGPT web uses Connectors — see `docs mcp` |
57
- | App config | `--configure` | Interactive wizard writes app settings; `--uninstall --configure` removes the file |
58
-
59
- ### Default `--all` behavior
60
-
61
- Bare **`install`** and **`install --all`** install targets with **`includedInAll: true`**. Core defaults:
62
-
63
- - **Always included:** `app`, `completions`, `configure` (wizard when `program.appConfig` is set)
64
- - **Agent integration** (`install.agentIntegration`, default from `mcpServer.enabled`):
65
- - **`skill`** (default when MCP off): all `*Skill` keys in `--all`; paired `*Mcp` keys excluded
66
- - **`mcp`** (default when `mcpServer.enabled`): all `*Mcp` keys in `--all`; paired skills excluded
67
- - **`both`**: MCP and skill for the same host when available
68
-
69
- Desktop-only MCP hosts (`claudeDesktopMcp`, `chatgptMcp`) follow the MCP side only — no skill pair.
70
-
71
- Scoped flags (`--app`, `--completions`, `--configure`) run that artifact category. **`--skill`** and **`--mcp`** install only targets enabled by `agentIntegration` and per-key `install.targets`. Honor `enabled: false` as a hard off.
72
-
73
- Use **`install --status --json`** to preview effective targets (`effective.all`, `effective.mcp`, `effective.skill`) before installing.
74
-
75
- ### Asymmetric uninstall
76
-
77
- - **`install --uninstall --all`** (including bare **`install --uninstall`**) removes **every detected artifact type**, ignoring `install.targets`.
78
- - Scoped uninstall (`--app`, `--skill`, …) removes only that category.
79
-
80
- Missing targets are skipped silently (no error if nothing is on disk or a shell/agent directory does not exist). Shells not on PATH are skipped silently (no warnings).
81
-
82
- ## `install.targets`
83
-
84
- Configure which artifacts participate in `--all`, `--reinstall`, and `--update`:
85
-
86
- ```typescript
87
- install: {
88
- agentIntegration: "mcp", // | "skill" | "both" — default from mcpServer.enabled
89
- targets: {
90
- app: { includedInAll: false },
91
- chatgptMcp: false,
92
- cursorSkill: { includedInAll: true },
93
- },
94
- },
95
- ```
96
-
97
- `InstallTargetSpec` is `boolean` or `{ enabled?: boolean; includedInAll?: boolean }`. Shorthand `true` enables the target with default `includedInAll`; `false` disables it.
98
-
99
- Artifact keys: `app`, `chatgptMcp`, `claudeCodeMcp`, `claudeDesktopMcp`, `claudeSkill`, `codexMcp`, `codexSkill`, `completions`, `configure`, `cursorMcp`, `cursorSkill`, `openclawMcp`, `openclawSkill`, `opencodeMcp`, `opencodeSkill`.
100
-
101
- Conflicting targets (e.g. both `cursorMcp` and `cursorSkill` without `agentIntegration: 'both'`) fail at program validation time.
102
-
103
- ## Examples
104
-
105
- ### MCP CLI (default)
106
-
107
- ```typescript
108
- const program = {
109
- key: "myapp",
110
- version: "1.0.0",
111
- description: "…",
112
- mcpServer: { enabled: true },
113
- install: {}, // agentIntegration defaults to "mcp"
114
- // …
115
- } satisfies CliProgram;
116
- ```
117
-
118
- Bare **`myapp install --yes`** installs the app, completions, configure wizard (when `appConfig` is set), and MCP hosts — not shell skills for paired agents.
119
-
120
- ### Shell-only CLI (default)
121
-
122
- ```typescript
123
- const program = {
124
- key: "myapp",
125
- version: "1.0.0",
126
- description: "…",
127
- install: {}, // agentIntegration defaults to "skill"
128
- // …
129
- } satisfies CliProgram;
130
- ```
131
-
132
- Bare install includes agent skills (when each host is available), not MCP config.
133
-
134
- ### Overrides
135
-
136
- ```typescript
137
- install: {
138
- agentIntegration: "both", // MCP + skill on the same host
139
- targets: {
140
- chatgptMcp: false, // opt out of one MCP host
141
- app: { includedInAll: false }, // skip app on --all
142
- },
143
- },
144
- ```
145
-
146
- Preview resolved targets: **`myapp install --status --json`**.
147
-
148
- ## Configuration
149
-
150
- On the program root:
151
-
152
- ```typescript
153
- install: {
154
- enabled: false, // opt out of the install built-in
155
- updateGetLatest: async ({ version }) => {
156
- // download or locate latest release; return { path, version, cleanup }
157
- return { path: "/tmp/myapp", version: "2.0.0" };
158
- },
159
- }
160
- ```
161
-
162
- When `updateGetLatest` is set, ArgsBarg adds **`install --update`** (download latest release and reinstall installed artifacts in scope).
163
-
164
- ### GitHub releases (`ghReleaseUpdateGetLatest`)
165
-
166
- For compiled apps published via `gh release`, wire a hook without hand-rolling download logic:
167
-
168
- ```typescript
169
- import {
170
- createGhFetchLatest,
171
- createGhVersionCheck,
172
- ghReleaseUpdateGetLatest,
173
- } from "argsbarg";
174
-
175
- const cachePath = path.join(configDir, "version-check.json");
176
-
177
- install: {
178
- updateGetLatest: ghReleaseUpdateGetLatest({
179
- repo: "owner/repo",
180
- asset: "myapp",
181
- tempPrefix: "myapp-update.",
182
- cachePath,
183
- }),
184
- }
185
-
186
- // Optional: summary notice + background refresh
187
- const versionCheck = createGhVersionCheck({
188
- currentVersion: "1.0.0",
189
- commandName: "myapp",
190
- cachePath,
191
- fetchLatest: createGhFetchLatest({ repo: "owner/repo" }),
192
- });
193
- versionCheck.getUpdateNotice();
194
- versionCheck.refreshIfStale();
195
- ```
196
-
197
- Requires `gh` on PATH and `gh auth login`. Consumers keep app-specific config only (~15 lines).
198
-
199
- ## App config (`program.appConfig`)
200
-
201
- When `program.appConfig` is set on the program root, ArgsBarg manages a flat JSON config file:
202
-
203
- ```typescript
204
- appConfig: {
205
- entries: {
206
- apiToken: {
207
- description: "Create at https://example.com/settings/tokens",
208
- env: "API_TOKEN",
209
- sensitive: true,
210
- },
211
- },
212
- },
213
- ```
214
-
215
- Config file path: `~/.local/lib/<sanitized-key>/config.json`.
216
-
217
- | Flag | Description |
218
- | --- | --- |
219
- | `--configure` | Interactive prompt for each setting; writes or updates the config file. On full install, the wizard runs automatically when configuration is in scope. Standalone **`install --configure`** runs the wizard only (no other install steps). |
220
- | `--uninstall --configure` | Remove the config directory (`~/.local/lib/<key>/`) |
221
- | `--status` | Shows config path and which required keys are set or missing |
222
-
223
- **Configure UX** (TTY):
224
-
225
- ```
226
- Configuration Setup
227
-
228
- API token (API_TOKEN)
229
- Create at https://example.com/settings/tokens
230
- Current: REDACTED
231
- Value (Enter to copy from env):
232
- ```
233
-
234
- Non-sensitive vars show the current value; first-time setup omits the `Current:` line. When the current value comes from a mapped environment variable, Enter copies it into `config.json`; otherwise Enter keeps the existing file value. At runtime, a non-empty mapped environment variable always wins over `config.json` (the file is the fallback when env is unset).
235
-
236
- ## Flags
237
-
238
- ### Target flags
239
-
240
- | Flag | Description |
241
- | --- | --- |
242
- | `--all` | Install the default set (app, shell completions, and configuration when supported) |
243
- | `--app` | Copy this app to the install directory |
244
- | `--completions` | Install bash, zsh, and fish tab-completion scripts |
245
- | `--skill` | Install agent skills for Cursor, Claude, and other supported AI tools |
246
- | `--mcp` | Add MCP server configuration for Cursor, Claude Code, and other supported agents |
247
- | `--configure` | Run the configuration wizard (install) or remove the config file (`--uninstall`) |
248
-
249
- ### Operation flags
250
-
251
- | Flag | Description |
252
- | --- | --- |
253
- | `--status` | Read-only inventory |
254
- | `--reinstall` | Refresh everything already installed (implies `--yes`; no numbered confirm) |
255
- | `--update` | Download the latest release and refresh installed files (implies `--yes`) |
256
- | `--uninstall` | Remove installed files (`--all` removes everything; use individual flags for one category) |
257
- | `--from <path>` | App executable to copy with `--reinstall` / `--update` (default: running executable) |
258
-
259
- ### Behavior flags
260
-
261
- | Flag | Description |
262
- | --- | --- |
263
- | `--yes`, `-y` | Skip confirmation (required for non-TTY unless `--json`, `--reinstall`, or `--update`) |
264
- | `--dry` | Preview changes; per-step messages on stderr with `[dry run]` |
265
- | `--json` | Machine-readable output on stdout (implies `--yes`) |
266
-
267
- ## Confirmation
268
-
269
- Install and uninstall (except `--yes`, `--json`, `--dry`, `--reinstall`, `--update`) print a **`{app} Setup`** banner on stderr, then a numbered list of planned actions on stdout. Reply **`y`** for all, **`n`** or Enter to abort, or numbers for a subset. On **install**, when the plan includes the app as item **1**, it is always installed (prompt example: **`2,3`**); MCP and other targets need the binary on PATH. On **uninstall**, use any subset (e.g. **`1,3`**). After you confirm, **`Done.`** prints on stderr. Per-step progress is suppressed until you confirm; the final **`Installed N file(s).`** summary still prints.
270
-
271
- ## MCP merge behavior
272
-
273
- When `--mcp` runs, entries are merged into host config with:
274
-
275
- ```json
276
- { "command": "<root.key>", "args": ["mcp"] }
277
- ```
278
-
279
- If an existing entry differs, the command exits with an error unless `--yes` is passed (then it overwrites). MCP conflict checks run only for hosts present in the current plan.
280
-
281
- ## Opt out
282
-
283
- ```typescript
284
- const cli = {
285
- key: "myapp",
286
- description: "...",
287
- install: { enabled: false },
288
- // ...
289
- } satisfies CliProgram;
290
- ```
@@ -1,31 +0,0 @@
1
- ---
2
- description: Argsbarg schema — read framework docs before editing CLI commands
3
- globs: "src/**/commands/**/*.{ts,tsx},src/index.{ts,tsx}"
4
- alwaysApply: false
5
- ---
6
-
7
- When adding or changing argsbarg schema, leaf handlers, or MCP exposure:
8
-
9
- 1. **Read** `node_modules/argsbarg/docs/cli-program.md` (required — authoritative guide).
10
- 2. MCP tools, varargs, `inputSchema` → also `node_modules/argsbarg/docs/mcp.md`.
11
- 3. JSON stdout / `outputSchema` guide and codegen → `node_modules/argsbarg/docs/output-schema.md`.
12
- 4. App config / `program.appConfig` guide and codegen → `node_modules/argsbarg/docs/config-schema.md`.
13
- 5. `install`, `install.targets`, completions, skills → `node_modules/argsbarg/docs/install.md`.
14
- 6. Bundled `docs` built-in → `node_modules/argsbarg/docs/bundled-docs.md`.
15
- 7. **Examples** (shipped under `node_modules/argsbarg/examples/`):
16
- - Concepts / minimal config → `examples/config-app/`
17
- - **Copy template** (all builtins, schemagen, `outputSchema`) → `examples/consumer-app/`
18
-
19
- **Hard rules** (details and examples are in the docs above — do not contradict them):
20
-
21
- - Reserved root commands: `completion`, `install`, `mcp`, `version`, `docs`, `update`, `config`.
22
- - `satisfies CliProgram` / `CliLeaf`; action-oriented `description` on root, commands, options, and positionals.
23
- - Omit `mcpTool` unless genuinely CLI-only (`enabled: false`) or an irreducible wire limit — fix schema and headless handlers first.
24
- - Interactive leaves: one headless path for MCP, non-TTY CLI, and `--yes` / `--dry-run` / `--json` (`shouldRunHeadless*`, `requireYesInNonTty`); not raw `isTTY`.
25
- - String options: `format` / `default` / `pattern` per `cli-program.md`; `readLeafInputs()` for multi-flag leaves.
26
- - Varargs (`argMax: 0`): CLI space-separated; MCP JSON array only — no comma-splitting positionals.
27
- - 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.
28
- - JSON stdout: `outputSchema` on the leaf from generated constants in `outputSchemas.ts` — see `output-schema.md`; mark roots with **`JSON payload`** JSDoc in `src/**/types.ts`; do not hand-edit `src/schemas/generated/` or `outputSchemas.ts`.
29
- - App config: `program.appConfig.jsonSchema` from generated `configSchemas.ts` — see `config-schema.md`; mark roots with **`Config schema`** JSDoc; prefer the layout in `node_modules/argsbarg/examples/consumer-app/` when adding new schema roots.
30
-
31
- **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.
@@ -1,20 +0,0 @@
1
- #!/usr/bin/env bun
2
- /*
3
- Multi-file consumer example for program.appConfig.
4
-
5
- Files:
6
- types.ts — AppConfig interface (Config schema JSDoc marker for schemagen)
7
- schema.ts — APP_CONFIG_JSON_SCHEMA (inline; production apps generate this)
8
- program.ts — CliProgram with appConfig block and commands using ctx.appConfig
9
-
10
- Try:
11
- CONFIG_APP_API_TOKEN=dev bun ./examples/config-app/main.ts show --json
12
- CONFIG_APP_API_TOKEN=dev bun ./examples/config-app/main.ts config get
13
- CONFIG_APP_API_TOKEN=dev bun ./examples/config-app/main.ts ping
14
- */
15
-
16
- import { Cli } from "../../src/index.ts";
17
- import { program } from "./program.ts";
18
-
19
- const cli = new Cli(program);
20
- await cli.run();
@@ -1,78 +0,0 @@
1
- /*
2
- CliProgram for the config-app example — program.appConfig with jsonSchema + metadata overlay.
3
- */
4
-
5
- import pkg from "../../package.json" with { type: "json" };
6
- import {
7
- type CliAppConfig,
8
- type CliAppConfigEntry,
9
- CliOptionKind,
10
- type CliProgram,
11
- } from "../../src/index.ts";
12
- import { APP_CONFIG_JSON_SCHEMA } from "./schema.ts";
13
-
14
- const configSchema = {
15
- apiToken: {
16
- description: "Create at https://example.com/settings/tokens",
17
- env: "CONFIG_APP_API_TOKEN",
18
- sensitive: true,
19
- },
20
- defaultRegion: {
21
- description: "AWS region for API calls.",
22
- required: false,
23
- },
24
- maxRetries: {
25
- description: "HTTP retry count (0–10).",
26
- },
27
- prefs: {
28
- description: "Local cache preferences (not exported to env).",
29
- required: false,
30
- },
31
- } as const satisfies Record<string, CliAppConfigEntry>;
32
-
33
- export const program = {
34
- key: "config-app",
35
- version: pkg.version,
36
- description: "Demonstrates program.appConfig, ctx.appConfig, and built-in config get/set.",
37
- appConfig: {
38
- jsonSchema: APP_CONFIG_JSON_SCHEMA,
39
- entries: configSchema,
40
- } satisfies CliAppConfig,
41
- commands: [
42
- {
43
- key: "show",
44
- description: "Print resolved config (secrets redacted).",
45
- options: [
46
- {
47
- name: "json",
48
- description: "Emit JSON.",
49
- kind: CliOptionKind.Presence,
50
- },
51
- ],
52
- handler: (ctx) => {
53
- const out = {
54
- defaultRegion: ctx.appConfig.get("defaultRegion"),
55
- maxRetries: ctx.appConfig.get("maxRetries"),
56
- prefs: ctx.appConfig.get("prefs"),
57
- apiTokenSet: ctx.appConfig.get("apiToken") !== undefined,
58
- };
59
- if (ctx.hasFlag("json")) {
60
- console.log(JSON.stringify(out, null, 2));
61
- } else {
62
- console.log(`region=${out.defaultRegion ?? "(not set)"}`);
63
- console.log(`maxRetries=${out.maxRetries ?? "(not set)"}`);
64
- console.log(`prefs=${out.prefs ? JSON.stringify(out.prefs) : "(not set)"}`);
65
- console.log(`apiToken=${out.apiTokenSet ? "set" : "missing"}`);
66
- }
67
- },
68
- },
69
- {
70
- key: "ping",
71
- description: "Require apiToken and print a short confirmation.",
72
- handler: (ctx) => {
73
- const token = ctx.appConfig.require("apiToken");
74
- console.log(`ok (token length ${String(token).length})`);
75
- },
76
- },
77
- ],
78
- } satisfies CliProgram;