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.
Files changed (82) hide show
  1. package/CHANGELOG.md +34 -1
  2. package/README.md +5 -5
  3. package/docs/README.md +3 -3
  4. package/docs/ai-skills.md +9 -9
  5. package/docs/bundled-docs.md +4 -4
  6. package/docs/cli-program.md +8 -8
  7. package/docs/config-schema.md +2 -2
  8. package/docs/configure.md +177 -0
  9. package/docs/developing.md +1 -1
  10. package/docs/distribution-homebrew.md +12 -9
  11. package/docs/mcp.md +9 -9
  12. package/examples/full-example/README.md +3 -3
  13. package/examples/full-example/justfile +6 -6
  14. package/examples/full-example/scripts/formula-shared.ts +3 -2
  15. package/examples/full-example/src/program.ts +3 -3
  16. package/examples/nested.ts +1 -1
  17. package/index.d.ts +23 -16
  18. package/package.json +1 -1
  19. package/src/builtins/builtins.test.ts +105 -61
  20. package/src/builtins/completion-group.ts +4 -6
  21. package/src/builtins/config.test.ts +8 -0
  22. package/src/builtins/configure-copy.ts +86 -0
  23. package/src/builtins/configure.ts +70 -0
  24. package/src/builtins/dispatch.ts +13 -33
  25. package/src/builtins/index.ts +1 -1
  26. package/src/builtins/mcp.ts +2 -2
  27. package/src/builtins/registry.ts +6 -6
  28. package/src/capabilities.ts +22 -13
  29. package/src/cli-tool/cli-smoke.test.ts +21 -3
  30. package/src/cli-tool/create.test.ts +36 -1
  31. package/src/cli-tool/create.ts +26 -4
  32. package/src/cli-tool/full-example-capabilities.test.ts +10 -2
  33. package/src/cli-tool/main.ts +0 -0
  34. package/src/cli-tool/program.ts +20 -5
  35. package/src/cli-tool/run-create.ts +8 -19
  36. package/src/config/bootstrap.ts +11 -9
  37. package/src/config/context.test.ts +8 -0
  38. package/src/config/file.test.ts +13 -1
  39. package/src/config/resolve.test.ts +18 -0
  40. package/src/config/resolve.ts +2 -2
  41. package/src/config/validate.test.ts +11 -0
  42. package/src/config.integration.test.ts +5 -0
  43. package/src/configure/configure.test.ts +170 -0
  44. package/src/configure/index.ts +298 -0
  45. package/src/configure/prompt.ts +47 -0
  46. package/src/docs/api-guide.test.ts +10 -0
  47. package/src/docs/builtin.ts +3 -5
  48. package/src/docs/docs.test.ts +32 -5
  49. package/src/docs/mcp-guide.ts +4 -4
  50. package/src/docs/mcp-resources.test.ts +10 -0
  51. package/src/formats.test.ts +9 -0
  52. package/src/headless.test.ts +10 -0
  53. package/src/hidden-mcpb.test.ts +22 -0
  54. package/src/index.ts +2 -2
  55. package/src/install/binary-placement.test.ts +14 -0
  56. package/src/install/gh-release-update.test.ts +9 -0
  57. package/src/install/install-validate.test.ts +15 -5
  58. package/src/install/mcp-codex.test.ts +7 -0
  59. package/src/install/mcp-openclaw.test.ts +6 -0
  60. package/src/install/mcp-opencode.test.ts +10 -0
  61. package/src/install/opts.ts +17 -0
  62. package/src/install/status.test.ts +9 -0
  63. package/src/install/target-effective.ts +8 -8
  64. package/src/install/target-scope.ts +11 -8
  65. package/src/install/targets/configure.ts +1 -1
  66. package/src/install/targets.test.ts +23 -4
  67. package/src/invoke.test.ts +15 -1
  68. package/src/mcp/claude.test.ts +10 -0
  69. package/src/mcp/env.test.ts +12 -0
  70. package/src/mcp/tools.ts +1 -1
  71. package/src/mcp/zip.test.ts +5 -0
  72. package/src/mcp.integration.test.ts +43 -4
  73. package/src/parse.test.ts +82 -13
  74. package/src/schema.ts +1 -9
  75. package/src/skill/hint.ts +2 -2
  76. package/src/types.ts +22 -14
  77. package/src/validate.ts +17 -17
  78. package/docs/install.md +0 -206
  79. package/src/builtins/install.ts +0 -106
  80. package/src/builtins/uninstall.ts +0 -80
  81. package/src/install/index.ts +0 -409
  82. package/src/install/install.test.ts +0 -317
@@ -1,6 +1,6 @@
1
1
  import { resolveCapabilities } from "../capabilities.ts";
2
2
  import { appConfigInstalled } from "../config/file.ts";
3
- import type { CliInstallTargets, CliProgram } from "../types.ts";
3
+ import type { CliConfigureTargets, CliProgram } from "../types.ts";
4
4
  import type { InstallPaths } from "./paths.ts";
5
5
  import {
6
6
  type InstallPlanMode,
@@ -78,7 +78,7 @@ export function buildDetectedSnapshot(root: CliProgram, paths: InstallPaths): De
78
78
  }
79
79
 
80
80
  function targetExplicitlyConfigured(
81
- user: CliInstallTargets | undefined,
81
+ user: CliConfigureTargets | undefined,
82
82
  key: CliInstallArtifactKey,
83
83
  ): boolean {
84
84
  return user?.[key] !== undefined;
@@ -89,7 +89,7 @@ function agentCategoryInScope(
89
89
  categoryKeys: readonly CliInstallArtifactKey[],
90
90
  category: "skill" | "mcp",
91
91
  effective: Record<CliInstallArtifactKey, { enabled: boolean; includedInAll: boolean }>,
92
- targets: CliInstallTargets | undefined,
92
+ targets: CliConfigureTargets | undefined,
93
93
  root: CliProgram,
94
94
  ): boolean {
95
95
  if (!categoryKeys.includes(key)) return false;
@@ -105,7 +105,7 @@ export function isArtifactInScope(
105
105
  effective: Record<CliInstallArtifactKey, { enabled: boolean; includedInAll: boolean }>,
106
106
  mode: InstallPlanMode,
107
107
  root: CliProgram,
108
- targets?: CliInstallTargets,
108
+ targets?: CliConfigureTargets,
109
109
  ): boolean {
110
110
  if (mode === "uninstall-all") {
111
111
  return true;
@@ -150,7 +150,7 @@ export function shouldIncludeArtifact(
150
150
  detected?: Partial<Record<CliInstallArtifactKey, boolean>>,
151
151
  ): boolean {
152
152
  const target = installTargetForKey(key);
153
- const targets = root.install?.targets;
153
+ const targets = root.configure?.targets;
154
154
 
155
155
  if (key !== "configure" && target && !target.isAvailable(root, paths)) {
156
156
  return false;
@@ -196,7 +196,7 @@ export function buildTargetPlanContext(
196
196
  opts: InstallOpts,
197
197
  detected: DetectedSnapshot,
198
198
  ): TargetPlanContext {
199
- const effective = resolveEffectiveInstallTargets(root.install, root);
199
+ const effective = resolveEffectiveInstallTargets(root.configure, root);
200
200
  const mode = resolveInstallPlanMode(opts);
201
201
  const scope = resolveInstallScope(opts);
202
202
  const detPartial = Object.fromEntries(
@@ -236,8 +236,11 @@ export function resolveInstallTargetPreview(
236
236
  program: CliProgram,
237
237
  paths: InstallPaths,
238
238
  ): InstallTargetPreview {
239
- const effective = resolveEffectiveInstallTargets(program.install, program);
240
- const integration = resolveAgentIntegration(program.install, program.mcpServer?.enabled === true);
239
+ const effective = resolveEffectiveInstallTargets(program.configure, program);
240
+ const integration = resolveAgentIntegration(
241
+ program.configure,
242
+ program.mcpServer?.enabled === true,
243
+ );
241
244
 
242
245
  const keysForScope = (scope: InstallScope, mode: InstallPlanMode): CliInstallArtifactKey[] =>
243
246
  INSTALL_ARTIFACT_KEYS.filter((key) =>
@@ -11,7 +11,7 @@ import type {
11
11
  UninstallAction,
12
12
  } from "../target-types.ts";
13
13
 
14
- /** App config file (install --configure / wizard). */
14
+ /** App config file (interactive configure / wizard). */
15
15
  class ConfigureInstallTarget extends InstallTarget {
16
16
  readonly key = "configure" as const;
17
17
  readonly actionKind = "configure" as const;
@@ -1,3 +1,7 @@
1
+ /*
2
+ Tests for install/targets module behavior.
3
+ */
4
+
1
5
  import { describe, expect, test } from "bun:test";
2
6
  import type { CliProgram } from "../types.ts";
3
7
  import { normalizeInstallRawOpts } from "./normalize.ts";
@@ -5,11 +9,14 @@ import { normalizeUninstallRawOpts } from "./normalize-uninstall.ts";
5
9
  import { resolveAgentIntegration, resolveEffectiveInstallTargets } from "./target-effective.ts";
6
10
  import { isArtifactInScope } from "./target-scope.ts";
7
11
 
12
+ /** Tests for normalizeInstallRawOpts. */
8
13
  describe("normalizeInstallRawOpts", () => {
14
+ /** Bare install sets all. */
9
15
  test("bare install sets all", () => {
10
16
  expect(normalizeInstallRawOpts({})).toEqual({ all: "1" });
11
17
  });
12
18
 
19
+ /** Bare uninstall sets all. */
13
20
  test("bare uninstall sets all", () => {
14
21
  expect(normalizeUninstallRawOpts({})).toEqual({
15
22
  uninstall: "1",
@@ -17,28 +24,35 @@ describe("normalizeInstallRawOpts", () => {
17
24
  });
18
25
  });
19
26
 
27
+ /** Configure-only install unchanged. */
20
28
  test("configure-only install unchanged", () => {
21
29
  expect(normalizeInstallRawOpts({ configure: "1" })).toEqual({ configure: "1" });
22
30
  });
23
31
  });
24
32
 
33
+ /** Tests for resolveAgentIntegration. */
25
34
  describe("resolveAgentIntegration", () => {
35
+ /** Defaults to skill without MCP. */
26
36
  test("defaults to skill without MCP", () => {
27
37
  expect(resolveAgentIntegration(undefined, false)).toBe("skill");
28
38
  });
29
39
 
40
+ /** Defaults to mcp when MCP enabled. */
30
41
  test("defaults to mcp when MCP enabled", () => {
31
42
  expect(resolveAgentIntegration(undefined, true)).toBe("mcp");
32
43
  });
33
44
  });
34
45
 
46
+ /** Tests for resolveEffectiveInstallTargets. */
35
47
  describe("resolveEffectiveInstallTargets", () => {
48
+ /** Defaults app and configure not in --all. */
36
49
  test("defaults app and configure not in --all", () => {
37
50
  const t = resolveEffectiveInstallTargets(undefined);
38
51
  expect(t.app.includedInAll).toBe(false);
39
52
  expect(t.configure.includedInAll).toBe(false);
40
53
  });
41
54
 
55
+ /** Skill mode includes skills in --all not MCP pairs. */
42
56
  test("skill mode includes skills in --all not MCP pairs", () => {
43
57
  const program: Pick<CliProgram, "mcpServer"> = {};
44
58
  const t = resolveEffectiveInstallTargets(undefined, program);
@@ -46,6 +60,7 @@ describe("resolveEffectiveInstallTargets", () => {
46
60
  expect(t.cursorMcp.includedInAll).toBe(false);
47
61
  });
48
62
 
63
+ /** Mcp mode includes MCP in --all not paired skills. */
49
64
  test("mcp mode includes MCP in --all not paired skills", () => {
50
65
  const program: Pick<CliProgram, "mcpServer"> = { mcpServer: { enabled: true } };
51
66
  const t = resolveEffectiveInstallTargets(undefined, program);
@@ -54,6 +69,7 @@ describe("resolveEffectiveInstallTargets", () => {
54
69
  expect(t.claudeDesktopMcp.includedInAll).toBe(true);
55
70
  });
56
71
 
72
+ /** Tests that both mode includes MCP and skills. */
57
73
  test("both mode includes MCP and skills", () => {
58
74
  const program: Pick<CliProgram, "mcpServer"> = { mcpServer: { enabled: true } };
59
75
  const t = resolveEffectiveInstallTargets({ agentIntegration: "both" }, program);
@@ -61,6 +77,7 @@ describe("resolveEffectiveInstallTargets", () => {
61
77
  expect(t.cursorSkill.includedInAll).toBe(true);
62
78
  });
63
79
 
80
+ /** Tests that per-key override disables one skill. */
64
81
  test("per-key override disables one skill", () => {
65
82
  const t = resolveEffectiveInstallTargets({
66
83
  targets: { cursorSkill: false },
@@ -69,16 +86,17 @@ describe("resolveEffectiveInstallTargets", () => {
69
86
  expect(t.cursorSkill.enabled).toBe(false);
70
87
  });
71
88
 
89
+ /** Scoped --mcp uses effective targets not all MCP hosts. */
72
90
  test("scoped --mcp uses effective targets not all MCP hosts", () => {
73
91
  const program: CliProgram = {
74
92
  key: "app",
75
93
  version: "1",
76
94
  description: "x",
77
95
  mcpServer: { enabled: true },
78
- install: { agentIntegration: "skill" },
96
+ configure: { agentIntegration: "skill" },
79
97
  handler: () => {},
80
98
  };
81
- const effective = resolveEffectiveInstallTargets(program.install, program);
99
+ const effective = resolveEffectiveInstallTargets(program.configure, program);
82
100
  const scope = { mcp: true };
83
101
  expect(isArtifactInScope("cursorMcp", scope, effective, "install-scoped", program)).toBe(false);
84
102
  expect(
@@ -95,16 +113,17 @@ describe("resolveEffectiveInstallTargets", () => {
95
113
  ).toBe(true);
96
114
  });
97
115
 
116
+ /** Scoped --mcp --skill --configure includes skill and mcp not only configure. */
98
117
  test("scoped --mcp --skill --configure includes skill and mcp not only configure", () => {
99
118
  const program: CliProgram = {
100
119
  key: "app",
101
120
  version: "1",
102
121
  description: "x",
103
122
  mcpServer: { enabled: true },
104
- install: { agentIntegration: "both" },
123
+ configure: { agentIntegration: "both" },
105
124
  handler: () => {},
106
125
  };
107
- const effective = resolveEffectiveInstallTargets(program.install, program);
126
+ const effective = resolveEffectiveInstallTargets(program.configure, program);
108
127
  const scope = { mcp: true, skill: true, configure: true };
109
128
  expect(isArtifactInScope("cursorSkill", scope, effective, "install-scoped", program)).toBe(
110
129
  true,
@@ -12,6 +12,7 @@ import type { CliLeaf } from "./types.ts";
12
12
  import { isCliRouter } from "./types.ts";
13
13
  import { cliValidateProgram } from "./validate.ts";
14
14
 
15
+ /** Tests that ctx.invocation is cli via Cli.run. */
15
16
  test("ctx.invocation is cli via Cli.run", async () => {
16
17
  const indexPath = join(import.meta.dir, "index.ts");
17
18
  const { stdout } = await $`bun -e ${`
@@ -20,7 +21,7 @@ const program = {
20
21
  key: "t",
21
22
  description: "d",
22
23
  version: "0.0.0",
23
- install: { enabled: false },
24
+ configure: { enabled: false },
24
25
  handler: (ctx) => console.log(ctx.invocation),
25
26
  };
26
27
  await new Cli(program).run([]);
@@ -28,6 +29,7 @@ await new Cli(program).run([]);
28
29
  expect(stdout.toString().trim()).toBe("cli");
29
30
  });
30
31
 
32
+ /** Tests that ctx.invocation is mcp via Cli.invoke. */
31
33
  test("ctx.invocation is mcp via Cli.invoke", async () => {
32
34
  let seen = "";
33
35
  const root = testProgram({
@@ -43,6 +45,7 @@ test("ctx.invocation is mcp via Cli.invoke", async () => {
43
45
  expect(seen).toBe("mcp");
44
46
  });
45
47
 
48
+ /** Cli.invoke rejects invalid Enum value. */
46
49
  test("Cli.invoke rejects invalid Enum value", async () => {
47
50
  const root = testProgram({
48
51
  key: "app",
@@ -64,6 +67,7 @@ test("Cli.invoke rejects invalid Enum value", async () => {
64
67
  expect(result.errorMsg).toContain("not one of");
65
68
  });
66
69
 
70
+ /** Cli.invoke accepts valid Enum value. */
67
71
  test("Cli.invoke accepts valid Enum value", async () => {
68
72
  const root = testProgram({
69
73
  key: "app",
@@ -87,6 +91,7 @@ test("Cli.invoke accepts valid Enum value", async () => {
87
91
  expect(result.stdout.trim()).toBe("dev");
88
92
  });
89
93
 
94
+ /** Varargs trailing option after positionals via Cli.invoke. */
90
95
  test("varargs trailing option after positionals via Cli.invoke", async () => {
91
96
  const root = varargsReadFixture();
92
97
  cliValidateProgram(root);
@@ -96,6 +101,7 @@ test("varargs trailing option after positionals via Cli.invoke", async () => {
96
101
  expect(pr.opts.json).toBe("1");
97
102
  });
98
103
 
104
+ /** Varargs option before positionals. */
99
105
  test("varargs option before positionals", () => {
100
106
  const root = varargsReadFixture();
101
107
  cliValidateProgram(root);
@@ -105,6 +111,7 @@ test("varargs option before positionals", () => {
105
111
  expect(pr.opts.json).toBe("1");
106
112
  });
107
113
 
114
+ /** Varargs multiple files then trailing option. */
108
115
  test("varargs multiple files then trailing option", () => {
109
116
  const root = varargsReadFixture();
110
117
  cliValidateProgram(root);
@@ -114,6 +121,7 @@ test("varargs multiple files then trailing option", () => {
114
121
  expect(pr.opts.json).toBe("1");
115
122
  });
116
123
 
124
+ /** Varargs double dash forces positional. */
117
125
  test("varargs double dash forces positional", () => {
118
126
  const root = varargsReadFixture();
119
127
  cliValidateProgram(root);
@@ -123,6 +131,7 @@ test("varargs double dash forces positional", () => {
123
131
  expect(pr.opts.json).toBeUndefined();
124
132
  });
125
133
 
134
+ /** Varargs unknown flag errors. */
126
135
  test("varargs unknown flag errors", async () => {
127
136
  const root = varargsReadFixture();
128
137
  cliValidateProgram(root);
@@ -131,6 +140,7 @@ test("varargs unknown flag errors", async () => {
131
140
  expect(result.stderr).toContain("--unknown");
132
141
  });
133
142
 
143
+ /** Varargs scoped help in tail. */
134
144
  test("varargs scoped help in tail", () => {
135
145
  const root = varargsReadFixture();
136
146
  cliValidateProgram(root);
@@ -140,6 +150,7 @@ test("varargs scoped help in tail", () => {
140
150
  expect(pr.helpExplicit).toBe(true);
141
151
  });
142
152
 
153
+ /** Tests that ctx.positional returns single slot value. */
143
154
  test("ctx.positional returns single slot value", async () => {
144
155
  const root = testProgram({
145
156
  key: "app",
@@ -161,6 +172,7 @@ test("ctx.positional returns single slot value", async () => {
161
172
  expect(captured).toBe("./file");
162
173
  });
163
174
 
175
+ /** Tests that ctx.positional returns varargs array. */
164
176
  test("ctx.positional returns varargs array", async () => {
165
177
  const root = varargsReadFixture();
166
178
  let captured: string | string[] | undefined;
@@ -174,6 +186,7 @@ test("ctx.positional returns varargs array", async () => {
174
186
  expect(captured).toEqual(["a.txt", "b.txt"]);
175
187
  });
176
188
 
189
+ /** Tests that ctx.positional returns undefined for absent optional slot. */
177
190
  test("ctx.positional returns undefined for absent optional slot", async () => {
178
191
  const root = testProgram({
179
192
  key: "app",
@@ -197,6 +210,7 @@ test("ctx.positional returns undefined for absent optional slot", async () => {
197
210
  expect(captured).toBeUndefined();
198
211
  });
199
212
 
213
+ /** Tests that ctx.positional varargs matches ctx.args. */
200
214
  test("ctx.positional varargs matches ctx.args", async () => {
201
215
  const root = varargsReadFixture();
202
216
  let positional: string | string[] | undefined;
@@ -1,3 +1,7 @@
1
+ /*
2
+ Tests for mcp/claude module behavior.
3
+ */
4
+
1
5
  import { describe, expect, test } from "bun:test";
2
6
  import { execSync } from "node:child_process";
3
7
  import { mkdirSync, mkdtempSync, readFileSync, rmSync, statSync, writeFileSync } from "node:fs";
@@ -29,11 +33,14 @@ const configFixture: CliProgram = {
29
33
  commands: [{ key: "run", description: "Run.", handler: () => {} }],
30
34
  };
31
35
 
36
+ /** Tests for claude plugin. */
32
37
  describe("claude plugin", () => {
38
+ /** PluginName is kebab-case. */
33
39
  test("pluginName is kebab-case", () => {
34
40
  expect(pluginName({ ...configFixture, key: "MyApp" })).toBe("my-app");
35
41
  });
36
42
 
43
+ /** Tests that generatePluginManifest includes userConfig from program.appConfig. */
37
44
  test("generatePluginManifest includes userConfig from program.appConfig", () => {
38
45
  const manifest = generatePluginManifest(configFixture, "myapp");
39
46
  expect(manifest.name).toBe("myapp");
@@ -43,6 +50,7 @@ describe("claude plugin", () => {
43
50
  expect(userConfig.api_token?.sensitive).toBe(true);
44
51
  });
45
52
 
53
+ /** Tests that generatePluginMcpJson uses CLAUDE_PLUGIN_ROOT and env mapping. */
46
54
  test("generatePluginMcpJson uses CLAUDE_PLUGIN_ROOT and env mapping", () => {
47
55
  const json = generatePluginMcpJson(configFixture, "myapp");
48
56
  const entry = json.myapp as { command: string; args: string[]; env: Record<string, string> };
@@ -51,12 +59,14 @@ describe("claude plugin", () => {
51
59
  expect(entry.env.API_TOKEN).toBe("${user_config.api_token}");
52
60
  });
53
61
 
62
+ /** DefaultClaudePluginPaths. */
54
63
  test("defaultClaudePluginPaths", () => {
55
64
  const cwd = "/tmp/work";
56
65
  const paths = defaultClaudePluginPaths(configFixture, cwd);
57
66
  expect(paths.pluginZipPath).toBe(join(cwd, "dist", "claude-plugin", "myapp.zip"));
58
67
  });
59
68
 
69
+ /** Tests that packClaudePlugin writes zip with MCP pointer skill only. */
60
70
  test("packClaudePlugin writes zip with MCP pointer skill only", () => {
61
71
  const work = mkdtempSync(join(tmpdir(), "claude-plugin-test-"));
62
72
  try {
@@ -1,3 +1,7 @@
1
+ /*
2
+ Tests for mcp/env module behavior.
3
+ */
4
+
1
5
  import { afterEach, beforeEach, describe, expect, test } from "bun:test";
2
6
  import { chmodSync, mkdtempSync, writeFileSync } from "node:fs";
3
7
  import { tmpdir } from "node:os";
@@ -6,7 +10,9 @@ import { applyShellEnv, bootstrapMcpEnv } from "./env.ts";
6
10
 
7
11
  const TEST_VAR = "ARGS_BARG_SHELL_ENV_TEST";
8
12
 
13
+ /** Tests for mcp/env. */
9
14
  describe("mcp/env", () => {
15
+ /** ApplyShellEnv merges PATH and fills missing vars. */
10
16
  test("applyShellEnv merges PATH and fills missing vars", () => {
11
17
  const prevPath = process.env.PATH;
12
18
  const prevTest = process.env[TEST_VAR];
@@ -27,6 +33,7 @@ describe("mcp/env", () => {
27
33
  }
28
34
  });
29
35
 
36
+ /** ApplyShellEnv does not overwrite host vars except PATH merge. */
30
37
  test("applyShellEnv does not overwrite host vars except PATH merge", () => {
31
38
  const prev = process.env.HOME;
32
39
  process.env.HOME = "/host/home";
@@ -40,6 +47,7 @@ describe("mcp/env", () => {
40
47
  });
41
48
  });
42
49
 
50
+ /** Tests for bootstrapMcpEnv. */
43
51
  describe("bootstrapMcpEnv", () => {
44
52
  let fakeShell: string;
45
53
  let prevShell: string | undefined;
@@ -70,21 +78,25 @@ fi
70
78
  else process.env[TEST_VAR] = prevTest;
71
79
  });
72
80
 
81
+ /** Defaults on when shellEnv is undefined. */
73
82
  test("defaults on when shellEnv is undefined", () => {
74
83
  bootstrapMcpEnv({});
75
84
  expect(process.env[TEST_VAR]).toBe("from_fake_shell");
76
85
  });
77
86
 
87
+ /** Runs when shellEnv is true. */
78
88
  test("runs when shellEnv is true", () => {
79
89
  bootstrapMcpEnv({ shellEnv: true });
80
90
  expect(process.env[TEST_VAR]).toBe("from_fake_shell");
81
91
  });
82
92
 
93
+ /** Tests that uses explicit shell path when shellEnv is a string. */
83
94
  test("uses explicit shell path when shellEnv is a string", () => {
84
95
  bootstrapMcpEnv({ shellEnv: fakeShell });
85
96
  expect(process.env[TEST_VAR]).toBe("from_fake_shell");
86
97
  });
87
98
 
99
+ /** Tests that skips capture when shellEnv is false. */
88
100
  test("skips capture when shellEnv is false", () => {
89
101
  bootstrapMcpEnv({ shellEnv: false });
90
102
  expect(process.env[TEST_VAR]).toBeUndefined();
package/src/mcp/tools.ts CHANGED
@@ -224,7 +224,7 @@ export function collectMcpTools(root: CliProgram): McpToolDef[] {
224
224
  if (isCliLeaf(cmd)) {
225
225
  if (
226
226
  cmd.key === "completion" ||
227
- cmd.key === "install" ||
227
+ cmd.key === "configure" ||
228
228
  cmd.key === "mcp" ||
229
229
  cmd.key === "version"
230
230
  ) {
@@ -1,3 +1,7 @@
1
+ /*
2
+ Tests for mcp/zip module behavior.
3
+ */
4
+
1
5
  import { expect, test } from "bun:test";
2
6
  import { execSync } from "node:child_process";
3
7
  import { mkdtempSync, readFileSync, statSync, writeFileSync } from "node:fs";
@@ -5,6 +9,7 @@ import { tmpdir } from "node:os";
5
9
  import { join } from "node:path";
6
10
  import { zipStore } from "./zip.ts";
7
11
 
12
+ /** ZipStore preserves unix executable mode on extract. */
8
13
  test("zipStore preserves unix executable mode on extract", () => {
9
14
  const work = mkdtempSync(join(tmpdir(), "zip-exec-"));
10
15
  const data = Buffer.from("#!/bin/sh\necho hi\n");