argsbarg 4.1.1 → 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.
- package/CHANGELOG.md +27 -1
- package/README.md +5 -5
- package/docs/README.md +3 -3
- package/docs/ai-skills.md +9 -9
- package/docs/bundled-docs.md +4 -4
- package/docs/cli-program.md +8 -8
- package/docs/config-schema.md +2 -2
- package/docs/configure.md +177 -0
- package/docs/developing.md +1 -1
- package/docs/distribution-homebrew.md +10 -9
- package/docs/mcp.md +9 -9
- package/examples/full-example/README.md +3 -3
- package/examples/full-example/justfile +6 -6
- package/examples/full-example/scripts/formula-shared.ts +2 -2
- package/examples/full-example/src/program.ts +3 -3
- package/examples/nested.ts +1 -1
- package/index.d.ts +23 -16
- package/package.json +1 -1
- package/src/builtins/builtins.test.ts +82 -61
- package/src/builtins/completion-group.ts +4 -6
- package/src/builtins/configure-copy.ts +86 -0
- package/src/builtins/configure.ts +70 -0
- package/src/builtins/dispatch.ts +13 -33
- package/src/builtins/index.ts +1 -1
- package/src/builtins/mcp.ts +2 -2
- package/src/builtins/registry.ts +6 -6
- package/src/capabilities.ts +22 -13
- package/src/cli-tool/cli-smoke.test.ts +13 -3
- package/src/cli-tool/create.test.ts +23 -1
- package/src/cli-tool/create.ts +26 -4
- package/src/cli-tool/full-example-capabilities.test.ts +2 -2
- package/src/cli-tool/program.ts +20 -5
- package/src/cli-tool/run-create.ts +8 -19
- package/src/config/bootstrap.ts +11 -9
- package/src/config/file.test.ts +1 -1
- package/src/config/resolve.ts +2 -2
- package/src/configure/configure.test.ts +148 -0
- package/src/configure/index.ts +284 -0
- package/src/configure/prompt.ts +40 -0
- package/src/docs/builtin.ts +3 -5
- package/src/docs/docs.test.ts +5 -5
- package/src/docs/mcp-guide.ts +4 -4
- package/src/index.ts +2 -2
- package/src/install/install-validate.test.ts +5 -5
- package/src/install/opts.ts +17 -0
- package/src/install/target-effective.ts +8 -8
- package/src/install/target-scope.ts +11 -8
- package/src/install/targets/configure.ts +1 -1
- package/src/install/targets.test.ts +4 -4
- package/src/invoke.test.ts +1 -1
- package/src/mcp/tools.ts +1 -1
- package/src/mcp.integration.test.ts +4 -4
- package/src/parse.test.ts +11 -13
- package/src/schema.ts +1 -9
- package/src/skill/hint.ts +2 -2
- package/src/types.ts +22 -14
- package/src/validate.ts +17 -17
- package/docs/install.md +0 -206
- package/src/builtins/install.ts +0 -106
- package/src/builtins/uninstall.ts +0 -80
- package/src/install/index.ts +0 -409
- package/src/install/install.test.ts +0 -317
|
@@ -32,7 +32,7 @@ const configSchema = {
|
|
|
32
32
|
export const program = {
|
|
33
33
|
key: createIdentity.key,
|
|
34
34
|
version: "1.0.0",
|
|
35
|
-
description:
|
|
35
|
+
description: createIdentity.desc,
|
|
36
36
|
appConfig: {
|
|
37
37
|
jsonSchema: APP_CONFIG_JSON_SCHEMA,
|
|
38
38
|
entries: configSchema,
|
|
@@ -50,8 +50,8 @@ export const program = {
|
|
|
50
50
|
mcpd: true,
|
|
51
51
|
claudePlugin: true,
|
|
52
52
|
},
|
|
53
|
-
|
|
54
|
-
// Defaults: agentIntegration picks skill vs MCP for
|
|
53
|
+
configure: {
|
|
54
|
+
// Defaults: agentIntegration picks skill vs MCP for sync; app config is opt-in in interactive configure.
|
|
55
55
|
},
|
|
56
56
|
commands: [echoCommand, statusCommand],
|
|
57
57
|
} satisfies CliProgram;
|
package/examples/nested.ts
CHANGED
package/index.d.ts
CHANGED
|
@@ -307,18 +307,23 @@ export interface CliAppConfig {
|
|
|
307
307
|
/** Per-key metadata; keys must match `jsonSchema.properties` when `jsonSchema` is set. */
|
|
308
308
|
entries: Record<string, CliAppConfigEntry>;
|
|
309
309
|
}
|
|
310
|
-
|
|
311
|
-
|
|
310
|
+
/** Opt-out for the `completion` built-in (default: enabled). */
|
|
311
|
+
export interface CliCompletionConfig {
|
|
312
|
+
/** When `false`, hide/disable `completion` (default: enabled). */
|
|
313
|
+
enabled?: boolean;
|
|
314
|
+
}
|
|
315
|
+
export interface CliConfigureConfig {
|
|
316
|
+
/** When `false`, hide/disable `configure` (default: enabled). */
|
|
312
317
|
enabled?: boolean;
|
|
313
318
|
/**
|
|
314
|
-
* Default agent integration for
|
|
315
|
-
* - `'mcp'` when `mcpServer.enabled` (default): MCP targets in
|
|
316
|
-
* - `'skill'` when MCP is off (default): skill targets in
|
|
317
|
-
* - `'both'`:
|
|
319
|
+
* Default agent integration for sync (`configure --sync`).
|
|
320
|
+
* - `'mcp'` when `mcpServer.enabled` (default): MCP targets in sync; paired skills excluded.
|
|
321
|
+
* - `'skill'` when MCP is off (default): skill targets in sync; paired MCP excluded.
|
|
322
|
+
* - `'both'`: sync MCP and skill for the same host when both are available.
|
|
318
323
|
*/
|
|
319
324
|
agentIntegration?: InstallAgentIntegration;
|
|
320
|
-
/** Per-artifact gates for
|
|
321
|
-
targets?:
|
|
325
|
+
/** Per-artifact gates for configure sync and interactive wizard. See {@link resolveEffectiveInstallTargets}. */
|
|
326
|
+
targets?: CliConfigureTargets;
|
|
322
327
|
}
|
|
323
328
|
/** Agent integration mode for install — MCP vs shell skill per host. */
|
|
324
329
|
export type InstallAgentIntegration = "mcp" | "skill" | "both";
|
|
@@ -326,15 +331,15 @@ export type InstallAgentIntegration = "mcp" | "skill" | "both";
|
|
|
326
331
|
export type InstallTargetSpec = boolean | {
|
|
327
332
|
/** When false, artifact is never installed (even with scoped CLI flags). Default true. */
|
|
328
333
|
enabled?: boolean;
|
|
329
|
-
/** When true, included in
|
|
334
|
+
/** When true, included in `configure --sync`. Default varies by key. */
|
|
330
335
|
includedInAll?: boolean;
|
|
331
336
|
};
|
|
332
337
|
export interface ResolvedInstallTarget {
|
|
333
338
|
enabled: boolean;
|
|
334
339
|
includedInAll: boolean;
|
|
335
340
|
}
|
|
336
|
-
/** Per-artifact gates for
|
|
337
|
-
export interface
|
|
341
|
+
/** Per-artifact gates for configure. See {@link resolveEffectiveInstallTargets}. */
|
|
342
|
+
export interface CliConfigureTargets {
|
|
338
343
|
/** App binary status only (Homebrew PATH); no self-install. */
|
|
339
344
|
app?: InstallTargetSpec;
|
|
340
345
|
/** ChatGPT desktop MCP. Default false. */
|
|
@@ -349,7 +354,7 @@ export interface CliInstallTargets {
|
|
|
349
354
|
codexMcp?: InstallTargetSpec;
|
|
350
355
|
/** Codex skill. Default false. */
|
|
351
356
|
codexSkill?: InstallTargetSpec;
|
|
352
|
-
/** App config: wizard
|
|
357
|
+
/** App config: interactive wizard step in `configure`. Default not in sync. */
|
|
353
358
|
configure?: InstallTargetSpec;
|
|
354
359
|
/** Cursor MCP. Default false. */
|
|
355
360
|
cursorMcp?: InstallTargetSpec;
|
|
@@ -447,8 +452,10 @@ export type CliProgram = CliNode & {
|
|
|
447
452
|
appConfig?: CliAppConfig;
|
|
448
453
|
/** When set with `enabled: true`, enables the `mcp` built-in subcommand. */
|
|
449
454
|
mcpServer?: CliMcpServerConfig;
|
|
450
|
-
/** Opt-out and defaults for `
|
|
451
|
-
|
|
455
|
+
/** Opt-out and defaults for `configure`. */
|
|
456
|
+
configure?: CliConfigureConfig;
|
|
457
|
+
/** Opt-out for shell completion generation (`completion bash|zsh|fish`). */
|
|
458
|
+
completion?: CliCompletionConfig;
|
|
452
459
|
/** When set with `enabled: true`, enables the `docs` built-in command group. */
|
|
453
460
|
docs?: CliDocsConfig;
|
|
454
461
|
};
|
|
@@ -466,9 +473,9 @@ export declare class CliSchemaValidationError extends Error {
|
|
|
466
473
|
}
|
|
467
474
|
/** Platform builtins derived from program config and runtime. */
|
|
468
475
|
export interface CliCapabilities {
|
|
469
|
-
completion:
|
|
476
|
+
completion: boolean;
|
|
470
477
|
mcp: boolean;
|
|
471
|
-
|
|
478
|
+
configure: boolean;
|
|
472
479
|
docs: boolean;
|
|
473
480
|
configCommands: boolean;
|
|
474
481
|
}
|
package/package.json
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import { describe, expect, test } from "bun:test";
|
|
2
|
+
import { resolveCapabilities } from "../capabilities.ts";
|
|
3
|
+
import { cliBuiltinDocsGroup } from "../docs/builtin.ts";
|
|
2
4
|
import { ParseKind, parse, postParseValidate } from "../parse.ts";
|
|
3
5
|
import type { CliProgram } from "../types.ts";
|
|
6
|
+
import { cliBuiltinConfigureCommand, configureBuiltinOptions } from "./configure.ts";
|
|
7
|
+
import { configureCommandDescription, configureSyncOptionDescription } from "./configure-copy.ts";
|
|
4
8
|
import { exportPresentationBuiltins } from "./export.ts";
|
|
5
9
|
import { completionBashScript, completionFishScript, completionZshScript } from "./index.ts";
|
|
6
|
-
import { cliBuiltinInstallCommand, installBuiltinOptions } from "./install.ts";
|
|
7
10
|
import { cliBuiltinMcpCommand } from "./mcp.ts";
|
|
8
11
|
import { cliParseRoot, cliPresentationRoot } from "./presentation.ts";
|
|
9
|
-
import { cliBuiltinUninstallCommand, uninstallBuiltinOptions } from "./uninstall.ts";
|
|
10
12
|
|
|
11
13
|
const fixture: CliProgram = {
|
|
12
14
|
key: "myapp",
|
|
@@ -22,54 +24,63 @@ const fixture: CliProgram = {
|
|
|
22
24
|
],
|
|
23
25
|
};
|
|
24
26
|
|
|
27
|
+
const noMcp: CliProgram = {
|
|
28
|
+
key: "skillonly",
|
|
29
|
+
version: "0.0.0",
|
|
30
|
+
description: "Skills only.",
|
|
31
|
+
commands: [{ key: "ping", description: "Ping.", handler: () => {} }],
|
|
32
|
+
};
|
|
33
|
+
|
|
25
34
|
describe("builtins help copy", () => {
|
|
26
|
-
test("
|
|
27
|
-
const
|
|
28
|
-
expect(
|
|
29
|
-
expect(
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
expect(names).toContain("
|
|
33
|
-
expect(names).
|
|
34
|
-
expect(names).
|
|
35
|
-
|
|
36
|
-
expect(names.indexOf("all")).toBeLessThan(names.indexOf("mcp"));
|
|
37
|
-
expect(names.indexOf("mcp")).toBeLessThan(names.indexOf("status"));
|
|
38
|
-
expect(names).not.toContain("uninstall");
|
|
39
|
-
const yesOpt = installBuiltinOptions(fixture).find((o) => o.name === "yes");
|
|
35
|
+
test("configure command includes Homebrew-oriented description", () => {
|
|
36
|
+
const configure = cliBuiltinConfigureCommand(fixture);
|
|
37
|
+
expect(configure.description).toContain("agent skills");
|
|
38
|
+
expect(configure.description).toContain("MCP config");
|
|
39
|
+
expect(configure.notes).toContain("brew install");
|
|
40
|
+
const names = configureBuiltinOptions(fixture).map((o) => o.name);
|
|
41
|
+
expect(names).toContain("sync");
|
|
42
|
+
expect(names).toContain("remove-all");
|
|
43
|
+
expect(names).toContain("status");
|
|
44
|
+
const yesOpt = configureBuiltinOptions(fixture).find((o) => o.name === "yes");
|
|
40
45
|
expect(yesOpt?.shortName).toBe("y");
|
|
41
46
|
});
|
|
42
47
|
|
|
43
|
-
test("
|
|
44
|
-
const
|
|
45
|
-
expect(
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
expect(
|
|
49
|
-
expect(
|
|
48
|
+
test("configure copy omits MCP when mcpServer unset", () => {
|
|
49
|
+
const caps = resolveCapabilities(noMcp);
|
|
50
|
+
expect(configureCommandDescription(noMcp, caps)).toBe(
|
|
51
|
+
"Set up agent skills for this app (binary via Homebrew).",
|
|
52
|
+
);
|
|
53
|
+
expect(configureCommandDescription(noMcp, caps)).not.toContain("MCP");
|
|
54
|
+
expect(configureSyncOptionDescription(noMcp, caps)).not.toContain("MCP");
|
|
55
|
+
const configure = cliBuiltinConfigureCommand(noMcp);
|
|
56
|
+
expect(configure.description).not.toContain("MCP");
|
|
50
57
|
});
|
|
51
58
|
|
|
52
|
-
test("
|
|
59
|
+
test("configure notes mention brew upgrade and interactive configure", () => {
|
|
60
|
+
const configure = cliBuiltinConfigureCommand(fixture);
|
|
61
|
+
expect(configure.notes).toContain("brew upgrade");
|
|
62
|
+
expect(configure.notes).toContain("configure --sync --yes");
|
|
63
|
+
expect(configure.notes).toContain(`${fixture.key} configure`);
|
|
64
|
+
|
|
65
|
+
const withConfig: CliProgram = {
|
|
66
|
+
...fixture,
|
|
67
|
+
appConfig: {
|
|
68
|
+
entries: { token: { description: "Token.", env: "TOKEN" } },
|
|
69
|
+
},
|
|
70
|
+
};
|
|
71
|
+
expect(configureBuiltinOptions(withConfig).map((o) => o.name)).toContain("remove-config");
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
test("configure -y parses as --yes", () => {
|
|
53
75
|
const root = cliParseRoot(fixture);
|
|
54
|
-
const pr = postParseValidate(root, parse(root, ["
|
|
76
|
+
const pr = postParseValidate(root, parse(root, ["configure", "-y", "--sync"]));
|
|
55
77
|
expect(pr.kind).toBe(ParseKind.Ok);
|
|
56
78
|
if (pr.kind === ParseKind.Ok) {
|
|
57
79
|
expect(pr.opts.yes).toBe("1");
|
|
80
|
+
expect(pr.opts.sync).toBe("1");
|
|
58
81
|
}
|
|
59
82
|
});
|
|
60
83
|
|
|
61
|
-
test("install omits --mcp option when mcpServer unset", () => {
|
|
62
|
-
const noMcp: CliProgram = { key: "x", version: "0.0.0", description: "x", handler: () => {} };
|
|
63
|
-
const names = installBuiltinOptions(noMcp).map((o) => o.name);
|
|
64
|
-
expect(names).not.toContain("mcp");
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
test("install notes mention brew upgrade", () => {
|
|
68
|
-
const install = cliBuiltinInstallCommand(fixture);
|
|
69
|
-
expect(install.notes).toContain("brew upgrade");
|
|
70
|
-
expect(install.notes).toContain("install --configure");
|
|
71
|
-
});
|
|
72
|
-
|
|
73
84
|
test("mcp builtin description is user-facing", () => {
|
|
74
85
|
const withDocs: CliProgram = {
|
|
75
86
|
...fixture,
|
|
@@ -77,39 +88,31 @@ describe("builtins help copy", () => {
|
|
|
77
88
|
};
|
|
78
89
|
const mcp = cliBuiltinMcpCommand(withDocs);
|
|
79
90
|
expect(mcp.description).toContain("MCP server");
|
|
80
|
-
expect(mcp.notes).toContain("
|
|
91
|
+
expect(mcp.notes).toContain("configure");
|
|
81
92
|
expect(mcp.notes).toContain("docs mcp");
|
|
82
93
|
});
|
|
83
94
|
});
|
|
84
95
|
|
|
85
96
|
describe("presentation root", () => {
|
|
86
|
-
test("includes mcp and
|
|
97
|
+
test("includes mcp and configure when enabled", () => {
|
|
87
98
|
const root = cliPresentationRoot(fixture);
|
|
88
99
|
const keys = root.commands?.map((c) => c.key) ?? [];
|
|
89
100
|
expect(keys).toContain("mcp");
|
|
90
|
-
expect(keys).toContain("
|
|
91
|
-
expect(keys).toContain("
|
|
101
|
+
expect(keys).toContain("configure");
|
|
102
|
+
expect(keys).not.toContain("completion");
|
|
103
|
+
expect(keys).not.toContain("install");
|
|
92
104
|
});
|
|
93
105
|
|
|
94
|
-
test("omits
|
|
95
|
-
const disabled: CliProgram = { ...fixture,
|
|
106
|
+
test("omits configure when configure.enabled is false", () => {
|
|
107
|
+
const disabled: CliProgram = { ...fixture, configure: { enabled: false } };
|
|
96
108
|
const root = cliPresentationRoot(disabled);
|
|
97
|
-
expect(root.commands?.map((c) => c.key)).not.toContain("
|
|
109
|
+
expect(root.commands?.map((c) => c.key)).not.toContain("configure");
|
|
98
110
|
});
|
|
111
|
+
|
|
99
112
|
test("includes version builtin", () => {
|
|
100
113
|
const root = cliPresentationRoot(fixture);
|
|
101
114
|
expect(root.commands?.map((c) => c.key)).toContain("version");
|
|
102
115
|
});
|
|
103
|
-
|
|
104
|
-
test("root notes include agent hint when docs enabled", () => {
|
|
105
|
-
const withDocs: CliProgram = {
|
|
106
|
-
...fixture,
|
|
107
|
-
docs: { enabled: true, topics: { readme: { text: "# r\n" } } },
|
|
108
|
-
};
|
|
109
|
-
const root = cliPresentationRoot(withDocs);
|
|
110
|
-
expect(root.notes).toContain("For AI agents: `myapp docs skill`.");
|
|
111
|
-
expect(root.notes).not.toContain("install --skill");
|
|
112
|
-
});
|
|
113
116
|
});
|
|
114
117
|
|
|
115
118
|
describe("completion emitters", () => {
|
|
@@ -118,14 +121,14 @@ describe("completion emitters", () => {
|
|
|
118
121
|
const fish = completionFishScript(schema);
|
|
119
122
|
expect(fish).toContain("complete -c myapp");
|
|
120
123
|
expect(fish).toContain("hello");
|
|
121
|
-
expect(fish).toContain("
|
|
124
|
+
expect(fish).toContain("configure");
|
|
122
125
|
});
|
|
123
126
|
|
|
124
|
-
test("bash script includes
|
|
127
|
+
test("bash script includes configure flags", () => {
|
|
125
128
|
const schema = cliPresentationRoot(fixture);
|
|
126
129
|
const bash = completionBashScript(schema);
|
|
127
|
-
expect(bash).toContain("
|
|
128
|
-
expect(bash).toContain("
|
|
130
|
+
expect(bash).toContain("hello");
|
|
131
|
+
expect(bash).toContain("--sync");
|
|
129
132
|
});
|
|
130
133
|
|
|
131
134
|
test("zsh script registers compdef", () => {
|
|
@@ -153,11 +156,29 @@ describe("schema export builtins", () => {
|
|
|
153
156
|
};
|
|
154
157
|
const builtins = exportPresentationBuiltins(withConfig);
|
|
155
158
|
expect(builtins.map((b) => b.key)).toContain("config");
|
|
159
|
+
expect(builtins.map((b) => b.key)).toContain("configure");
|
|
156
160
|
});
|
|
157
161
|
|
|
158
|
-
test("exportPresentationBuiltins
|
|
162
|
+
test("exportPresentationBuiltins omits hidden completion", () => {
|
|
159
163
|
const builtins = exportPresentationBuiltins(fixture);
|
|
160
|
-
|
|
161
|
-
|
|
164
|
+
expect(builtins.map((b) => b.key)).not.toContain("completion");
|
|
165
|
+
});
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
describe("docs skill topic copy", () => {
|
|
169
|
+
test("mentions configure when configure is enabled", () => {
|
|
170
|
+
const withDocs: CliProgram = {
|
|
171
|
+
...noMcp,
|
|
172
|
+
docs: { enabled: true, topics: { readme: { text: "# r\n" } } },
|
|
173
|
+
};
|
|
174
|
+
const skill = cliBuiltinDocsGroup(withDocs).commands.find((c) => c.key === "skill");
|
|
175
|
+
expect(skill?.description).toContain("configure");
|
|
176
|
+
|
|
177
|
+
const configureOff: CliProgram = {
|
|
178
|
+
...withDocs,
|
|
179
|
+
configure: { enabled: false },
|
|
180
|
+
};
|
|
181
|
+
const skillOff = cliBuiltinDocsGroup(configureOff).commands.find((c) => c.key === "skill");
|
|
182
|
+
expect(skillOff?.description).not.toContain("configure");
|
|
162
183
|
});
|
|
163
184
|
});
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { resolveCapabilities } from "../capabilities.ts";
|
|
2
1
|
import type { CliProgram } from "../types.ts";
|
|
3
2
|
|
|
4
3
|
/**
|
|
@@ -8,6 +7,7 @@ export function cliBuiltinCompletionGroup(program: CliProgram): import("../types
|
|
|
8
7
|
const appName = program.key;
|
|
9
8
|
const router: import("../types.ts").CliRouter = {
|
|
10
9
|
key: "completion",
|
|
10
|
+
hidden: true,
|
|
11
11
|
description: "Generate the autocompletion script for shells.",
|
|
12
12
|
commands: [
|
|
13
13
|
{
|
|
@@ -44,10 +44,8 @@ export function cliBuiltinCompletionGroup(program: CliProgram): import("../types
|
|
|
44
44
|
},
|
|
45
45
|
],
|
|
46
46
|
};
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
"See: https://docs.brew.sh/Shell-Completion";
|
|
51
|
-
}
|
|
47
|
+
router.notes =
|
|
48
|
+
"Completions are installed by Homebrew during formula install.\n\n" +
|
|
49
|
+
"See: https://docs.brew.sh/Shell-Completion";
|
|
52
50
|
return router;
|
|
53
51
|
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/** Capability-aware labels for configure builtin and docs copy. */
|
|
2
|
+
|
|
3
|
+
import type { CliCapabilities } from "../capabilities.ts";
|
|
4
|
+
import type { CliProgram } from "../types.ts";
|
|
5
|
+
|
|
6
|
+
type Kind = "skills" | "mcp" | "config";
|
|
7
|
+
|
|
8
|
+
const LABEL: Record<Kind, { prose: string; short: string }> = {
|
|
9
|
+
skills: { prose: "agent skills", short: "skills" },
|
|
10
|
+
mcp: { prose: "MCP config", short: "MCP" },
|
|
11
|
+
config: { prose: "app config", short: "config" },
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
function enabledKinds(program: CliProgram, caps: CliCapabilities): Kind[] {
|
|
15
|
+
const kinds: Kind[] = ["skills"];
|
|
16
|
+
if (caps.mcp) kinds.push("mcp");
|
|
17
|
+
if (program.appConfig) kinds.push("config");
|
|
18
|
+
return kinds;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function joinEnglish(items: string[]): string {
|
|
22
|
+
if (items.length === 0) return "agent artifacts";
|
|
23
|
+
if (items.length === 1) return items[0]!;
|
|
24
|
+
if (items.length === 2) return `${items[0]} and ${items[1]}`;
|
|
25
|
+
return `${items.slice(0, -1).join(", ")}, and ${items[items.length - 1]}`;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function prose(program: CliProgram, caps: CliCapabilities): string {
|
|
29
|
+
return joinEnglish(enabledKinds(program, caps).map((k) => LABEL[k].prose));
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function short(program: CliProgram, caps: CliCapabilities): string {
|
|
33
|
+
return joinEnglish(enabledKinds(program, caps).map((k) => LABEL[k].short));
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function configureCommandDescription(program: CliProgram, caps: CliCapabilities): string {
|
|
37
|
+
return `Set up ${prose(program, caps)} for this app (binary via Homebrew).`;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function configureSyncOptionDescription(program: CliProgram, caps: CliCapabilities): string {
|
|
41
|
+
return `Refresh installed ${short(program, caps)}. Used by Homebrew post_install.`;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function docsSkillTopicDescription(program: CliProgram, caps: CliCapabilities): string {
|
|
45
|
+
if (caps.configure) {
|
|
46
|
+
return "Print a reference agent SKILL; run `configure` to install an optimized copy.";
|
|
47
|
+
}
|
|
48
|
+
return "Print a reference agent SKILL for AI agents.";
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export function configureCommandNotes(program: CliProgram, caps: CliCapabilities): string {
|
|
52
|
+
const app = program.key;
|
|
53
|
+
const lines = [
|
|
54
|
+
"Install the binary via Homebrew (tap-from-repo), then set up agent artifacts:",
|
|
55
|
+
` brew tap <org>/<repo>`,
|
|
56
|
+
` brew install <tap>/${app}`,
|
|
57
|
+
"",
|
|
58
|
+
"Homebrew post_install runs:",
|
|
59
|
+
` ${app} configure --sync --yes`,
|
|
60
|
+
"",
|
|
61
|
+
"Interactive setup (per target):",
|
|
62
|
+
` ${app} configure`,
|
|
63
|
+
"",
|
|
64
|
+
"Upgrade:",
|
|
65
|
+
` brew upgrade ${app}`,
|
|
66
|
+
"",
|
|
67
|
+
"Shell completions are installed by Homebrew during brew install.",
|
|
68
|
+
"See: https://docs.brew.sh/Shell-Completion",
|
|
69
|
+
"",
|
|
70
|
+
"See what is installed:",
|
|
71
|
+
` ${app} configure --status`,
|
|
72
|
+
"",
|
|
73
|
+
"Remove agent artifacts before brew uninstall:",
|
|
74
|
+
` ${app} configure --remove-all --yes`,
|
|
75
|
+
` brew uninstall <tap>/${app}`,
|
|
76
|
+
"",
|
|
77
|
+
];
|
|
78
|
+
if (program.appConfig) {
|
|
79
|
+
lines.push("Remove app config only:", ` ${app} configure --remove-config --yes`, "");
|
|
80
|
+
}
|
|
81
|
+
lines.push(
|
|
82
|
+
"Use --dry to preview changes without writing files.",
|
|
83
|
+
"Use --json for machine-readable output.",
|
|
84
|
+
);
|
|
85
|
+
return lines.join("\n");
|
|
86
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { resolveCapabilities } from "../capabilities.ts";
|
|
2
|
+
import { type CliLeaf, type CliOption, CliOptionKind, type CliProgram } from "../types.ts";
|
|
3
|
+
import {
|
|
4
|
+
configureCommandDescription,
|
|
5
|
+
configureCommandNotes,
|
|
6
|
+
configureSyncOptionDescription,
|
|
7
|
+
} from "./configure-copy.ts";
|
|
8
|
+
|
|
9
|
+
/** Configure command options. */
|
|
10
|
+
export function configureBuiltinOptions(root: CliProgram): CliOption[] {
|
|
11
|
+
const caps = resolveCapabilities(root);
|
|
12
|
+
const opts: CliOption[] = [
|
|
13
|
+
{
|
|
14
|
+
name: "sync",
|
|
15
|
+
description: configureSyncOptionDescription(root, caps),
|
|
16
|
+
kind: CliOptionKind.Presence,
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
name: "remove-all",
|
|
20
|
+
description: "Remove all detected agent artifacts (skills and MCP).",
|
|
21
|
+
kind: CliOptionKind.Presence,
|
|
22
|
+
},
|
|
23
|
+
];
|
|
24
|
+
|
|
25
|
+
if (root.appConfig) {
|
|
26
|
+
opts.push({
|
|
27
|
+
name: "remove-config",
|
|
28
|
+
description: "Remove the app config file only.",
|
|
29
|
+
kind: CliOptionKind.Presence,
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
opts.push(
|
|
34
|
+
{
|
|
35
|
+
name: "status",
|
|
36
|
+
description: "Print what is currently installed (read-only).",
|
|
37
|
+
kind: CliOptionKind.Presence,
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
name: "yes",
|
|
41
|
+
description: "Skip confirmation (required for --sync, --remove-all, --remove-config).",
|
|
42
|
+
kind: CliOptionKind.Presence,
|
|
43
|
+
shortName: "y",
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
name: "dry",
|
|
47
|
+
description: "Show what would change without writing files.",
|
|
48
|
+
kind: CliOptionKind.Presence,
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
name: "json",
|
|
52
|
+
description: "Print changed paths or status JSON on stdout.",
|
|
53
|
+
kind: CliOptionKind.Presence,
|
|
54
|
+
},
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
return opts;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** Builds the `configure` built-in command. */
|
|
61
|
+
export function cliBuiltinConfigureCommand(root: CliProgram): CliLeaf {
|
|
62
|
+
const caps = resolveCapabilities(root);
|
|
63
|
+
return {
|
|
64
|
+
key: "configure",
|
|
65
|
+
description: configureCommandDescription(root, caps),
|
|
66
|
+
options: configureBuiltinOptions(root),
|
|
67
|
+
notes: configureCommandNotes(root, caps),
|
|
68
|
+
handler: () => {},
|
|
69
|
+
};
|
|
70
|
+
}
|
package/src/builtins/dispatch.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { capabilityDeniedMessage, resolveCapabilities } from "../capabilities.ts";
|
|
2
2
|
import { Cli } from "../cli.ts";
|
|
3
|
+
import { cliConfigure } from "../configure/index.ts";
|
|
3
4
|
import { cliBuiltinDocsGroupIfEnabled } from "../docs/builtin.ts";
|
|
4
|
-
import { cliInstall, cliUninstall } from "../install/index.ts";
|
|
5
5
|
import { runMcpBundle } from "../mcp/bundle.ts";
|
|
6
6
|
import type { ParseResult } from "../parse.ts";
|
|
7
7
|
import { ParseKind } from "../parse.ts";
|
|
@@ -12,10 +12,9 @@ import { completionFishScript } from "./completion-fish.ts";
|
|
|
12
12
|
import { cliBuiltinCompletionGroup as completionGroup } from "./completion-group.ts";
|
|
13
13
|
import { completionZshScript } from "./completion-zsh.ts";
|
|
14
14
|
import { cliBuiltinConfigGroupIfEnabled } from "./config.ts";
|
|
15
|
-
import {
|
|
15
|
+
import { cliBuiltinConfigureCommand } from "./configure.ts";
|
|
16
16
|
import { cliBuiltinMcpCommand } from "./mcp.ts";
|
|
17
17
|
import { cliPresentationRoot } from "./presentation.ts";
|
|
18
|
-
import { cliBuiltinUninstallCommand } from "./uninstall.ts";
|
|
19
18
|
import { cliBuiltinVersionCommand } from "./version.ts";
|
|
20
19
|
|
|
21
20
|
export interface DispatchBuiltinOpts {
|
|
@@ -45,6 +44,10 @@ export async function dispatchBuiltin(
|
|
|
45
44
|
const caps = resolveCapabilities(program);
|
|
46
45
|
|
|
47
46
|
if (pr.path[0] === "completion") {
|
|
47
|
+
if (!caps.completion) {
|
|
48
|
+
process.stderr.write(capabilityDeniedMessage("completion"));
|
|
49
|
+
process.exit(1);
|
|
50
|
+
}
|
|
48
51
|
const schemaForCompletion = completionSchema(program, opts);
|
|
49
52
|
if (pr.path[1] === "bash") {
|
|
50
53
|
process.stdout.write(completionBashScript(schemaForCompletion));
|
|
@@ -93,28 +96,16 @@ export async function dispatchBuiltin(
|
|
|
93
96
|
process.exit(1);
|
|
94
97
|
}
|
|
95
98
|
|
|
96
|
-
if (pr.path[0] === "
|
|
97
|
-
if (!caps.
|
|
98
|
-
process.stderr.write(capabilityDeniedMessage("
|
|
99
|
-
process.exit(1);
|
|
100
|
-
}
|
|
101
|
-
if (pr.path.length !== 1) {
|
|
102
|
-
process.stderr.write(`Unknown subcommand: install ${pr.path.slice(1).join(" ")}\n`);
|
|
103
|
-
process.exit(1);
|
|
104
|
-
}
|
|
105
|
-
await cliInstall(program, pr.opts);
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
if (pr.path[0] === "uninstall") {
|
|
109
|
-
if (!caps.install) {
|
|
110
|
-
process.stderr.write(capabilityDeniedMessage("install"));
|
|
99
|
+
if (pr.path[0] === "configure") {
|
|
100
|
+
if (!caps.configure) {
|
|
101
|
+
process.stderr.write(capabilityDeniedMessage("configure"));
|
|
111
102
|
process.exit(1);
|
|
112
103
|
}
|
|
113
104
|
if (pr.path.length !== 1) {
|
|
114
|
-
process.stderr.write(`Unknown subcommand:
|
|
105
|
+
process.stderr.write(`Unknown subcommand: configure ${pr.path.slice(1).join(" ")}\n`);
|
|
115
106
|
process.exit(1);
|
|
116
107
|
}
|
|
117
|
-
await
|
|
108
|
+
await cliConfigure(program, pr.opts);
|
|
118
109
|
}
|
|
119
110
|
}
|
|
120
111
|
|
|
@@ -141,23 +132,12 @@ export function builtinInterceptRoot(
|
|
|
141
132
|
};
|
|
142
133
|
}
|
|
143
134
|
|
|
144
|
-
if (first === "
|
|
145
|
-
return {
|
|
146
|
-
parseRoot: {
|
|
147
|
-
key: program.key,
|
|
148
|
-
description: program.description,
|
|
149
|
-
commands: [cliBuiltinInstallCommand(program)],
|
|
150
|
-
},
|
|
151
|
-
isLeafCompletionIntercept: false,
|
|
152
|
-
};
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
if (first === "uninstall" && caps.install) {
|
|
135
|
+
if (first === "configure" && caps.configure) {
|
|
156
136
|
return {
|
|
157
137
|
parseRoot: {
|
|
158
138
|
key: program.key,
|
|
159
139
|
description: program.description,
|
|
160
|
-
commands: [
|
|
140
|
+
commands: [cliBuiltinConfigureCommand(program)],
|
|
161
141
|
},
|
|
162
142
|
isLeafCompletionIntercept: false,
|
|
163
143
|
};
|
package/src/builtins/index.ts
CHANGED
|
@@ -2,9 +2,9 @@ export { completionBashScript } from "./completion-bash.ts";
|
|
|
2
2
|
export { completionFishScript } from "./completion-fish.ts";
|
|
3
3
|
export { cliBuiltinCompletionGroup } from "./completion-group.ts";
|
|
4
4
|
export { completionZshScript } from "./completion-zsh.ts";
|
|
5
|
+
export { cliBuiltinConfigureCommand, configureBuiltinOptions } from "./configure.ts";
|
|
5
6
|
export { builtinInterceptRoot, dispatchBuiltin } from "./dispatch.ts";
|
|
6
7
|
export { type CliSchemaExport, exportPresentationBuiltins } from "./export.ts";
|
|
7
|
-
export { cliBuiltinInstallCommand, installBuiltinOptions } from "./install.ts";
|
|
8
8
|
export { cliBuiltinMcpCommand } from "./mcp.ts";
|
|
9
9
|
export {
|
|
10
10
|
cliParseRoot,
|
package/src/builtins/mcp.ts
CHANGED
|
@@ -12,8 +12,8 @@ export function cliBuiltinMcpCommand(program: CliProgram): CliRouter {
|
|
|
12
12
|
" args: mcp",
|
|
13
13
|
"",
|
|
14
14
|
];
|
|
15
|
-
if (caps.
|
|
16
|
-
lines.push("Or:", "", " {argsbarg:program}
|
|
15
|
+
if (caps.configure) {
|
|
16
|
+
lines.push("Or:", "", " {argsbarg:program} configure", "");
|
|
17
17
|
}
|
|
18
18
|
if (docsEnabled(program)) {
|
|
19
19
|
lines.push("Full setup guide: {argsbarg:program} docs mcp");
|