argsbarg 4.1.1 → 5.0.2
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 +34 -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 +12 -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 +3 -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 +105 -61
- package/src/builtins/completion-group.ts +4 -6
- package/src/builtins/config.test.ts +8 -0
- 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 +21 -3
- package/src/cli-tool/create.test.ts +36 -1
- package/src/cli-tool/create.ts +26 -4
- package/src/cli-tool/full-example-capabilities.test.ts +10 -2
- package/src/cli-tool/main.ts +0 -0
- 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/context.test.ts +8 -0
- package/src/config/file.test.ts +13 -1
- package/src/config/resolve.test.ts +18 -0
- package/src/config/resolve.ts +2 -2
- package/src/config/validate.test.ts +11 -0
- package/src/config.integration.test.ts +5 -0
- package/src/configure/configure.test.ts +170 -0
- package/src/configure/index.ts +298 -0
- package/src/configure/prompt.ts +47 -0
- package/src/docs/api-guide.test.ts +10 -0
- package/src/docs/builtin.ts +3 -5
- package/src/docs/docs.test.ts +32 -5
- package/src/docs/mcp-guide.ts +4 -4
- package/src/docs/mcp-resources.test.ts +10 -0
- package/src/formats.test.ts +9 -0
- package/src/headless.test.ts +10 -0
- package/src/hidden-mcpb.test.ts +22 -0
- package/src/index.ts +2 -2
- package/src/install/binary-placement.test.ts +14 -0
- package/src/install/gh-release-update.test.ts +9 -0
- package/src/install/install-validate.test.ts +15 -5
- package/src/install/mcp-codex.test.ts +7 -0
- package/src/install/mcp-openclaw.test.ts +6 -0
- package/src/install/mcp-opencode.test.ts +10 -0
- package/src/install/opts.ts +17 -0
- package/src/install/status.test.ts +9 -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 +23 -4
- package/src/invoke.test.ts +15 -1
- package/src/mcp/claude.test.ts +10 -0
- package/src/mcp/env.test.ts +12 -0
- package/src/mcp/tools.ts +1 -1
- package/src/mcp/zip.test.ts +5 -0
- package/src/mcp.integration.test.ts +43 -4
- package/src/parse.test.ts +82 -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
|
@@ -11,12 +11,13 @@ export const formulaInstallRuby = `def install
|
|
|
11
11
|
end`;
|
|
12
12
|
|
|
13
13
|
export const formulaPostInstallRuby = `def post_install
|
|
14
|
-
system bin/"${key}", "
|
|
14
|
+
system bin/"${key}", "configure", "--sync", "--yes"
|
|
15
15
|
end`;
|
|
16
16
|
|
|
17
17
|
export const formulaCaveatsRuby = `def caveats
|
|
18
18
|
<<~EOS
|
|
19
|
-
Run \`${key}
|
|
19
|
+
Run \`${key} configure\` to set up agent artifacts and app config (interactive).
|
|
20
|
+
Restart MCP chat apps (Cursor, Claude Desktop, etc.) after install or upgrade so they load the updated server.
|
|
20
21
|
EOS
|
|
21
22
|
end`;
|
|
22
23
|
|
|
@@ -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,18 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Tests for builtins/builtins module behavior.
|
|
3
|
+
*/
|
|
4
|
+
|
|
1
5
|
import { describe, expect, test } from "bun:test";
|
|
6
|
+
import { resolveCapabilities } from "../capabilities.ts";
|
|
7
|
+
import { cliBuiltinDocsGroup } from "../docs/builtin.ts";
|
|
2
8
|
import { ParseKind, parse, postParseValidate } from "../parse.ts";
|
|
3
9
|
import type { CliProgram } from "../types.ts";
|
|
10
|
+
import { cliBuiltinConfigureCommand, configureBuiltinOptions } from "./configure.ts";
|
|
11
|
+
import { configureCommandDescription, configureSyncOptionDescription } from "./configure-copy.ts";
|
|
4
12
|
import { exportPresentationBuiltins } from "./export.ts";
|
|
5
13
|
import { completionBashScript, completionFishScript, completionZshScript } from "./index.ts";
|
|
6
|
-
import { cliBuiltinInstallCommand, installBuiltinOptions } from "./install.ts";
|
|
7
14
|
import { cliBuiltinMcpCommand } from "./mcp.ts";
|
|
8
15
|
import { cliParseRoot, cliPresentationRoot } from "./presentation.ts";
|
|
9
|
-
import { cliBuiltinUninstallCommand, uninstallBuiltinOptions } from "./uninstall.ts";
|
|
10
16
|
|
|
11
17
|
const fixture: CliProgram = {
|
|
12
18
|
key: "myapp",
|
|
@@ -22,54 +28,69 @@ const fixture: CliProgram = {
|
|
|
22
28
|
],
|
|
23
29
|
};
|
|
24
30
|
|
|
31
|
+
const noMcp: CliProgram = {
|
|
32
|
+
key: "skillonly",
|
|
33
|
+
version: "0.0.0",
|
|
34
|
+
description: "Skills only.",
|
|
35
|
+
commands: [{ key: "ping", description: "Ping.", handler: () => {} }],
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
/** Tests for builtins help copy. */
|
|
25
39
|
describe("builtins help copy", () => {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
expect(
|
|
30
|
-
|
|
31
|
-
expect(
|
|
32
|
-
|
|
33
|
-
expect(names).
|
|
34
|
-
expect(names).
|
|
35
|
-
expect(names).
|
|
36
|
-
|
|
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");
|
|
40
|
+
/** Configure command includes Homebrew-oriented description. */
|
|
41
|
+
test("configure command includes Homebrew-oriented description", () => {
|
|
42
|
+
const configure = cliBuiltinConfigureCommand(fixture);
|
|
43
|
+
expect(configure.description).toContain("agent skills");
|
|
44
|
+
expect(configure.description).toContain("MCP config");
|
|
45
|
+
expect(configure.notes).toContain("brew install");
|
|
46
|
+
const names = configureBuiltinOptions(fixture).map((o) => o.name);
|
|
47
|
+
expect(names).toContain("sync");
|
|
48
|
+
expect(names).toContain("remove-all");
|
|
49
|
+
expect(names).toContain("status");
|
|
50
|
+
const yesOpt = configureBuiltinOptions(fixture).find((o) => o.name === "yes");
|
|
40
51
|
expect(yesOpt?.shortName).toBe("y");
|
|
41
52
|
});
|
|
42
53
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
expect(
|
|
54
|
+
/** Configure copy omits MCP when mcpServer unset. */
|
|
55
|
+
test("configure copy omits MCP when mcpServer unset", () => {
|
|
56
|
+
const caps = resolveCapabilities(noMcp);
|
|
57
|
+
expect(configureCommandDescription(noMcp, caps)).toBe(
|
|
58
|
+
"Set up agent skills for this app (binary via Homebrew).",
|
|
59
|
+
);
|
|
60
|
+
expect(configureCommandDescription(noMcp, caps)).not.toContain("MCP");
|
|
61
|
+
expect(configureSyncOptionDescription(noMcp, caps)).not.toContain("MCP");
|
|
62
|
+
const configure = cliBuiltinConfigureCommand(noMcp);
|
|
63
|
+
expect(configure.description).not.toContain("MCP");
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
/** Configure notes mention brew upgrade and interactive configure. */
|
|
67
|
+
test("configure notes mention brew upgrade and interactive configure", () => {
|
|
68
|
+
const configure = cliBuiltinConfigureCommand(fixture);
|
|
69
|
+
expect(configure.notes).toContain("brew upgrade");
|
|
70
|
+
expect(configure.notes).toContain("configure --sync --yes");
|
|
71
|
+
expect(configure.notes).toContain(`${fixture.key} configure`);
|
|
72
|
+
|
|
73
|
+
const withConfig: CliProgram = {
|
|
74
|
+
...fixture,
|
|
75
|
+
appConfig: {
|
|
76
|
+
entries: { token: { description: "Token.", env: "TOKEN" } },
|
|
77
|
+
},
|
|
78
|
+
};
|
|
79
|
+
expect(configureBuiltinOptions(withConfig).map((o) => o.name)).toContain("remove-config");
|
|
50
80
|
});
|
|
51
81
|
|
|
52
|
-
|
|
82
|
+
/** Configure -y parses as --yes. */
|
|
83
|
+
test("configure -y parses as --yes", () => {
|
|
53
84
|
const root = cliParseRoot(fixture);
|
|
54
|
-
const pr = postParseValidate(root, parse(root, ["
|
|
85
|
+
const pr = postParseValidate(root, parse(root, ["configure", "-y", "--sync"]));
|
|
55
86
|
expect(pr.kind).toBe(ParseKind.Ok);
|
|
56
87
|
if (pr.kind === ParseKind.Ok) {
|
|
57
88
|
expect(pr.opts.yes).toBe("1");
|
|
89
|
+
expect(pr.opts.sync).toBe("1");
|
|
58
90
|
}
|
|
59
91
|
});
|
|
60
92
|
|
|
61
|
-
|
|
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
|
-
|
|
93
|
+
/** Mcp builtin description is user-facing. */
|
|
73
94
|
test("mcp builtin description is user-facing", () => {
|
|
74
95
|
const withDocs: CliProgram = {
|
|
75
96
|
...fixture,
|
|
@@ -77,57 +98,57 @@ describe("builtins help copy", () => {
|
|
|
77
98
|
};
|
|
78
99
|
const mcp = cliBuiltinMcpCommand(withDocs);
|
|
79
100
|
expect(mcp.description).toContain("MCP server");
|
|
80
|
-
expect(mcp.notes).toContain("
|
|
101
|
+
expect(mcp.notes).toContain("configure");
|
|
81
102
|
expect(mcp.notes).toContain("docs mcp");
|
|
82
103
|
});
|
|
83
104
|
});
|
|
84
105
|
|
|
106
|
+
/** Tests for presentation root. */
|
|
85
107
|
describe("presentation root", () => {
|
|
86
|
-
|
|
108
|
+
/** Includes mcp and configure when enabled. */
|
|
109
|
+
test("includes mcp and configure when enabled", () => {
|
|
87
110
|
const root = cliPresentationRoot(fixture);
|
|
88
111
|
const keys = root.commands?.map((c) => c.key) ?? [];
|
|
89
112
|
expect(keys).toContain("mcp");
|
|
90
|
-
expect(keys).toContain("
|
|
91
|
-
expect(keys).toContain("
|
|
113
|
+
expect(keys).toContain("configure");
|
|
114
|
+
expect(keys).not.toContain("completion");
|
|
115
|
+
expect(keys).not.toContain("install");
|
|
92
116
|
});
|
|
93
117
|
|
|
94
|
-
|
|
95
|
-
|
|
118
|
+
/** Omits configure when configure.enabled is false. */
|
|
119
|
+
test("omits configure when configure.enabled is false", () => {
|
|
120
|
+
const disabled: CliProgram = { ...fixture, configure: { enabled: false } };
|
|
96
121
|
const root = cliPresentationRoot(disabled);
|
|
97
|
-
expect(root.commands?.map((c) => c.key)).not.toContain("
|
|
122
|
+
expect(root.commands?.map((c) => c.key)).not.toContain("configure");
|
|
98
123
|
});
|
|
124
|
+
|
|
125
|
+
/** Includes version builtin. */
|
|
99
126
|
test("includes version builtin", () => {
|
|
100
127
|
const root = cliPresentationRoot(fixture);
|
|
101
128
|
expect(root.commands?.map((c) => c.key)).toContain("version");
|
|
102
129
|
});
|
|
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
130
|
});
|
|
114
131
|
|
|
132
|
+
/** Tests for completion emitters. */
|
|
115
133
|
describe("completion emitters", () => {
|
|
134
|
+
/** Tests that fish script references app key and subcommands. */
|
|
116
135
|
test("fish script references app key and subcommands", () => {
|
|
117
136
|
const schema = cliPresentationRoot(fixture);
|
|
118
137
|
const fish = completionFishScript(schema);
|
|
119
138
|
expect(fish).toContain("complete -c myapp");
|
|
120
139
|
expect(fish).toContain("hello");
|
|
121
|
-
expect(fish).toContain("
|
|
140
|
+
expect(fish).toContain("configure");
|
|
122
141
|
});
|
|
123
142
|
|
|
124
|
-
|
|
143
|
+
/** Tests that bash script includes configure flags. */
|
|
144
|
+
test("bash script includes configure flags", () => {
|
|
125
145
|
const schema = cliPresentationRoot(fixture);
|
|
126
146
|
const bash = completionBashScript(schema);
|
|
127
|
-
expect(bash).toContain("
|
|
128
|
-
expect(bash).toContain("
|
|
147
|
+
expect(bash).toContain("hello");
|
|
148
|
+
expect(bash).toContain("--sync");
|
|
129
149
|
});
|
|
130
150
|
|
|
151
|
+
/** Tests that zsh script registers compdef. */
|
|
131
152
|
test("zsh script registers compdef", () => {
|
|
132
153
|
const schema = cliPresentationRoot({
|
|
133
154
|
key: "zapp",
|
|
@@ -141,7 +162,9 @@ describe("completion emitters", () => {
|
|
|
141
162
|
});
|
|
142
163
|
});
|
|
143
164
|
|
|
165
|
+
/** Tests for schema export builtins. */
|
|
144
166
|
describe("schema export builtins", () => {
|
|
167
|
+
/** ExportPresentationBuiltins includes config when appConfig set. */
|
|
145
168
|
test("exportPresentationBuiltins includes config when appConfig set", () => {
|
|
146
169
|
const withConfig: CliProgram = {
|
|
147
170
|
...fixture,
|
|
@@ -153,11 +176,32 @@ describe("schema export builtins", () => {
|
|
|
153
176
|
};
|
|
154
177
|
const builtins = exportPresentationBuiltins(withConfig);
|
|
155
178
|
expect(builtins.map((b) => b.key)).toContain("config");
|
|
179
|
+
expect(builtins.map((b) => b.key)).toContain("configure");
|
|
156
180
|
});
|
|
157
181
|
|
|
158
|
-
|
|
182
|
+
/** ExportPresentationBuiltins omits hidden completion. */
|
|
183
|
+
test("exportPresentationBuiltins omits hidden completion", () => {
|
|
159
184
|
const builtins = exportPresentationBuiltins(fixture);
|
|
160
|
-
|
|
161
|
-
|
|
185
|
+
expect(builtins.map((b) => b.key)).not.toContain("completion");
|
|
186
|
+
});
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
/** Tests for docs skill topic copy. */
|
|
190
|
+
describe("docs skill topic copy", () => {
|
|
191
|
+
/** Tests that mentions configure when configure is enabled. */
|
|
192
|
+
test("mentions configure when configure is enabled", () => {
|
|
193
|
+
const withDocs: CliProgram = {
|
|
194
|
+
...noMcp,
|
|
195
|
+
docs: { enabled: true, topics: { readme: { text: "# r\n" } } },
|
|
196
|
+
};
|
|
197
|
+
const skill = cliBuiltinDocsGroup(withDocs).commands.find((c) => c.key === "skill");
|
|
198
|
+
expect(skill?.description).toContain("configure");
|
|
199
|
+
|
|
200
|
+
const configureOff: CliProgram = {
|
|
201
|
+
...withDocs,
|
|
202
|
+
configure: { enabled: false },
|
|
203
|
+
};
|
|
204
|
+
const skillOff = cliBuiltinDocsGroup(configureOff).commands.find((c) => c.key === "skill");
|
|
205
|
+
expect(skillOff?.description).not.toContain("configure");
|
|
162
206
|
});
|
|
163
207
|
});
|
|
@@ -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
|
}
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Tests for builtins/config module behavior.
|
|
3
|
+
*/
|
|
4
|
+
|
|
1
5
|
import { describe, expect, test } from "bun:test";
|
|
2
6
|
import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
|
|
3
7
|
import { tmpdir } from "node:os";
|
|
@@ -20,7 +24,9 @@ function configFixture(): CliProgram {
|
|
|
20
24
|
};
|
|
21
25
|
}
|
|
22
26
|
|
|
27
|
+
/** Tests for builtins/config. */
|
|
23
28
|
describe("builtins/config", () => {
|
|
29
|
+
/** Tests that config get redacts sensitive values. */
|
|
24
30
|
test("config get redacts sensitive values", async () => {
|
|
25
31
|
const dir = mkdtempSync(join(tmpdir(), "cfg-builtin-"));
|
|
26
32
|
const prevHome = process.env.HOME;
|
|
@@ -43,6 +49,7 @@ describe("builtins/config", () => {
|
|
|
43
49
|
}
|
|
44
50
|
});
|
|
45
51
|
|
|
52
|
+
/** Tests that config get --json redacts sensitive as { set: true }. */
|
|
46
53
|
test("config get --json redacts sensitive as { set: true }", async () => {
|
|
47
54
|
const dir = mkdtempSync(join(tmpdir(), "cfg-builtin-"));
|
|
48
55
|
const prevHome = process.env.HOME;
|
|
@@ -65,6 +72,7 @@ describe("builtins/config", () => {
|
|
|
65
72
|
}
|
|
66
73
|
});
|
|
67
74
|
|
|
75
|
+
/** Tests that config set writes and resolves without required exit. */
|
|
68
76
|
test("config set writes and resolves without required exit", async () => {
|
|
69
77
|
const dir = mkdtempSync(join(tmpdir(), "cfg-builtin-"));
|
|
70
78
|
const prevHome = process.env.HOME;
|
|
@@ -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
|
+
}
|