argsbarg 4.0.4 → 4.1.0
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 +30 -1
- package/README.md +5 -5
- package/docs/ai-skills.md +8 -5
- package/docs/cli-program.md +4 -4
- package/docs/config-schema.md +1 -4
- package/docs/developing.md +1 -1
- package/docs/install.md +160 -39
- package/docs/mcp.md +21 -9
- package/docs/templates/cursor/rules/cli-program.mdc +1 -1
- package/examples/config-app/program.ts +0 -3
- package/examples/consumer-app/README.md +0 -1
- package/examples/consumer-app/src/program.ts +3 -3
- package/examples/mcp-test.ts +8 -24
- package/index.d.ts +60 -5
- package/package.json +1 -1
- package/src/builtins/builtins.test.ts +20 -4
- package/src/builtins/config.test.ts +31 -25
- package/src/builtins/config.ts +4 -3
- package/src/builtins/install.ts +50 -57
- package/src/builtins/mcp.ts +1 -1
- package/src/capabilities.ts +4 -4
- package/src/cli.ts +2 -0
- package/src/config/bootstrap.ts +167 -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 +25 -1
- package/src/config/resolve.ts +43 -8
- package/src/config.integration.test.ts +17 -10
- package/src/docs/api-guide.test.ts +1 -1
- package/src/docs/docs.test.ts +1 -1
- package/src/docs/mcp-guide.ts +1 -1
- package/src/hidden-mcpb.test.ts +41 -1
- package/src/index.ts +4 -0
- package/src/install/{binary.ts → app.ts} +13 -13
- package/src/install/bootstrap.ts +22 -0
- package/src/install/detect-installed.ts +2 -97
- package/src/install/index.ts +187 -110
- package/src/install/install-validate.test.ts +61 -0
- package/src/install/install.test.ts +138 -42
- package/src/install/mcp-openclaw.test.ts +40 -0
- package/src/install/mcp-openclaw.ts +106 -0
- package/src/install/normalize.ts +35 -0
- package/src/install/paths.ts +27 -13
- package/src/install/plan.ts +30 -259
- package/src/install/shell.ts +2 -2
- package/src/install/status.test.ts +85 -0
- package/src/install/status.ts +22 -9
- package/src/install/target-base.ts +93 -0
- package/src/install/target-detect.ts +20 -0
- package/src/install/target-effective.ts +131 -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 +266 -0
- package/src/install/target-skill.ts +104 -0
- package/src/install/target-types.ts +145 -0
- package/src/install/targets/app.ts +69 -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/completions.ts +133 -0
- package/src/install/targets/configure.ts +59 -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 +53 -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 +136 -0
- package/src/install/uninstall.ts +16 -152
- package/src/install/update.test.ts +17 -2
- package/src/install/update.ts +2 -5
- 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/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 +12 -1
- package/src/paths/host.ts +11 -11
- package/src/paths/remove-empty-dir.ts +13 -0
- 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 +65 -4
- package/src/validate.ts +70 -0
package/index.d.ts
CHANGED
|
@@ -22,7 +22,7 @@ declare class AppConfigSnapshot {
|
|
|
22
22
|
require(key: string): unknown;
|
|
23
23
|
set(key: string, value: unknown): void;
|
|
24
24
|
read(): ResolvedConfig;
|
|
25
|
-
/** Resolved absolute path to the app JSON config file (
|
|
25
|
+
/** Resolved absolute path to the app JSON config file (`~/.local/lib/<key>/config.json`). */
|
|
26
26
|
get path(): string;
|
|
27
27
|
/** Resolved absolute directory containing the config file. */
|
|
28
28
|
get dir(): string;
|
|
@@ -194,6 +194,10 @@ export interface CliMcpBundleConfig {
|
|
|
194
194
|
export interface CliMcpServerConfig {
|
|
195
195
|
/** When `true`, enables the `mcp` built-in and MCP stdio server. */
|
|
196
196
|
enabled: boolean;
|
|
197
|
+
/** When `true`, `mcp bundle` writes `dist/<key>.mcpb` for Claude Desktop. Default false. */
|
|
198
|
+
mcpd?: boolean;
|
|
199
|
+
/** When `true`, `mcp bundle` also writes `dist/claude-plugin/<name>.zip`. Default false. */
|
|
200
|
+
claudePlugin?: boolean;
|
|
197
201
|
/** Resource URI for schema export (default: `<sanitized root key>://schema`). */
|
|
198
202
|
schemaResourceUri?: string;
|
|
199
203
|
/**
|
|
@@ -281,8 +285,6 @@ export interface CliAppConfigEntry {
|
|
|
281
285
|
* App configuration block on the program root ({@link CliProgram.appConfig}).
|
|
282
286
|
*/
|
|
283
287
|
export interface CliAppConfig {
|
|
284
|
-
/** Default: `~/.config/<sanitized-key>/config` (or `%APPDATA%/<key>/config` on Windows). */
|
|
285
|
-
path?: string;
|
|
286
288
|
/** Built-in `config get` / `config set`. Default: enabled when `appConfig` is set. */
|
|
287
289
|
commands?: boolean | {
|
|
288
290
|
enabled?: boolean;
|
|
@@ -296,14 +298,67 @@ export interface CliAppConfig {
|
|
|
296
298
|
export interface CliInstallConfig {
|
|
297
299
|
/** When `false`, hide/disable `install` (default: enabled). */
|
|
298
300
|
enabled?: boolean;
|
|
299
|
-
/**
|
|
300
|
-
|
|
301
|
+
/**
|
|
302
|
+
* Default agent integration for full install (`install --all`).
|
|
303
|
+
* - `'mcp'` when `mcpServer.enabled` (default): MCP targets in `--all`; paired skills excluded.
|
|
304
|
+
* - `'skill'` when MCP is off (default): skill targets in `--all`; paired MCP excluded.
|
|
305
|
+
* - `'both'`: install MCP and skill for the same host when both are available.
|
|
306
|
+
*/
|
|
307
|
+
agentIntegration?: InstallAgentIntegration;
|
|
308
|
+
/** Per-artifact gates for full install/uninstall. See {@link resolveEffectiveInstallTargets}. */
|
|
309
|
+
targets?: CliInstallTargets;
|
|
301
310
|
/**
|
|
302
311
|
* When set, enables `install --update` on the program root.
|
|
303
312
|
* Should download or locate the latest release binary and return its path.
|
|
304
313
|
*/
|
|
305
314
|
updateGetLatest?: CliUpdateGetLatest;
|
|
306
315
|
}
|
|
316
|
+
/** Agent integration mode for install — MCP vs shell skill per host. */
|
|
317
|
+
export type InstallAgentIntegration = "mcp" | "skill" | "both";
|
|
318
|
+
/** Boolean or structured gate for one install artifact. */
|
|
319
|
+
export type InstallTargetSpec = boolean | {
|
|
320
|
+
/** When false, artifact is never installed (even with scoped CLI flags). Default true. */
|
|
321
|
+
enabled?: boolean;
|
|
322
|
+
/** When true, included in bare `install` / `install --all`. Default varies by key. */
|
|
323
|
+
includedInAll?: boolean;
|
|
324
|
+
};
|
|
325
|
+
export interface ResolvedInstallTarget {
|
|
326
|
+
enabled: boolean;
|
|
327
|
+
includedInAll: boolean;
|
|
328
|
+
}
|
|
329
|
+
/** Per-artifact gates for full install/uninstall. See {@link resolveEffectiveInstallTargets}. */
|
|
330
|
+
export interface CliInstallTargets {
|
|
331
|
+
/** Copy app to `~/.local/bin/<key>`. Default includedInAll true (opt-out). */
|
|
332
|
+
app?: InstallTargetSpec;
|
|
333
|
+
/** ChatGPT desktop MCP. Default false. */
|
|
334
|
+
chatgptMcp?: InstallTargetSpec;
|
|
335
|
+
/** Claude Code MCP (`~/.claude.json`). Default false. */
|
|
336
|
+
claudeCodeMcp?: InstallTargetSpec;
|
|
337
|
+
/** Claude Desktop MCP. Default false. */
|
|
338
|
+
claudeDesktopMcp?: InstallTargetSpec;
|
|
339
|
+
/** Claude Code skill. Default false. */
|
|
340
|
+
claudeSkill?: InstallTargetSpec;
|
|
341
|
+
/** Codex MCP (`codex mcp add`). Default false. */
|
|
342
|
+
codexMcp?: InstallTargetSpec;
|
|
343
|
+
/** Codex skill. Default false. */
|
|
344
|
+
codexSkill?: InstallTargetSpec;
|
|
345
|
+
/** Shell completions for detected shells. Default includedInAll true (opt-out). */
|
|
346
|
+
completions?: InstallTargetSpec;
|
|
347
|
+
/** App config: wizard on install, file removal on uninstall. Default includedInAll true. */
|
|
348
|
+
configure?: InstallTargetSpec;
|
|
349
|
+
/** Cursor MCP. Default false. */
|
|
350
|
+
cursorMcp?: InstallTargetSpec;
|
|
351
|
+
/** Cursor skill. Default false. */
|
|
352
|
+
cursorSkill?: InstallTargetSpec;
|
|
353
|
+
/** OpenClaw MCP. Default false. */
|
|
354
|
+
openclawMcp?: InstallTargetSpec;
|
|
355
|
+
/** OpenClaw skill. Default false. */
|
|
356
|
+
openclawSkill?: InstallTargetSpec;
|
|
357
|
+
/** OpenCode MCP. Default false. */
|
|
358
|
+
opencodeMcp?: InstallTargetSpec;
|
|
359
|
+
/** OpenCode skill. Default false. */
|
|
360
|
+
opencodeSkill?: InstallTargetSpec;
|
|
361
|
+
}
|
|
307
362
|
/**
|
|
308
363
|
* One bundled documentation topic for the `docs` built-in (program root only).
|
|
309
364
|
*/
|
package/package.json
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { describe, expect, test } from "bun:test";
|
|
2
|
+
import { ParseKind, parse, postParseValidate } from "../parse.ts";
|
|
2
3
|
import type { CliProgram } from "../types.ts";
|
|
3
4
|
import { exportPresentationBuiltins } from "./export.ts";
|
|
4
5
|
import { completionBashScript, completionFishScript, completionZshScript } from "./index.ts";
|
|
5
6
|
import { cliBuiltinInstallCommand, installBuiltinOptions } from "./install.ts";
|
|
6
7
|
import { cliBuiltinMcpCommand } from "./mcp.ts";
|
|
7
|
-
import { cliPresentationRoot } from "./presentation.ts";
|
|
8
|
+
import { cliParseRoot, cliPresentationRoot } from "./presentation.ts";
|
|
8
9
|
|
|
9
10
|
const fixture: CliProgram = {
|
|
10
11
|
key: "myapp",
|
|
@@ -23,12 +24,27 @@ const fixture: CliProgram = {
|
|
|
23
24
|
describe("builtins help copy", () => {
|
|
24
25
|
test("install command includes description and option text", () => {
|
|
25
26
|
const install = cliBuiltinInstallCommand(fixture);
|
|
26
|
-
expect(install.description).toContain("
|
|
27
|
+
expect(install.description).toContain("shell completions");
|
|
27
28
|
expect(install.notes).toContain("install --all");
|
|
28
29
|
const names = installBuiltinOptions(fixture).map((o) => o.name);
|
|
29
30
|
expect(names).toContain("all");
|
|
30
31
|
expect(names).toContain("mcp");
|
|
31
|
-
expect(names).
|
|
32
|
+
expect(names.indexOf("all")).toBeLessThan(names.indexOf("mcp"));
|
|
33
|
+
expect(names.indexOf("mcp")).toBeLessThan(names.indexOf("status"));
|
|
34
|
+
expect(names.indexOf("status")).toBeLessThan(names.indexOf("uninstall"));
|
|
35
|
+
expect(names.indexOf("uninstall")).toBeLessThan(names.indexOf("from"));
|
|
36
|
+
expect(names.indexOf("from")).toBeLessThan(names.indexOf("yes"));
|
|
37
|
+
const yesOpt = installBuiltinOptions(fixture).find((o) => o.name === "yes");
|
|
38
|
+
expect(yesOpt?.shortName).toBe("y");
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
test("install -y parses as --yes", () => {
|
|
42
|
+
const root = cliParseRoot(fixture);
|
|
43
|
+
const pr = postParseValidate(root, parse(root, ["install", "-y"]));
|
|
44
|
+
expect(pr.kind).toBe(ParseKind.Ok);
|
|
45
|
+
if (pr.kind === ParseKind.Ok) {
|
|
46
|
+
expect(pr.opts.yes).toBe("1");
|
|
47
|
+
}
|
|
32
48
|
});
|
|
33
49
|
|
|
34
50
|
test("install omits --mcp option when mcpServer unset", () => {
|
|
@@ -143,6 +159,6 @@ describe("schema export builtins", () => {
|
|
|
143
159
|
test("exportPresentationBuiltins includes install options", () => {
|
|
144
160
|
const builtins = exportPresentationBuiltins(fixture);
|
|
145
161
|
const install = builtins.find((b) => b.key === "install");
|
|
146
|
-
expect(install?.options?.find((o) => o.name === "all")?.description).toContain("
|
|
162
|
+
expect(install?.options?.find((o) => o.name === "all")?.description).toContain("app");
|
|
147
163
|
});
|
|
148
164
|
});
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import { describe, expect, test } from "bun:test";
|
|
2
|
-
import { mkdtempSync, rmSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
|
|
3
3
|
import { tmpdir } from "node:os";
|
|
4
|
-
import { join } from "node:path";
|
|
4
|
+
import { dirname, join } from "node:path";
|
|
5
|
+
import { resolveAppConfigPath, writeAppConfigFile } from "../config/file.ts";
|
|
5
6
|
import { Cli, type CliProgram } from "../index.ts";
|
|
6
7
|
|
|
7
|
-
function configFixture(
|
|
8
|
+
function configFixture(): CliProgram {
|
|
8
9
|
return {
|
|
9
10
|
key: "cfg-app",
|
|
10
11
|
version: "1.0.0",
|
|
11
12
|
description: "Config builtin test.",
|
|
12
13
|
appConfig: {
|
|
13
|
-
path: configPath,
|
|
14
14
|
entries: {
|
|
15
15
|
apiToken: { description: "Token.", env: "API_TOKEN", sensitive: true },
|
|
16
16
|
port: { description: "Port.", required: false },
|
|
@@ -23,15 +23,21 @@ function configFixture(configPath: string): CliProgram {
|
|
|
23
23
|
describe("builtins/config", () => {
|
|
24
24
|
test("config get redacts sensitive values", async () => {
|
|
25
25
|
const dir = mkdtempSync(join(tmpdir(), "cfg-builtin-"));
|
|
26
|
-
const
|
|
27
|
-
|
|
26
|
+
const prevHome = process.env.HOME;
|
|
27
|
+
process.env.HOME = dir;
|
|
28
28
|
const prev = process.env.API_TOKEN;
|
|
29
29
|
delete process.env.API_TOKEN;
|
|
30
30
|
try {
|
|
31
|
-
const
|
|
31
|
+
const program = configFixture();
|
|
32
|
+
const configPath = resolveAppConfigPath(program);
|
|
33
|
+
mkdirSync(dirname(configPath), { recursive: true });
|
|
34
|
+
writeFileSync(configPath, `${JSON.stringify({ apiToken: "secret" })}\n`);
|
|
35
|
+
const result = await new Cli(program).invoke(["config", "get", "apiToken"]);
|
|
32
36
|
expect(result.exitCode).toBe(0);
|
|
33
37
|
expect(result.stdout.trim()).toBe("REDACTED");
|
|
34
38
|
} finally {
|
|
39
|
+
if (prevHome === undefined) delete process.env.HOME;
|
|
40
|
+
else process.env.HOME = prevHome;
|
|
35
41
|
if (prev !== undefined) process.env.API_TOKEN = prev;
|
|
36
42
|
rmSync(dir, { recursive: true, force: true });
|
|
37
43
|
}
|
|
@@ -39,20 +45,21 @@ describe("builtins/config", () => {
|
|
|
39
45
|
|
|
40
46
|
test("config get --json redacts sensitive as { set: true }", async () => {
|
|
41
47
|
const dir = mkdtempSync(join(tmpdir(), "cfg-builtin-"));
|
|
42
|
-
const
|
|
43
|
-
|
|
48
|
+
const prevHome = process.env.HOME;
|
|
49
|
+
process.env.HOME = dir;
|
|
44
50
|
const prev = process.env.API_TOKEN;
|
|
45
51
|
delete process.env.API_TOKEN;
|
|
46
52
|
try {
|
|
47
|
-
const
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
]);
|
|
53
|
+
const program = configFixture();
|
|
54
|
+
const configPath = resolveAppConfigPath(program);
|
|
55
|
+
mkdirSync(dirname(configPath), { recursive: true });
|
|
56
|
+
writeFileSync(configPath, `${JSON.stringify({ apiToken: "secret" })}\n`);
|
|
57
|
+
const result = await new Cli(program).invoke(["config", "get", "apiToken", "--json"]);
|
|
53
58
|
expect(result.exitCode).toBe(0);
|
|
54
|
-
expect(JSON.parse(result.stdout
|
|
59
|
+
expect(JSON.parse(result.stdout)).toEqual({ set: true });
|
|
55
60
|
} finally {
|
|
61
|
+
if (prevHome === undefined) delete process.env.HOME;
|
|
62
|
+
else process.env.HOME = prevHome;
|
|
56
63
|
if (prev !== undefined) process.env.API_TOKEN = prev;
|
|
57
64
|
rmSync(dir, { recursive: true, force: true });
|
|
58
65
|
}
|
|
@@ -60,21 +67,20 @@ describe("builtins/config", () => {
|
|
|
60
67
|
|
|
61
68
|
test("config set writes and resolves without required exit", async () => {
|
|
62
69
|
const dir = mkdtempSync(join(tmpdir(), "cfg-builtin-"));
|
|
63
|
-
const
|
|
64
|
-
|
|
70
|
+
const prevHome = process.env.HOME;
|
|
71
|
+
process.env.HOME = dir;
|
|
65
72
|
const prev = process.env.API_TOKEN;
|
|
66
73
|
delete process.env.API_TOKEN;
|
|
67
74
|
try {
|
|
68
|
-
const
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
"port",
|
|
72
|
-
"9090",
|
|
73
|
-
]);
|
|
75
|
+
const program = configFixture();
|
|
76
|
+
writeAppConfigFile(program, { apiToken: "seed" });
|
|
77
|
+
const result = await new Cli(program).invoke(["config", "set", "port", "9090"]);
|
|
74
78
|
expect(result.exitCode).toBe(0);
|
|
75
|
-
const get = await new Cli(
|
|
79
|
+
const get = await new Cli(program).invoke(["config", "get", "port"]);
|
|
76
80
|
expect(get.stdout.trim()).toBe("9090");
|
|
77
81
|
} finally {
|
|
82
|
+
if (prevHome === undefined) delete process.env.HOME;
|
|
83
|
+
else process.env.HOME = prevHome;
|
|
78
84
|
if (prev !== undefined) process.env.API_TOKEN = prev;
|
|
79
85
|
rmSync(dir, { recursive: true, force: true });
|
|
80
86
|
}
|
package/src/builtins/config.ts
CHANGED
|
@@ -5,7 +5,7 @@ Built-in `config get` / `config set` commands.
|
|
|
5
5
|
import { bootstrapAppConfig } from "../config/bootstrap.ts";
|
|
6
6
|
import { configEntrySensitive, defaultConfigEntryTitle } from "../config/entry.ts";
|
|
7
7
|
import { writeAppConfigFile } from "../config/file.ts";
|
|
8
|
-
import { exportConfigToEnv, resolveAppConfig } from "../config/resolve.ts";
|
|
8
|
+
import { captureMappedHostEnv, exportConfigToEnv, resolveAppConfig } from "../config/resolve.ts";
|
|
9
9
|
import { configPropertySchema, effectiveJsonSchema } from "../config/schema.ts";
|
|
10
10
|
import { parseConfigSetValue } from "../config/validate.ts";
|
|
11
11
|
import type { CliLeaf, CliOption, CliProgram, CliRouter } from "../types.ts";
|
|
@@ -128,11 +128,12 @@ function configSetRun(program: CliProgram, key: string, rawValue: string, useJso
|
|
|
128
128
|
process.exit(1);
|
|
129
129
|
}
|
|
130
130
|
|
|
131
|
+
const hostEnv = captureMappedHostEnv(program);
|
|
131
132
|
const { fileData } = bootstrapAppConfig(program, { validateFile: true });
|
|
132
133
|
const next = { ...fileData, [key]: parsed };
|
|
133
134
|
writeAppConfigFile(program, next);
|
|
134
|
-
const resolved = resolveAppConfig(program, next);
|
|
135
|
-
exportConfigToEnv(program, resolved);
|
|
135
|
+
const resolved = resolveAppConfig(program, next, hostEnv);
|
|
136
|
+
exportConfigToEnv(program, resolved, hostEnv);
|
|
136
137
|
}
|
|
137
138
|
|
|
138
139
|
function configGetLeaf(program: CliProgram): CliLeaf {
|
package/src/builtins/install.ts
CHANGED
|
@@ -6,12 +6,13 @@ export function installBuiltinOptions(root: CliProgram): CliOption[] {
|
|
|
6
6
|
const opts: CliOption[] = [
|
|
7
7
|
{
|
|
8
8
|
name: "all",
|
|
9
|
-
description:
|
|
9
|
+
description:
|
|
10
|
+
"Install the default set (app, shell completions, and configuration when supported).",
|
|
10
11
|
kind: CliOptionKind.Presence,
|
|
11
12
|
},
|
|
12
13
|
{
|
|
13
|
-
name: "
|
|
14
|
-
description: "Copy this
|
|
14
|
+
name: "app",
|
|
15
|
+
description: "Copy this app to your install directory (default ~/.local/bin).",
|
|
15
16
|
kind: CliOptionKind.Presence,
|
|
16
17
|
},
|
|
17
18
|
{
|
|
@@ -22,40 +23,68 @@ export function installBuiltinOptions(root: CliProgram): CliOption[] {
|
|
|
22
23
|
},
|
|
23
24
|
{
|
|
24
25
|
name: "skill",
|
|
25
|
-
description:
|
|
26
|
+
description:
|
|
27
|
+
"Install agent skills for Cursor, Claude, and other supported AI tools on this machine.",
|
|
26
28
|
kind: CliOptionKind.Presence,
|
|
27
29
|
},
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
30
|
+
];
|
|
31
|
+
|
|
32
|
+
if (resolveCapabilities(root).mcp) {
|
|
33
|
+
opts.push({
|
|
34
|
+
name: "mcp",
|
|
35
|
+
description:
|
|
36
|
+
"Add MCP server configuration for Cursor, Claude Code, and other supported agents.",
|
|
31
37
|
kind: CliOptionKind.Presence,
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (root.appConfig) {
|
|
42
|
+
opts.push({
|
|
43
|
+
name: "configure",
|
|
44
|
+
description:
|
|
45
|
+
"Run the configuration wizard (install), or remove the config file (--uninstall).",
|
|
46
|
+
kind: CliOptionKind.Presence,
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
opts.push(
|
|
38
51
|
{
|
|
39
52
|
name: "status",
|
|
40
53
|
description: "Print what is currently installed (read-only).",
|
|
41
54
|
kind: CliOptionKind.Presence,
|
|
42
55
|
},
|
|
56
|
+
{
|
|
57
|
+
name: "reinstall",
|
|
58
|
+
description: "Refresh everything already installed for this app.",
|
|
59
|
+
kind: CliOptionKind.Presence,
|
|
60
|
+
},
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
if (resolveCapabilities(root).update) {
|
|
64
|
+
opts.push({
|
|
65
|
+
name: "update",
|
|
66
|
+
description: "Download the latest release and refresh installed files.",
|
|
67
|
+
kind: CliOptionKind.Presence,
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
opts.push(
|
|
43
72
|
{
|
|
44
73
|
name: "uninstall",
|
|
45
74
|
description:
|
|
46
|
-
"Remove installed
|
|
75
|
+
"Remove installed files (--all removes everything; use individual flags to remove one category).",
|
|
47
76
|
kind: CliOptionKind.Presence,
|
|
48
77
|
},
|
|
49
78
|
{
|
|
50
|
-
name: "
|
|
51
|
-
description:
|
|
52
|
-
"Install directory for the binary (default ~/.local/bin; overrides INSTALL_PREFIX).",
|
|
79
|
+
name: "from",
|
|
80
|
+
description: "App executable to copy (default: running executable). Used with --reinstall.",
|
|
53
81
|
kind: CliOptionKind.String,
|
|
54
82
|
},
|
|
55
83
|
{
|
|
56
84
|
name: "yes",
|
|
57
85
|
description: "Skip the confirmation prompt.",
|
|
58
86
|
kind: CliOptionKind.Presence,
|
|
87
|
+
shortName: "y",
|
|
59
88
|
},
|
|
60
89
|
{
|
|
61
90
|
name: "dry",
|
|
@@ -67,43 +96,7 @@ export function installBuiltinOptions(root: CliProgram): CliOption[] {
|
|
|
67
96
|
description: "Print changed paths (install/update/uninstall) or status JSON on stdout.",
|
|
68
97
|
kind: CliOptionKind.Presence,
|
|
69
98
|
},
|
|
70
|
-
|
|
71
|
-
name: "quiet",
|
|
72
|
-
description:
|
|
73
|
-
"Suppress informational output (requires --yes, --json, --reinstall, or --update).",
|
|
74
|
-
kind: CliOptionKind.Presence,
|
|
75
|
-
},
|
|
76
|
-
];
|
|
77
|
-
|
|
78
|
-
if (resolveCapabilities(root).mcp) {
|
|
79
|
-
opts.splice(4, 0, {
|
|
80
|
-
name: "mcp",
|
|
81
|
-
description: "Add or update MCP server entries in Cursor and Claude config files.",
|
|
82
|
-
kind: CliOptionKind.Presence,
|
|
83
|
-
});
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
if (resolveCapabilities(root).update) {
|
|
87
|
-
const statusIdx = opts.findIndex((o) => o.name === "status");
|
|
88
|
-
opts.splice(statusIdx, 0, {
|
|
89
|
-
name: "update",
|
|
90
|
-
description: "Download the latest release and reinstall installed artifacts.",
|
|
91
|
-
kind: CliOptionKind.Presence,
|
|
92
|
-
});
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
if (root.appConfig) {
|
|
96
|
-
opts.push({
|
|
97
|
-
name: "configure",
|
|
98
|
-
description: "Interactively write app config (~/.config/<key>/config).",
|
|
99
|
-
kind: CliOptionKind.Presence,
|
|
100
|
-
});
|
|
101
|
-
opts.push({
|
|
102
|
-
name: "config",
|
|
103
|
-
description: "Remove app config file (with --uninstall).",
|
|
104
|
-
kind: CliOptionKind.Presence,
|
|
105
|
-
});
|
|
106
|
-
}
|
|
99
|
+
);
|
|
107
100
|
|
|
108
101
|
return opts;
|
|
109
102
|
}
|
|
@@ -113,7 +106,7 @@ export function cliBuiltinInstallCommand(root: CliProgram): CliLeaf {
|
|
|
113
106
|
const app = root.key;
|
|
114
107
|
const notesLines = [
|
|
115
108
|
"First-time setup:",
|
|
116
|
-
` ${app} install --
|
|
109
|
+
` ${app} install --yes`,
|
|
117
110
|
"",
|
|
118
111
|
"Refresh after upgrading:",
|
|
119
112
|
` ${app} install --reinstall`,
|
|
@@ -135,9 +128,9 @@ export function cliBuiltinInstallCommand(root: CliProgram): CliLeaf {
|
|
|
135
128
|
return {
|
|
136
129
|
key: "install",
|
|
137
130
|
description:
|
|
138
|
-
"Install
|
|
139
|
-
notes: notesLines.join("\n"),
|
|
131
|
+
"Install this app, shell completions, agent skills, and MCP config on your machine.",
|
|
140
132
|
options: installBuiltinOptions(root),
|
|
133
|
+
notes: notesLines.join("\n"),
|
|
141
134
|
handler: () => {},
|
|
142
135
|
};
|
|
143
136
|
}
|
package/src/builtins/mcp.ts
CHANGED
|
@@ -28,7 +28,7 @@ export function cliBuiltinMcpCommand(program: CliProgram): CliRouter {
|
|
|
28
28
|
|
|
29
29
|
const bundle: CliLeaf = {
|
|
30
30
|
key: "bundle",
|
|
31
|
-
description: "Pack
|
|
31
|
+
description: "Pack dist MCP artifacts (`.mcpb`, Claude Code plugin zip) from dist/<key>.",
|
|
32
32
|
handler: () => {},
|
|
33
33
|
};
|
|
34
34
|
|
package/src/capabilities.ts
CHANGED
|
@@ -65,13 +65,13 @@ export type CapabilityFeature = "mcp" | "install" | "docs" | "config";
|
|
|
65
65
|
export function capabilityDeniedMessage(feature: CapabilityFeature): string {
|
|
66
66
|
switch (feature) {
|
|
67
67
|
case "mcp":
|
|
68
|
-
return "MCP is not
|
|
68
|
+
return "MCP is not available for this app.\n";
|
|
69
69
|
case "install":
|
|
70
|
-
return "
|
|
70
|
+
return "Install is not available for this app.\n";
|
|
71
71
|
case "docs":
|
|
72
|
-
return "
|
|
72
|
+
return "Documentation commands are not available for this app.\n";
|
|
73
73
|
case "config":
|
|
74
|
-
return "
|
|
74
|
+
return "Configuration commands are not available for this app.\n";
|
|
75
75
|
}
|
|
76
76
|
}
|
|
77
77
|
|
package/src/cli.ts
CHANGED
|
@@ -20,6 +20,7 @@ import { type AnyAppConfigSnapshot, createAppConfigSnapshot } from "./config/con
|
|
|
20
20
|
import { effectiveJsonSchema } from "./config/schema.ts";
|
|
21
21
|
import { CliContext } from "./context.ts";
|
|
22
22
|
import { cliHelpRender } from "./help.ts";
|
|
23
|
+
import { maybeBootstrapInstallArgv } from "./install/bootstrap.ts";
|
|
23
24
|
import { bootstrapMcpEnv } from "./mcp/env.ts";
|
|
24
25
|
import { mcpServeStdioLoop } from "./mcp/server.ts";
|
|
25
26
|
import { ParseKind, type ParseResult, parse, postParseValidate } from "./parse.ts";
|
|
@@ -94,6 +95,7 @@ export class Cli {
|
|
|
94
95
|
}
|
|
95
96
|
|
|
96
97
|
async run(argv: string[] = process.argv.slice(2)): Promise<never> {
|
|
98
|
+
argv = maybeBootstrapInstallArgv(argv, this.program);
|
|
97
99
|
assertBuiltinAllowed(argv, this.caps);
|
|
98
100
|
|
|
99
101
|
const prep = this.prepareDispatch(argv);
|