argsbarg 4.0.4 → 4.1.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.
- package/CHANGELOG.md +77 -1
- package/README.md +91 -85
- package/docs/README.md +6 -6
- package/docs/ai-skills.md +8 -5
- package/docs/bundled-docs.md +1 -1
- package/docs/cli-program.md +9 -7
- package/docs/config-schema.md +37 -13
- package/docs/developing.md +8 -8
- package/docs/distribution-homebrew.md +103 -0
- package/docs/install.md +143 -106
- package/docs/mcp.md +23 -12
- package/docs/output-schema.md +1 -1
- package/examples/full-example/Formula/.gitkeep +0 -0
- package/examples/full-example/README.md +98 -0
- package/examples/full-example/biome.json +22 -0
- package/examples/{consumer-app → full-example}/bun.lock +2 -0
- package/examples/full-example/justfile +134 -0
- package/examples/{consumer-app → full-example}/package.json +10 -3
- package/examples/{consumer-app → full-example}/schemas/generated/app-config.json +1 -1
- package/examples/{consumer-app → full-example}/schemas/generated/status.json +1 -1
- package/examples/full-example/scripts/create-identity.ts +11 -0
- package/examples/full-example/scripts/formula-shared.ts +73 -0
- package/examples/full-example/scripts/gen-dev-formula.ts +26 -0
- package/examples/full-example/scripts/print-identity.ts +27 -0
- package/examples/full-example/src/commands/echo/command.ts +21 -0
- package/examples/full-example/src/commands/status/command.test.ts +10 -0
- package/examples/full-example/src/commands/status/command.ts +36 -0
- package/examples/{consumer-app → full-example}/src/commands/status/types.ts +1 -1
- package/examples/full-example/src/index.ts +10 -0
- package/examples/full-example/src/program.ts +57 -0
- package/examples/{consumer-app → full-example}/src/types.ts +1 -1
- package/examples/mcp-test.ts +8 -24
- package/examples/nested.ts +1 -3
- package/index.d.ts +81 -65
- package/package.json +2 -2
- package/src/builtins/builtins.test.ts +37 -22
- package/src/builtins/completion-group.ts +17 -15
- package/src/builtins/config.test.ts +31 -25
- package/src/builtins/config.ts +4 -3
- package/src/builtins/dispatch.ts +25 -1
- package/src/builtins/install.ts +45 -82
- package/src/builtins/mcp.ts +1 -1
- package/src/builtins/registry.ts +2 -0
- package/src/builtins/uninstall.ts +80 -0
- package/src/capabilities.ts +5 -7
- package/src/cli-tool/cli-smoke.test.ts +19 -0
- package/src/cli-tool/create.test.ts +119 -0
- package/src/cli-tool/create.ts +380 -0
- package/{examples/consumer-app/capabilities.test.ts → src/cli-tool/full-example-capabilities.test.ts} +15 -14
- package/src/cli-tool/main.ts +8 -0
- package/src/cli-tool/post-create.ts +111 -0
- package/src/cli-tool/program.ts +82 -0
- package/src/cli-tool/prompt.ts +28 -0
- package/src/cli-tool/run-create.ts +149 -0
- package/src/config/bootstrap.ts +174 -66
- package/src/config/context.test.ts +22 -36
- package/src/config/context.ts +5 -4
- package/src/config/file.test.ts +66 -56
- package/src/config/file.ts +33 -25
- package/src/config/resolve.test.ts +192 -1
- package/src/config/resolve.ts +92 -13
- package/src/config.integration.test.ts +17 -10
- package/src/docs/api-guide.test.ts +4 -5
- package/src/docs/docs.test.ts +2 -1
- package/src/docs/mcp-guide.ts +7 -8
- package/src/hidden-mcpb.test.ts +41 -1
- package/src/index.ts +7 -10
- package/src/install/binary-placement.test.ts +101 -0
- package/src/install/binary-placement.ts +47 -0
- package/src/install/detect-installed.ts +2 -97
- package/src/install/index.ts +239 -168
- package/src/install/install-validate.test.ts +61 -0
- package/src/install/install.test.ts +170 -90
- package/src/install/mcp-openclaw.test.ts +40 -0
- package/src/install/mcp-openclaw.ts +106 -0
- package/src/install/normalize-uninstall.ts +11 -0
- package/src/install/normalize.ts +20 -0
- package/src/install/paths.ts +18 -26
- package/src/install/plan.ts +40 -261
- package/src/install/shell.ts +0 -14
- package/src/install/status.test.ts +85 -0
- package/src/install/status.ts +22 -15
- package/src/install/target-base.ts +93 -0
- package/src/install/target-detect.ts +20 -0
- package/src/install/target-effective.ts +129 -0
- package/src/install/target-mcp-cli.ts +149 -0
- package/src/install/target-mcp-json.ts +130 -0
- package/src/install/target-plan-build.ts +67 -0
- package/src/install/target-registry.ts +57 -0
- package/src/install/target-scope.ts +253 -0
- package/src/install/target-skill.ts +104 -0
- package/src/install/target-types.ts +129 -0
- package/src/install/targets/app.ts +60 -0
- package/src/install/targets/chatgpt-mcp.ts +12 -0
- package/src/install/targets/claude-code-mcp.ts +15 -0
- package/src/install/targets/claude-desktop-mcp.ts +12 -0
- package/src/install/targets/claude-skill.ts +16 -0
- package/src/install/targets/codex-mcp.ts +25 -0
- package/src/install/targets/codex-skill.ts +14 -0
- package/src/install/targets/configure.ts +63 -0
- package/src/install/targets/cursor-mcp.ts +15 -0
- package/src/install/targets/cursor-skill.ts +16 -0
- package/src/install/targets/index.ts +50 -0
- package/src/install/targets/openclaw-mcp.ts +25 -0
- package/src/install/targets/openclaw-skill.ts +17 -0
- package/src/install/targets/opencode-mcp.ts +101 -0
- package/src/install/targets/opencode-skill.ts +15 -0
- package/src/install/targets.test.ts +118 -0
- package/src/install/uninstall.ts +16 -152
- package/src/invoke.test.ts +7 -1
- package/src/mcp/bundle.ts +16 -4
- package/src/mcp/claude.test.ts +14 -1
- package/src/mcp/claude.ts +11 -4
- package/src/mcp/env.test.ts +92 -0
- package/src/mcp/env.ts +15 -14
- package/src/mcp/zip.test.ts +17 -0
- package/src/mcp/zip.ts +62 -9
- package/src/mcp.integration.test.ts +1 -1
- package/src/parse.test.ts +14 -2
- package/src/paths/host.ts +11 -11
- package/src/paths/remove-empty-dir.ts +13 -0
- package/src/prompt.ts +10 -0
- package/src/schema.ts +9 -1
- package/src/skill/generate.ts +18 -4
- package/src/skill/install.ts +33 -6
- package/src/skill/naming.ts +28 -0
- package/src/types.ts +86 -7
- package/src/validate.ts +73 -9
- package/docs/templates/cursor/rules/cli-program.mdc +0 -31
- package/examples/config-app/main.ts +0 -20
- package/examples/config-app/program.ts +0 -81
- package/examples/config-app/schema.ts +0 -37
- package/examples/config-app/types.ts +0 -19
- package/examples/consumer-app/README.md +0 -57
- package/examples/consumer-app/src/main.ts +0 -15
- package/examples/consumer-app/src/program.ts +0 -108
- package/src/install/binary.ts +0 -94
- package/src/install/completions.ts +0 -56
- package/src/install/update.test.ts +0 -108
- package/src/install/update.ts +0 -57
- /package/examples/{consumer-app → full-example}/schemas/configSchemas.ts +0 -0
- /package/examples/{consumer-app → full-example}/schemas/outputSchemas.ts +0 -0
- /package/examples/{consumer-app → full-example}/scripts/schemagen/discover-schema-roots.test.ts +0 -0
- /package/examples/{consumer-app → full-example}/scripts/schemagen/discover-schema-roots.ts +0 -0
- /package/examples/{consumer-app → full-example}/scripts/schemagen/naming.ts +0 -0
- /package/examples/{consumer-app → full-example}/scripts/schemagen.ts +0 -0
- /package/examples/{consumer-app → full-example}/tsconfig.json +0 -0
package/src/types.ts
CHANGED
|
@@ -133,6 +133,10 @@ export interface CliMcpBundleConfig {
|
|
|
133
133
|
export interface CliMcpServerConfig {
|
|
134
134
|
/** When `true`, enables the `mcp` built-in and MCP stdio server. */
|
|
135
135
|
enabled: boolean;
|
|
136
|
+
/** When `true`, `mcp bundle` writes `dist/<key>.mcpb` for Claude Desktop. Default false. */
|
|
137
|
+
mcpd?: boolean;
|
|
138
|
+
/** When `true`, `mcp bundle` also writes `dist/claude-plugin/<name>.zip`. Default false. */
|
|
139
|
+
claudePlugin?: boolean;
|
|
136
140
|
/** Resource URI for schema export (default: `<sanitized root key>://schema`). */
|
|
137
141
|
schemaResourceUri?: string;
|
|
138
142
|
/**
|
|
@@ -198,6 +202,26 @@ export interface CliUpdateArtifact {
|
|
|
198
202
|
/** Fetches the latest release binary for `install --update`. */
|
|
199
203
|
export type CliUpdateGetLatest = (ctx: { version: string }) => Promise<CliUpdateArtifact>;
|
|
200
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
|
+
|
|
201
225
|
/**
|
|
202
226
|
* Metadata overlay for one key in {@link CliAppConfig.entries}.
|
|
203
227
|
* Types and validation come from {@link CliAppConfig.jsonSchema} when set; otherwise all values are strings.
|
|
@@ -218,14 +242,17 @@ export interface CliAppConfigEntry {
|
|
|
218
242
|
sensitive?: boolean;
|
|
219
243
|
/** When set: non-empty `process.env[env]` overrides file; value exported after resolve. */
|
|
220
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;
|
|
221
250
|
}
|
|
222
251
|
|
|
223
252
|
/**
|
|
224
253
|
* App configuration block on the program root ({@link CliProgram.appConfig}).
|
|
225
254
|
*/
|
|
226
255
|
export interface CliAppConfig {
|
|
227
|
-
/** Default: `~/.config/<sanitized-key>/config` (or `%APPDATA%/<key>/config` on Windows). */
|
|
228
|
-
path?: string;
|
|
229
256
|
/** Built-in `config get` / `config set`. Default: enabled when `appConfig` is set. */
|
|
230
257
|
commands?: boolean | { enabled?: boolean; mcpSet?: boolean };
|
|
231
258
|
/** Block JSON Schema (draft-07). When omitted, synthesize all-string schema from `entries`. */
|
|
@@ -237,13 +264,65 @@ export interface CliAppConfig {
|
|
|
237
264
|
export interface CliInstallConfig {
|
|
238
265
|
/** When `false`, hide/disable `install` (default: enabled). */
|
|
239
266
|
enabled?: boolean;
|
|
240
|
-
/** Default bin directory (default: `~/.local/bin`). Overridden by `INSTALL_PREFIX` env and `--prefix`. */
|
|
241
|
-
prefix?: string;
|
|
242
267
|
/**
|
|
243
|
-
*
|
|
244
|
-
*
|
|
268
|
+
* Default agent integration for full install (`install --all`).
|
|
269
|
+
* - `'mcp'` when `mcpServer.enabled` (default): MCP targets in `--all`; paired skills excluded.
|
|
270
|
+
* - `'skill'` when MCP is off (default): skill targets in `--all`; paired MCP excluded.
|
|
271
|
+
* - `'both'`: install MCP and skill for the same host when both are available.
|
|
245
272
|
*/
|
|
246
|
-
|
|
273
|
+
agentIntegration?: InstallAgentIntegration;
|
|
274
|
+
/** Per-artifact gates for full install/uninstall. See {@link resolveEffectiveInstallTargets}. */
|
|
275
|
+
targets?: CliInstallTargets;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
/** Agent integration mode for install — MCP vs shell skill per host. */
|
|
279
|
+
export type InstallAgentIntegration = "mcp" | "skill" | "both";
|
|
280
|
+
|
|
281
|
+
/** Boolean or structured gate for one install artifact. */
|
|
282
|
+
export type InstallTargetSpec =
|
|
283
|
+
| boolean
|
|
284
|
+
| {
|
|
285
|
+
/** When false, artifact is never installed (even with scoped CLI flags). Default true. */
|
|
286
|
+
enabled?: boolean;
|
|
287
|
+
/** When true, included in bare `install` / `install --all`. Default varies by key. */
|
|
288
|
+
includedInAll?: boolean;
|
|
289
|
+
};
|
|
290
|
+
|
|
291
|
+
export interface ResolvedInstallTarget {
|
|
292
|
+
enabled: boolean;
|
|
293
|
+
includedInAll: boolean;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/** Per-artifact gates for full install/uninstall. See {@link resolveEffectiveInstallTargets}. */
|
|
297
|
+
export interface CliInstallTargets {
|
|
298
|
+
/** App binary status only (Homebrew PATH); no self-install. */
|
|
299
|
+
app?: InstallTargetSpec;
|
|
300
|
+
/** ChatGPT desktop MCP. Default false. */
|
|
301
|
+
chatgptMcp?: InstallTargetSpec;
|
|
302
|
+
/** Claude Code MCP (`~/.claude.json`). Default false. */
|
|
303
|
+
claudeCodeMcp?: InstallTargetSpec;
|
|
304
|
+
/** Claude Desktop MCP. Default false. */
|
|
305
|
+
claudeDesktopMcp?: InstallTargetSpec;
|
|
306
|
+
/** Claude Code skill. Default false. */
|
|
307
|
+
claudeSkill?: InstallTargetSpec;
|
|
308
|
+
/** Codex MCP (`codex mcp add`). Default false. */
|
|
309
|
+
codexMcp?: InstallTargetSpec;
|
|
310
|
+
/** Codex skill. Default false. */
|
|
311
|
+
codexSkill?: InstallTargetSpec;
|
|
312
|
+
/** App config: wizard via install --configure only. Default not in --all. */
|
|
313
|
+
configure?: InstallTargetSpec;
|
|
314
|
+
/** Cursor MCP. Default false. */
|
|
315
|
+
cursorMcp?: InstallTargetSpec;
|
|
316
|
+
/** Cursor skill. Default false. */
|
|
317
|
+
cursorSkill?: InstallTargetSpec;
|
|
318
|
+
/** OpenClaw MCP. Default false. */
|
|
319
|
+
openclawMcp?: InstallTargetSpec;
|
|
320
|
+
/** OpenClaw skill. Default false. */
|
|
321
|
+
openclawSkill?: InstallTargetSpec;
|
|
322
|
+
/** OpenCode MCP. Default false. */
|
|
323
|
+
opencodeMcp?: InstallTargetSpec;
|
|
324
|
+
/** OpenCode skill. Default false. */
|
|
325
|
+
opencodeSkill?: InstallTargetSpec;
|
|
247
326
|
}
|
|
248
327
|
|
|
249
328
|
/**
|
package/src/validate.ts
CHANGED
|
@@ -6,6 +6,7 @@ import { reservedCommandNames, resolveCapabilities } from "./capabilities.ts";
|
|
|
6
6
|
import { reservedDocsTopicResourceUris } from "./docs/mcp-resources.ts";
|
|
7
7
|
import { DOCS_BUILTIN_TOPIC_KEYS } from "./docs/resolve.ts";
|
|
8
8
|
import { validateFormatValue } from "./formats.ts";
|
|
9
|
+
import { AGENT_PAIRS } from "./install/target-registry.ts";
|
|
9
10
|
import { resolveMcpSchemaUri } from "./mcp/tools.ts";
|
|
10
11
|
import {
|
|
11
12
|
type CliLeaf,
|
|
@@ -14,6 +15,8 @@ import {
|
|
|
14
15
|
type CliProgram,
|
|
15
16
|
CliSchemaValidationError,
|
|
16
17
|
CliValueFormat,
|
|
18
|
+
type InstallAgentIntegration,
|
|
19
|
+
type InstallTargetSpec,
|
|
17
20
|
isCliLeaf,
|
|
18
21
|
isCliRouter,
|
|
19
22
|
} from "./types.ts";
|
|
@@ -78,6 +81,11 @@ function validateConfigBlock(appConfigBlock: import("./types.ts").CliAppConfig):
|
|
|
78
81
|
}
|
|
79
82
|
envNames.add(entry.env);
|
|
80
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
|
+
}
|
|
81
89
|
}
|
|
82
90
|
|
|
83
91
|
const jsonSchema = appConfigBlock.jsonSchema;
|
|
@@ -105,6 +113,69 @@ function validateConfigBlock(appConfigBlock: import("./types.ts").CliAppConfig):
|
|
|
105
113
|
}
|
|
106
114
|
}
|
|
107
115
|
|
|
116
|
+
const PAIR_HOST_LABELS: Record<string, string> = {
|
|
117
|
+
cursorMcp: "cursor",
|
|
118
|
+
claudeCodeMcp: "claudeCode",
|
|
119
|
+
codexMcp: "codex",
|
|
120
|
+
opencodeMcp: "opencode",
|
|
121
|
+
openclawMcp: "openclaw",
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
function installTargetExplicitTruthy(spec: InstallTargetSpec | undefined): boolean {
|
|
125
|
+
if (spec === undefined || spec === false) return false;
|
|
126
|
+
if (spec === true) return true;
|
|
127
|
+
return spec.enabled !== false;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/** Validates `program.install` targets and agentIntegration. */
|
|
131
|
+
function validateInstallConfig(program: CliProgram): void {
|
|
132
|
+
const install = program.install;
|
|
133
|
+
if (!install) return;
|
|
134
|
+
|
|
135
|
+
if ("prefix" in install) {
|
|
136
|
+
throw new CliSchemaValidationError(
|
|
137
|
+
"install.prefix removed; app installs to ~/.local/bin/<key>",
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
if (!install.targets) return;
|
|
142
|
+
|
|
143
|
+
const targets = install.targets;
|
|
144
|
+
if ("allSkills" in targets || "allMcps" in targets) {
|
|
145
|
+
throw new CliSchemaValidationError(
|
|
146
|
+
"install.targets.allSkills/allMcps removed; use agentIntegration and per-key targets",
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
const integration: InstallAgentIntegration =
|
|
151
|
+
install.agentIntegration ?? (program.mcpServer?.enabled === true ? "mcp" : "skill");
|
|
152
|
+
|
|
153
|
+
for (const [mcpKey, skillKey] of AGENT_PAIRS) {
|
|
154
|
+
const mcpSpec = targets[mcpKey];
|
|
155
|
+
const skillSpec = targets[skillKey];
|
|
156
|
+
const mcpOn = installTargetExplicitTruthy(mcpSpec);
|
|
157
|
+
const skillOn = installTargetExplicitTruthy(skillSpec);
|
|
158
|
+
const host = PAIR_HOST_LABELS[mcpKey] ?? mcpKey;
|
|
159
|
+
|
|
160
|
+
if (mcpOn && skillOn && integration !== "both") {
|
|
161
|
+
throw new CliSchemaValidationError(
|
|
162
|
+
`install.targets: ${host} has both MCP and skill configured; set agentIntegration: 'both' or disable one side`,
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
if (integration === "skill" && mcpOn) {
|
|
167
|
+
throw new CliSchemaValidationError(
|
|
168
|
+
`install.targets.${mcpKey} requires agentIntegration: 'both' when agentIntegration is 'skill'`,
|
|
169
|
+
);
|
|
170
|
+
}
|
|
171
|
+
if (integration === "mcp" && skillOn) {
|
|
172
|
+
throw new CliSchemaValidationError(
|
|
173
|
+
`install.targets.${skillKey} requires agentIntegration: 'both' when agentIntegration is 'mcp'`,
|
|
174
|
+
);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
108
179
|
/** Validates a program schema. */
|
|
109
180
|
export function cliValidateProgram(program: CliProgram): void {
|
|
110
181
|
if (!program.version || program.version.trim().length === 0) {
|
|
@@ -131,15 +202,8 @@ export function cliValidateProgram(program: CliProgram): void {
|
|
|
131
202
|
validateConfigBlock(program.appConfig);
|
|
132
203
|
}
|
|
133
204
|
|
|
134
|
-
if (program.install
|
|
135
|
-
|
|
136
|
-
throw new CliSchemaValidationError(
|
|
137
|
-
"install.updateGetLatest requires install to be enabled (omit install.enabled: false)",
|
|
138
|
-
);
|
|
139
|
-
}
|
|
140
|
-
if (typeof program.install.updateGetLatest !== "function") {
|
|
141
|
-
throw new CliSchemaValidationError("install.updateGetLatest must be a function");
|
|
142
|
-
}
|
|
205
|
+
if (program.install !== undefined) {
|
|
206
|
+
validateInstallConfig(program);
|
|
143
207
|
}
|
|
144
208
|
|
|
145
209
|
const caps = resolveCapabilities(program);
|
|
@@ -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`, 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,81 +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 configPath = process.env.CONFIG_APP_CONFIG_FILE;
|
|
15
|
-
|
|
16
|
-
const configSchema = {
|
|
17
|
-
apiToken: {
|
|
18
|
-
description: "Create at https://example.com/settings/tokens",
|
|
19
|
-
env: "CONFIG_APP_API_TOKEN",
|
|
20
|
-
sensitive: true,
|
|
21
|
-
},
|
|
22
|
-
defaultRegion: {
|
|
23
|
-
description: "AWS region for API calls.",
|
|
24
|
-
required: false,
|
|
25
|
-
},
|
|
26
|
-
maxRetries: {
|
|
27
|
-
description: "HTTP retry count (0–10).",
|
|
28
|
-
},
|
|
29
|
-
prefs: {
|
|
30
|
-
description: "Local cache preferences (not exported to env).",
|
|
31
|
-
required: false,
|
|
32
|
-
},
|
|
33
|
-
} as const satisfies Record<string, CliAppConfigEntry>;
|
|
34
|
-
|
|
35
|
-
export const program = {
|
|
36
|
-
key: "config-app",
|
|
37
|
-
version: pkg.version,
|
|
38
|
-
description: "Demonstrates program.appConfig, ctx.appConfig, and built-in config get/set.",
|
|
39
|
-
appConfig: {
|
|
40
|
-
...(configPath ? { path: configPath } : {}),
|
|
41
|
-
jsonSchema: APP_CONFIG_JSON_SCHEMA,
|
|
42
|
-
entries: configSchema,
|
|
43
|
-
} satisfies CliAppConfig,
|
|
44
|
-
commands: [
|
|
45
|
-
{
|
|
46
|
-
key: "show",
|
|
47
|
-
description: "Print resolved config (secrets redacted).",
|
|
48
|
-
options: [
|
|
49
|
-
{
|
|
50
|
-
name: "json",
|
|
51
|
-
description: "Emit JSON.",
|
|
52
|
-
kind: CliOptionKind.Presence,
|
|
53
|
-
},
|
|
54
|
-
],
|
|
55
|
-
handler: (ctx) => {
|
|
56
|
-
const out = {
|
|
57
|
-
defaultRegion: ctx.appConfig.get("defaultRegion"),
|
|
58
|
-
maxRetries: ctx.appConfig.get("maxRetries"),
|
|
59
|
-
prefs: ctx.appConfig.get("prefs"),
|
|
60
|
-
apiTokenSet: ctx.appConfig.get("apiToken") !== undefined,
|
|
61
|
-
};
|
|
62
|
-
if (ctx.hasFlag("json")) {
|
|
63
|
-
console.log(JSON.stringify(out, null, 2));
|
|
64
|
-
} else {
|
|
65
|
-
console.log(`region=${out.defaultRegion ?? "(not set)"}`);
|
|
66
|
-
console.log(`maxRetries=${out.maxRetries ?? "(not set)"}`);
|
|
67
|
-
console.log(`prefs=${out.prefs ? JSON.stringify(out.prefs) : "(not set)"}`);
|
|
68
|
-
console.log(`apiToken=${out.apiTokenSet ? "set" : "missing"}`);
|
|
69
|
-
}
|
|
70
|
-
},
|
|
71
|
-
},
|
|
72
|
-
{
|
|
73
|
-
key: "ping",
|
|
74
|
-
description: "Require apiToken and print a short confirmation.",
|
|
75
|
-
handler: (ctx) => {
|
|
76
|
-
const token = ctx.appConfig.require("apiToken");
|
|
77
|
-
console.log(`ok (token length ${String(token).length})`);
|
|
78
|
-
},
|
|
79
|
-
},
|
|
80
|
-
],
|
|
81
|
-
} satisfies CliProgram;
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
Inline draft-07 JSON Schema for AppConfig.
|
|
3
|
-
Production apps commit generated JSON and import via configSchemas.ts — see docs/config-schema.md.
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import type { AppConfig } from "./types.ts";
|
|
7
|
-
|
|
8
|
-
/** JSON Schema root for program.appConfig.jsonSchema (hand-written stand-in for schemagen). */
|
|
9
|
-
export const APP_CONFIG_JSON_SCHEMA = {
|
|
10
|
-
$schema: "http://json-schema.org/draft-07/schema#",
|
|
11
|
-
type: "object",
|
|
12
|
-
additionalProperties: false,
|
|
13
|
-
required: ["apiToken", "maxRetries"],
|
|
14
|
-
properties: {
|
|
15
|
-
apiToken: { type: "string", minLength: 1 },
|
|
16
|
-
defaultRegion: { type: "string", default: "us-east-1" },
|
|
17
|
-
maxRetries: { type: "integer", minimum: 0, maximum: 10, default: 3 },
|
|
18
|
-
prefs: {
|
|
19
|
-
type: "object",
|
|
20
|
-
additionalProperties: false,
|
|
21
|
-
required: ["ttl"],
|
|
22
|
-
properties: {
|
|
23
|
-
ttl: { type: "integer", minimum: 1 },
|
|
24
|
-
},
|
|
25
|
-
},
|
|
26
|
-
},
|
|
27
|
-
} as const satisfies Record<string, unknown>;
|
|
28
|
-
|
|
29
|
-
/** Compile-time check that schema keys align with AppConfig (documentation only). */
|
|
30
|
-
type _SchemaKeys = keyof typeof APP_CONFIG_JSON_SCHEMA.properties;
|
|
31
|
-
type _ConfigKeys = keyof AppConfig;
|
|
32
|
-
const _assertKeysAlign: _SchemaKeys extends _ConfigKeys
|
|
33
|
-
? _ConfigKeys extends _SchemaKeys
|
|
34
|
-
? true
|
|
35
|
-
: never
|
|
36
|
-
: never = true;
|
|
37
|
-
void _assertKeysAlign;
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Config schema
|
|
3
|
-
*
|
|
4
|
-
* Application settings persisted in a flat JSON file (`program.appConfig`).
|
|
5
|
-
* In a production app, generate `APP_CONFIG_JSON_SCHEMA` from this interface
|
|
6
|
-
* with ts-json-schema-generator — see docs/config-schema.md.
|
|
7
|
-
*/
|
|
8
|
-
export interface AppConfig {
|
|
9
|
-
/** API token from the provider dashboard. */
|
|
10
|
-
apiToken: string;
|
|
11
|
-
/** AWS region (default us-east-1). */
|
|
12
|
-
defaultRegion?: string;
|
|
13
|
-
/** HTTP retry count (default 3). */
|
|
14
|
-
maxRetries: number;
|
|
15
|
-
/** Local preferences (file-only; not mapped to process.env). */
|
|
16
|
-
prefs?: {
|
|
17
|
-
ttl: number;
|
|
18
|
-
};
|
|
19
|
-
}
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
# consumer-app
|
|
2
|
-
|
|
3
|
-
**Kitchen-sink argsbarg reference** — copy this layout when bootstrapping a production CLI. For a minimal `program.appConfig` intro, see [`../config-app/`](../config-app/).
|
|
4
|
-
|
|
5
|
-
## What this demonstrates
|
|
6
|
-
|
|
7
|
-
| Area | Files / wiring |
|
|
8
|
-
| --- | --- |
|
|
9
|
-
| All builtins | `completion`, `version`, `install` (+ `--update`), `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
|
-
| Handler access | `ctx.appConfig` 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
|
-
|
|
17
|
-
## Quick start (in this repo)
|
|
18
|
-
|
|
19
|
-
```bash
|
|
20
|
-
cd examples/consumer-app
|
|
21
|
-
bun install
|
|
22
|
-
bun run schemagen # after changing src/**/types.ts
|
|
23
|
-
CONSUMER_APP_API_TOKEN=dev bun run start status --json
|
|
24
|
-
CONSUMER_APP_API_TOKEN=dev bun run start config get apiToken --json
|
|
25
|
-
CONSUMER_APP_API_TOKEN=dev bun run start docs readme
|
|
26
|
-
```
|
|
27
|
-
|
|
28
|
-
## Copy into a new app
|
|
29
|
-
|
|
30
|
-
1. Copy this directory into your repo (e.g. `apps/my-cli/`).
|
|
31
|
-
2. Set `"argsbarg": "^<version>"` in `package.json` (replace `file:../..`).
|
|
32
|
-
3. Run `bun run schemagen` and commit `schemas/generated/` + bridge `.ts` files.
|
|
33
|
-
4. Copy [`node_modules/argsbarg/docs/templates/cursor/rules/cli-program.mdc`](../../docs/templates/cursor/rules/cli-program.mdc) to `.cursor/rules/`.
|
|
34
|
-
|
|
35
|
-
## Schemagen markers
|
|
36
|
-
|
|
37
|
-
| Marker in interface JSDoc | Artifact |
|
|
38
|
-
| --- | --- |
|
|
39
|
-
| `Config schema` | `schemas/configSchemas.ts` + `schemas/generated/*-config.json` |
|
|
40
|
-
| `JSON payload` | `schemas/outputSchemas.ts` + `schemas/generated/*.json` |
|
|
41
|
-
|
|
42
|
-
Discovery walks `src/**/types.ts` only.
|
|
43
|
-
|
|
44
|
-
## Environment
|
|
45
|
-
|
|
46
|
-
| Variable | Purpose |
|
|
47
|
-
| --- | --- |
|
|
48
|
-
| `CONSUMER_APP_API_TOKEN` | Overrides `apiToken` via `program.appConfig` env mapping |
|
|
49
|
-
| `CONSUMER_APP_CONFIG_FILE` | Overrides config file path (`config.path`) |
|
|
50
|
-
|
|
51
|
-
## Maintainers (argsbarg repo)
|
|
52
|
-
|
|
53
|
-
When adding or changing builtins, update this example and run:
|
|
54
|
-
|
|
55
|
-
```bash
|
|
56
|
-
just consumer-app-schemagen
|
|
57
|
-
```
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bun
|
|
2
|
-
/*
|
|
3
|
-
Kitchen-sink argsbarg consumer reference.
|
|
4
|
-
|
|
5
|
-
cd examples/consumer-app && bun install && bun run schemagen
|
|
6
|
-
CONSUMER_APP_API_TOKEN=dev bun run start status --json
|
|
7
|
-
CONSUMER_APP_API_TOKEN=dev bun run start config get
|
|
8
|
-
CONSUMER_APP_API_TOKEN=dev bun run start docs readme
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
import { Cli } from "argsbarg";
|
|
12
|
-
import { program } from "./program.ts";
|
|
13
|
-
|
|
14
|
-
const cli = new Cli(program);
|
|
15
|
-
await cli.run();
|
|
@@ -1,108 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
Kitchen-sink CliProgram — every argsbarg builtin enabled.
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import {
|
|
6
|
-
type CliAppConfig,
|
|
7
|
-
type CliAppConfigEntry,
|
|
8
|
-
CliOptionKind,
|
|
9
|
-
type CliProgram,
|
|
10
|
-
} from "argsbarg";
|
|
11
|
-
import readmeText from "../README.md" with { type: "text" };
|
|
12
|
-
import { APP_CONFIG_JSON_SCHEMA } from "../schemas/configSchemas.ts";
|
|
13
|
-
import { STATUS_JSON_OUTPUT_SCHEMA } from "../schemas/outputSchemas.ts";
|
|
14
|
-
import type { StatusJsonOutput } from "./commands/status/types.ts";
|
|
15
|
-
|
|
16
|
-
const configPath = process.env.CONSUMER_APP_CONFIG_FILE;
|
|
17
|
-
|
|
18
|
-
const configSchema = {
|
|
19
|
-
apiToken: {
|
|
20
|
-
description: "Create at https://example.com/settings/tokens",
|
|
21
|
-
env: "CONSUMER_APP_API_TOKEN",
|
|
22
|
-
sensitive: true,
|
|
23
|
-
},
|
|
24
|
-
defaultRegion: {
|
|
25
|
-
description: "AWS region for API calls.",
|
|
26
|
-
required: false,
|
|
27
|
-
},
|
|
28
|
-
maxRetries: {
|
|
29
|
-
description: "HTTP retry count (0–10).",
|
|
30
|
-
},
|
|
31
|
-
prefs: {
|
|
32
|
-
description: "Local cache preferences (not exported to env).",
|
|
33
|
-
required: false,
|
|
34
|
-
},
|
|
35
|
-
} as const satisfies Record<string, CliAppConfigEntry>;
|
|
36
|
-
|
|
37
|
-
export const program = {
|
|
38
|
-
key: "consumer-app",
|
|
39
|
-
version: "1.0.0",
|
|
40
|
-
description: "Argsbarg kitchen-sink reference — all builtins, schemagen, ctx.appConfig.",
|
|
41
|
-
appConfig: {
|
|
42
|
-
...(configPath ? { path: configPath } : {}),
|
|
43
|
-
jsonSchema: APP_CONFIG_JSON_SCHEMA,
|
|
44
|
-
entries: configSchema,
|
|
45
|
-
} satisfies CliAppConfig,
|
|
46
|
-
docs: {
|
|
47
|
-
enabled: true,
|
|
48
|
-
topics: {
|
|
49
|
-
readme: {
|
|
50
|
-
text: readmeText,
|
|
51
|
-
},
|
|
52
|
-
},
|
|
53
|
-
},
|
|
54
|
-
mcpServer: {
|
|
55
|
-
enabled: true,
|
|
56
|
-
},
|
|
57
|
-
install: {
|
|
58
|
-
updateGetLatest: async () => ({
|
|
59
|
-
path: process.execPath,
|
|
60
|
-
version: "1.0.0",
|
|
61
|
-
}),
|
|
62
|
-
},
|
|
63
|
-
commands: [
|
|
64
|
-
{
|
|
65
|
-
key: "status",
|
|
66
|
-
description: "Show resolved config and app version.",
|
|
67
|
-
options: [
|
|
68
|
-
{
|
|
69
|
-
name: "json",
|
|
70
|
-
description: "Emit JSON.",
|
|
71
|
-
kind: CliOptionKind.Presence,
|
|
72
|
-
},
|
|
73
|
-
],
|
|
74
|
-
outputSchema: STATUS_JSON_OUTPUT_SCHEMA,
|
|
75
|
-
handler: (ctx) => {
|
|
76
|
-
const out: StatusJsonOutput = {
|
|
77
|
-
defaultRegion: ctx.appConfig.get("defaultRegion") as string | undefined,
|
|
78
|
-
maxRetries: ctx.appConfig.get("maxRetries") as number | undefined,
|
|
79
|
-
apiTokenSet: ctx.appConfig.get("apiToken") !== undefined,
|
|
80
|
-
version: ctx.program.version,
|
|
81
|
-
};
|
|
82
|
-
if (ctx.hasFlag("json")) {
|
|
83
|
-
console.log(JSON.stringify(out, null, 2));
|
|
84
|
-
} else {
|
|
85
|
-
console.log(`version=${out.version}`);
|
|
86
|
-
console.log(`region=${out.defaultRegion ?? "(not set)"}`);
|
|
87
|
-
console.log(`maxRetries=${out.maxRetries ?? "(not set)"}`);
|
|
88
|
-
console.log(`apiToken=${out.apiTokenSet ? "set" : "missing"}`);
|
|
89
|
-
}
|
|
90
|
-
},
|
|
91
|
-
},
|
|
92
|
-
{
|
|
93
|
-
key: "echo",
|
|
94
|
-
description: "Echo a message (MCP-friendly leaf).",
|
|
95
|
-
options: [
|
|
96
|
-
{
|
|
97
|
-
name: "message",
|
|
98
|
-
description: "Text to print.",
|
|
99
|
-
kind: CliOptionKind.String,
|
|
100
|
-
required: true,
|
|
101
|
-
},
|
|
102
|
-
],
|
|
103
|
-
handler: (ctx) => {
|
|
104
|
-
console.log(ctx.stringOpt("message") ?? "");
|
|
105
|
-
},
|
|
106
|
-
},
|
|
107
|
-
],
|
|
108
|
-
} satisfies CliProgram;
|