argsbarg 5.0.2 → 5.0.3

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.
@@ -12,7 +12,6 @@ import {
12
12
  } from "./formats.ts";
13
13
  import { CliValueFormat } from "./types.ts";
14
14
 
15
- /** ParseDurationMs parses minutes and hours. */
16
15
  test("parseDurationMs parses minutes and hours", () => {
17
16
  expect(parseDurationMs("30s")).toBe(30_000);
18
17
  expect(parseDurationMs("5m")).toBe(5 * 60 * 1000);
@@ -20,25 +19,21 @@ test("parseDurationMs parses minutes and hours", () => {
20
19
  expect(parseDurationMs("1d")).toBe(24 * 60 * 60 * 1000);
21
20
  });
22
21
 
23
- /** ParseCommaList splits and trims. */
24
22
  test("parseCommaList splits and trims", () => {
25
23
  expect(parseCommaList("a,b")).toEqual(["a", "b"]);
26
24
  expect(parseCommaList(" a , b , ")).toEqual(["a", "b"]);
27
25
  });
28
26
 
29
- /** ParseDate validates calendar dates. */
30
27
  test("parseDate validates calendar dates", () => {
31
28
  expect(parseDate("2026-06-22")).toBe("2026-06-22");
32
29
  expect(() => parseDate("2026-02-30")).toThrow();
33
30
  });
34
31
 
35
- /** ParseDateTime normalizes to UTC ISO. */
36
32
  test("parseDateTime normalizes to UTC ISO", () => {
37
33
  expect(parseDateTime("2026-06-22T15:00:00Z")).toBe("2026-06-22T15:00:00.000Z");
38
34
  expect(() => parseDateTime("2026-06-22")).toThrow();
39
35
  });
40
36
 
41
- /** ValidateFormatValue rejects invalid duration. */
42
37
  test("validateFormatValue rejects invalid duration", () => {
43
38
  expect(() => validateFormatValue("nope", CliValueFormat.Duration)).toThrow();
44
39
  });
@@ -12,14 +12,12 @@ import {
12
12
  wantsExplicitJson,
13
13
  } from "./headless.ts";
14
14
 
15
- /** WantsExplicitJson includes MCP invocation. */
16
15
  test("wantsExplicitJson includes MCP invocation", () => {
17
16
  expect(wantsExplicitJson({ invocation: "cli" }, false)).toBe(false);
18
17
  expect(wantsExplicitJson({ invocation: "mcp" }, false)).toBe(true);
19
18
  expect(wantsExplicitJson({ invocation: "cli" }, true)).toBe(true);
20
19
  });
21
20
 
22
- /** Tests that shouldRunHeadless is true for MCP and json. */
23
21
  test("shouldRunHeadless is true for MCP and json", () => {
24
22
  expect(shouldRunHeadless({ invocation: "mcp" }, false)).toBe(true);
25
23
  expect(shouldRunHeadless({ invocation: "cli" }, true)).toBe(true);
@@ -27,7 +25,6 @@ test("shouldRunHeadless is true for MCP and json", () => {
27
25
  expect(shouldRunHeadless({ invocation: "cli" }, false, false, false)).toBe(true);
28
26
  });
29
27
 
30
- /** Tests that shouldRunHeadlessWithPositionals requires positionals in non-tty. */
31
28
  test("shouldRunHeadlessWithPositionals requires positionals in non-tty", () => {
32
29
  expect(shouldRunHeadlessWithPositionals({ invocation: "cli" }, false, [], false, false)).toBe(
33
30
  false,
@@ -54,7 +51,6 @@ test("shouldRunHeadlessWithYes requires yes in non-tty", () => {
54
51
  ).toBe(true);
55
52
  });
56
53
 
57
- /** Tests that formatDryRunMessage prefixes dry-run output. */
58
54
  test("formatDryRunMessage prefixes dry-run output", () => {
59
55
  expect(formatDryRunMessage("hello", false)).toBe("hello");
60
56
  expect(formatDryRunMessage("hello", true)).toBe("[DRY RUN] hello");
package/src/headless.ts CHANGED
@@ -57,14 +57,15 @@ export function shouldRunHeadlessWithYes(
57
57
  return opts.yes && opts.hasRequiredArgs;
58
58
  }
59
59
 
60
- /**
61
- * Exits when non-interactive mode is used without `--yes`.
62
- * @param hint - Command-specific guidance appended to the error
63
- */
60
+ /** Exits when non-interactive mode is used without `--yes`. */
64
61
  export function requireYesInNonTty(
62
+ /** True when `--yes` was passed on the command line. */
65
63
  yes: boolean,
64
+ /** Command-specific guidance appended to the error message. */
66
65
  hint: string,
66
+ /** When true, skip the check (dry-run preview). */
67
67
  dryRun = false,
68
+ /** Injectable TTY probe for tests. */
68
69
  interactive: boolean = isInteractiveTty,
69
70
  ): void {
70
71
  if (dryRun) return;
@@ -59,13 +59,11 @@ const hiddenFixture: CliProgram = {
59
59
 
60
60
  /** Tests for hidden commands and options. */
61
61
  describe("hidden commands and options", () => {
62
- /** Parse root includes hidden commands. */
63
62
  test("parse root includes hidden commands", () => {
64
63
  const parse = cliParseRoot(hiddenFixture);
65
64
  expect(parse.commands?.map((c) => c.key)).toContain("secret");
66
65
  });
67
66
 
68
- /** Presentation root omits hidden commands. */
69
67
  test("presentation root omits hidden commands", () => {
70
68
  const presentation = cliPresentationRoot(hiddenFixture);
71
69
  const keys = presentation.commands?.map((c) => c.key) ?? [];
@@ -73,27 +71,23 @@ describe("hidden commands and options", () => {
73
71
  expect(keys).not.toContain("secret");
74
72
  });
75
73
 
76
- /** Root help omits hidden commands. */
77
74
  test("root help omits hidden commands", () => {
78
75
  const help = cliHelpRender(cliParseRoot(hiddenFixture), [], false);
79
76
  expect(help).toContain("public");
80
77
  expect(help).not.toContain("secret");
81
78
  });
82
79
 
83
- /** Hidden command -h still works. */
84
80
  test("hidden command -h still works", () => {
85
81
  const help = cliHelpRender(cliParseRoot(hiddenFixture), ["secret"], false);
86
82
  expect(help).toContain("Hidden command.");
87
83
  });
88
84
 
89
- /** Tests that help omits hidden options. */
90
85
  test("help omits hidden options", () => {
91
86
  const help = cliHelpRender(cliParseRoot(hiddenFixture), ["flags"], false);
92
87
  expect(help).toContain("--visible");
93
88
  expect(help).not.toContain("secret-flag");
94
89
  });
95
90
 
96
- /** Tests that schema export omits hidden nodes and options. */
97
91
  test("schema export omits hidden nodes and options", () => {
98
92
  const schema = cliSchemaExport(hiddenFixture);
99
93
  const keys = schema.commands?.map((c) => c.key) ?? [];
@@ -103,7 +97,6 @@ describe("hidden commands and options", () => {
103
97
  expect(flags?.options?.map((o) => o.name)).toEqual(["visible"]);
104
98
  });
105
99
 
106
- /** MCP tools omit hidden commands. */
107
100
  test("MCP tools omit hidden commands", () => {
108
101
  const tools = collectMcpTools(hiddenFixture);
109
102
  expect(tools.map((t) => t.name)).toEqual(["public", "flags"]);
@@ -112,7 +105,6 @@ describe("hidden commands and options", () => {
112
105
 
113
106
  /** Tests for mcp router. */
114
107
  describe("mcp router", () => {
115
- /** Presentation exposes mcp bundle but not hidden serve. */
116
108
  test("presentation exposes mcp bundle but not hidden serve", () => {
117
109
  const builtins = exportPresentationBuiltins(hiddenFixture);
118
110
  const mcp = builtins.find((b) => b.key === "mcp");
@@ -121,7 +113,6 @@ describe("mcp router", () => {
121
113
  expect(mcp?.fallbackCommand).toBe("serve");
122
114
  });
123
115
 
124
- /** Mcp help lists bundle. */
125
116
  test("mcp help lists bundle", () => {
126
117
  const help = cliHelpRender(cliParseRoot(hiddenFixture), ["mcp"], false);
127
118
  expect(help).toContain("bundle");
@@ -131,7 +122,6 @@ describe("mcp router", () => {
131
122
 
132
123
  /** Tests for mcp bundle. */
133
124
  describe("mcp bundle", () => {
134
- /** Tests that generateMcpManifest uses mcpServerId and binary entry. */
135
125
  test("generateMcpManifest uses mcpServerId and binary entry", () => {
136
126
  const manifest = generateMcpManifest(hiddenFixture, "myapp");
137
127
  expect(manifest.name).toBe("myapp");
@@ -145,7 +135,6 @@ describe("mcp bundle", () => {
145
135
  expect((manifest.compatibility as { platforms: string[] }).platforms).toEqual(["darwin"]);
146
136
  });
147
137
 
148
- /** DefaultMcpBundlePaths. */
149
138
  test("defaultMcpBundlePaths", () => {
150
139
  const cwd = "/tmp/work";
151
140
  const paths = defaultMcpBundlePaths(hiddenFixture, cwd);
@@ -241,7 +230,6 @@ describe("mcp bundle", () => {
241
230
  }
242
231
  });
243
232
 
244
- /** RunMcpBundle errors when no bundle flags enabled. */
245
233
  test("runMcpBundle errors when no bundle flags enabled", () => {
246
234
  const fixture: CliProgram = {
247
235
  ...hiddenFixture,
@@ -36,13 +36,11 @@ afterEach(() => {
36
36
 
37
37
  /** Tests for isExternallyManagedBinary. */
38
38
  describe("isExternallyManagedBinary", () => {
39
- /** Tests that false when command is not on PATH. */
40
39
  test("false when command is not on PATH", () => {
41
40
  process.env.PATH = tmp;
42
41
  expect(isExternallyManagedBinary("placementapp-not-on-path")).toBe(false);
43
42
  });
44
43
 
45
- /** Tests that true when PATH resolves to execPath. */
46
44
  test("true when PATH resolves to execPath", () => {
47
45
  const bin = join(tmp, "placementapp");
48
46
  writeFileSync(bin, "#!/bin/sh\n", "utf8");
@@ -51,7 +49,6 @@ describe("isExternallyManagedBinary", () => {
51
49
  expect(isExternallyManagedBinary("placementapp", bin)).toBe(true);
52
50
  });
53
51
 
54
- /** Tests that true when PATH entry is a symlink to execPath. */
55
52
  test("true when PATH entry is a symlink to execPath", () => {
56
53
  const bin = join(tmp, "placementapp");
57
54
  const target = join(tmp, "real-binary");
@@ -61,7 +58,6 @@ describe("isExternallyManagedBinary", () => {
61
58
  expect(isExternallyManagedBinary("placementapp", target)).toBe(true);
62
59
  });
63
60
 
64
- /** Tests that false when PATH points at a different binary. */
65
61
  test("false when PATH points at a different binary", () => {
66
62
  const bin = join(tmp, "placementapp");
67
63
  const other = join(tmp, "other");
@@ -107,7 +103,6 @@ describe("isAppInstalled", () => {
107
103
 
108
104
  /** Tests for resolvePathCommand. */
109
105
  describe("resolvePathCommand", () => {
110
- /** Tests that returns undefined when missing. */
111
106
  test("returns undefined when missing", () => {
112
107
  process.env.PATH = tmp;
113
108
  expect(resolvePathCommand("missing-cmd")).toBeUndefined();
@@ -5,27 +5,22 @@ Tests for install/gh-release-update module behavior.
5
5
  import { expect, test } from "bun:test";
6
6
  import { isAlreadyCurrent, parseReleaseTag } from "./gh-release-update.ts";
7
7
 
8
- /** ParseReleaseTag strips leading v. */
9
8
  test("parseReleaseTag strips leading v", () => {
10
9
  expect(parseReleaseTag("v1.4.3")).toBe("1.4.3");
11
10
  });
12
11
 
13
- /** ParseReleaseTag leaves bare semver unchanged. */
14
12
  test("parseReleaseTag leaves bare semver unchanged", () => {
15
13
  expect(parseReleaseTag("1.4.3")).toBe("1.4.3");
16
14
  });
17
15
 
18
- /** ParseReleaseTag throws on empty tag. */
19
16
  test("parseReleaseTag throws on empty tag", () => {
20
17
  expect(() => parseReleaseTag("")).toThrow("Release tag is empty");
21
18
  });
22
19
 
23
- /** Tests that isAlreadyCurrent returns true when versions match. */
24
20
  test("isAlreadyCurrent returns true when versions match", () => {
25
21
  expect(isAlreadyCurrent("1.4.3", "1.4.3")).toBe(true);
26
22
  });
27
23
 
28
- /** Tests that isAlreadyCurrent returns false when versions differ. */
29
24
  test("isAlreadyCurrent returns false when versions differ", () => {
30
25
  expect(isAlreadyCurrent("1.4.2", "1.4.3")).toBe(false);
31
26
  });
@@ -16,12 +16,10 @@ const base: CliProgram = {
16
16
 
17
17
  /** Tests for validateConfigureConfig. */
18
18
  describe("validateConfigureConfig", () => {
19
- /** Tests that accepts empty install config. */
20
19
  test("accepts empty install config", () => {
21
20
  expect(() => cliValidateProgram(base)).not.toThrow();
22
21
  });
23
22
 
24
- /** Rejects removed allSkills shorthand. */
25
23
  test("rejects removed allSkills shorthand", () => {
26
24
  const program = {
27
25
  ...base,
@@ -31,7 +29,6 @@ describe("validateConfigureConfig", () => {
31
29
  expect(() => cliValidateProgram(program)).toThrow(/allSkills/);
32
30
  });
33
31
 
34
- /** Rejects both sides of pair without both integration. */
35
32
  test("rejects both sides of pair without both integration", () => {
36
33
  const program: CliProgram = {
37
34
  ...base,
@@ -44,7 +41,6 @@ describe("validateConfigureConfig", () => {
44
41
  expect(() => cliValidateProgram(program)).toThrow(/both/);
45
42
  });
46
43
 
47
- /** Rejects explicit MCP target in skill integration mode. */
48
44
  test("rejects explicit MCP target in skill integration mode", () => {
49
45
  const program: CliProgram = {
50
46
  ...base,
@@ -56,7 +52,6 @@ describe("validateConfigureConfig", () => {
56
52
  expect(() => cliValidateProgram(program)).toThrow(/cursorMcp/);
57
53
  });
58
54
 
59
- /** Allows explicit pair targets with both integration. */
60
55
  test("allows explicit pair targets with both integration", () => {
61
56
  const program: CliProgram = {
62
57
  ...base,
@@ -47,7 +47,6 @@ afterEach(() => {
47
47
 
48
48
  /** Tests for opencode mcp config. */
49
49
  describe("opencode mcp config", () => {
50
- /** ResolveOpenCodeConfigPathForInstall prefers existing file. */
51
50
  test("resolveOpenCodeConfigPathForInstall prefers existing file", () => {
52
51
  const dir = opencodeConfigDir(home);
53
52
  mkdirSync(dir, { recursive: true });
@@ -56,7 +55,6 @@ describe("opencode mcp config", () => {
56
55
  expect(resolveOpenCodeConfigPathForInstall(home)).toBe(existing);
57
56
  });
58
57
 
59
- /** ResolveOpenCodeConfigPathForInstall defaults to config.json. */
60
58
  test("resolveOpenCodeConfigPathForInstall defaults to config.json", () => {
61
59
  mkdirSync(opencodeConfigDir(home), { recursive: true });
62
60
  expect(resolveOpenCodeConfigPathForInstall(home)).toBe(
@@ -64,7 +62,6 @@ describe("opencode mcp config", () => {
64
62
  );
65
63
  });
66
64
 
67
- /** MergeOpenCodeMcpConfig writes mcp block. */
68
65
  test("mergeOpenCodeMcpConfig writes mcp block", () => {
69
66
  const path = resolveOpenCodeConfigPathForInstall(home);
70
67
  mkdirSync(opencodeConfigDir(home), { recursive: true });
@@ -95,7 +92,6 @@ describe("opencode mcp config", () => {
95
92
  expect(detectOpenCodeMcpConfigPath(home, "testapp")).toBe(path);
96
93
  });
97
94
 
98
- /** RemoveOpenCodeMcpConfig deletes server entry. */
99
95
  test("removeOpenCodeMcpConfig deletes server entry", () => {
100
96
  const path = resolveOpenCodeConfigPathForInstall(home);
101
97
  mkdirSync(opencodeConfigDir(home), { recursive: true });
@@ -11,12 +11,10 @@ import { isArtifactInScope } from "./target-scope.ts";
11
11
 
12
12
  /** Tests for normalizeInstallRawOpts. */
13
13
  describe("normalizeInstallRawOpts", () => {
14
- /** Bare install sets all. */
15
14
  test("bare install sets all", () => {
16
15
  expect(normalizeInstallRawOpts({})).toEqual({ all: "1" });
17
16
  });
18
17
 
19
- /** Bare uninstall sets all. */
20
18
  test("bare uninstall sets all", () => {
21
19
  expect(normalizeUninstallRawOpts({})).toEqual({
22
20
  uninstall: "1",
@@ -24,7 +22,6 @@ describe("normalizeInstallRawOpts", () => {
24
22
  });
25
23
  });
26
24
 
27
- /** Configure-only install unchanged. */
28
25
  test("configure-only install unchanged", () => {
29
26
  expect(normalizeInstallRawOpts({ configure: "1" })).toEqual({ configure: "1" });
30
27
  });
@@ -32,12 +29,10 @@ describe("normalizeInstallRawOpts", () => {
32
29
 
33
30
  /** Tests for resolveAgentIntegration. */
34
31
  describe("resolveAgentIntegration", () => {
35
- /** Defaults to skill without MCP. */
36
32
  test("defaults to skill without MCP", () => {
37
33
  expect(resolveAgentIntegration(undefined, false)).toBe("skill");
38
34
  });
39
35
 
40
- /** Defaults to mcp when MCP enabled. */
41
36
  test("defaults to mcp when MCP enabled", () => {
42
37
  expect(resolveAgentIntegration(undefined, true)).toBe("mcp");
43
38
  });
@@ -45,14 +40,12 @@ describe("resolveAgentIntegration", () => {
45
40
 
46
41
  /** Tests for resolveEffectiveInstallTargets. */
47
42
  describe("resolveEffectiveInstallTargets", () => {
48
- /** Defaults app and configure not in --all. */
49
43
  test("defaults app and configure not in --all", () => {
50
44
  const t = resolveEffectiveInstallTargets(undefined);
51
45
  expect(t.app.includedInAll).toBe(false);
52
46
  expect(t.configure.includedInAll).toBe(false);
53
47
  });
54
48
 
55
- /** Skill mode includes skills in --all not MCP pairs. */
56
49
  test("skill mode includes skills in --all not MCP pairs", () => {
57
50
  const program: Pick<CliProgram, "mcpServer"> = {};
58
51
  const t = resolveEffectiveInstallTargets(undefined, program);
@@ -60,7 +53,6 @@ describe("resolveEffectiveInstallTargets", () => {
60
53
  expect(t.cursorMcp.includedInAll).toBe(false);
61
54
  });
62
55
 
63
- /** Mcp mode includes MCP in --all not paired skills. */
64
56
  test("mcp mode includes MCP in --all not paired skills", () => {
65
57
  const program: Pick<CliProgram, "mcpServer"> = { mcpServer: { enabled: true } };
66
58
  const t = resolveEffectiveInstallTargets(undefined, program);
@@ -69,7 +61,6 @@ describe("resolveEffectiveInstallTargets", () => {
69
61
  expect(t.claudeDesktopMcp.includedInAll).toBe(true);
70
62
  });
71
63
 
72
- /** Tests that both mode includes MCP and skills. */
73
64
  test("both mode includes MCP and skills", () => {
74
65
  const program: Pick<CliProgram, "mcpServer"> = { mcpServer: { enabled: true } };
75
66
  const t = resolveEffectiveInstallTargets({ agentIntegration: "both" }, program);
@@ -77,7 +68,6 @@ describe("resolveEffectiveInstallTargets", () => {
77
68
  expect(t.cursorSkill.includedInAll).toBe(true);
78
69
  });
79
70
 
80
- /** Tests that per-key override disables one skill. */
81
71
  test("per-key override disables one skill", () => {
82
72
  const t = resolveEffectiveInstallTargets({
83
73
  targets: { cursorSkill: false },
@@ -91,7 +91,6 @@ test("Cli.invoke accepts valid Enum value", async () => {
91
91
  expect(result.stdout.trim()).toBe("dev");
92
92
  });
93
93
 
94
- /** Varargs trailing option after positionals via Cli.invoke. */
95
94
  test("varargs trailing option after positionals via Cli.invoke", async () => {
96
95
  const root = varargsReadFixture();
97
96
  cliValidateProgram(root);
@@ -101,7 +100,6 @@ test("varargs trailing option after positionals via Cli.invoke", async () => {
101
100
  expect(pr.opts.json).toBe("1");
102
101
  });
103
102
 
104
- /** Varargs option before positionals. */
105
103
  test("varargs option before positionals", () => {
106
104
  const root = varargsReadFixture();
107
105
  cliValidateProgram(root);
@@ -111,7 +109,6 @@ test("varargs option before positionals", () => {
111
109
  expect(pr.opts.json).toBe("1");
112
110
  });
113
111
 
114
- /** Varargs multiple files then trailing option. */
115
112
  test("varargs multiple files then trailing option", () => {
116
113
  const root = varargsReadFixture();
117
114
  cliValidateProgram(root);
@@ -121,7 +118,6 @@ test("varargs multiple files then trailing option", () => {
121
118
  expect(pr.opts.json).toBe("1");
122
119
  });
123
120
 
124
- /** Varargs double dash forces positional. */
125
121
  test("varargs double dash forces positional", () => {
126
122
  const root = varargsReadFixture();
127
123
  cliValidateProgram(root);
@@ -131,7 +127,6 @@ test("varargs double dash forces positional", () => {
131
127
  expect(pr.opts.json).toBeUndefined();
132
128
  });
133
129
 
134
- /** Varargs unknown flag errors. */
135
130
  test("varargs unknown flag errors", async () => {
136
131
  const root = varargsReadFixture();
137
132
  cliValidateProgram(root);
@@ -140,7 +135,6 @@ test("varargs unknown flag errors", async () => {
140
135
  expect(result.stderr).toContain("--unknown");
141
136
  });
142
137
 
143
- /** Varargs scoped help in tail. */
144
138
  test("varargs scoped help in tail", () => {
145
139
  const root = varargsReadFixture();
146
140
  cliValidateProgram(root);
@@ -172,7 +166,6 @@ test("ctx.positional returns single slot value", async () => {
172
166
  expect(captured).toBe("./file");
173
167
  });
174
168
 
175
- /** Tests that ctx.positional returns varargs array. */
176
169
  test("ctx.positional returns varargs array", async () => {
177
170
  const root = varargsReadFixture();
178
171
  let captured: string | string[] | undefined;
@@ -35,12 +35,10 @@ const configFixture: CliProgram = {
35
35
 
36
36
  /** Tests for claude plugin. */
37
37
  describe("claude plugin", () => {
38
- /** PluginName is kebab-case. */
39
38
  test("pluginName is kebab-case", () => {
40
39
  expect(pluginName({ ...configFixture, key: "MyApp" })).toBe("my-app");
41
40
  });
42
41
 
43
- /** Tests that generatePluginManifest includes userConfig from program.appConfig. */
44
42
  test("generatePluginManifest includes userConfig from program.appConfig", () => {
45
43
  const manifest = generatePluginManifest(configFixture, "myapp");
46
44
  expect(manifest.name).toBe("myapp");
@@ -50,7 +48,6 @@ describe("claude plugin", () => {
50
48
  expect(userConfig.api_token?.sensitive).toBe(true);
51
49
  });
52
50
 
53
- /** Tests that generatePluginMcpJson uses CLAUDE_PLUGIN_ROOT and env mapping. */
54
51
  test("generatePluginMcpJson uses CLAUDE_PLUGIN_ROOT and env mapping", () => {
55
52
  const json = generatePluginMcpJson(configFixture, "myapp");
56
53
  const entry = json.myapp as { command: string; args: string[]; env: Record<string, string> };
@@ -59,7 +56,6 @@ describe("claude plugin", () => {
59
56
  expect(entry.env.API_TOKEN).toBe("${user_config.api_token}");
60
57
  });
61
58
 
62
- /** DefaultClaudePluginPaths. */
63
59
  test("defaultClaudePluginPaths", () => {
64
60
  const cwd = "/tmp/work";
65
61
  const paths = defaultClaudePluginPaths(configFixture, cwd);
@@ -33,7 +33,6 @@ describe("mcp/env", () => {
33
33
  }
34
34
  });
35
35
 
36
- /** ApplyShellEnv does not overwrite host vars except PATH merge. */
37
36
  test("applyShellEnv does not overwrite host vars except PATH merge", () => {
38
37
  const prev = process.env.HOME;
39
38
  process.env.HOME = "/host/home";
@@ -78,25 +77,21 @@ fi
78
77
  else process.env[TEST_VAR] = prevTest;
79
78
  });
80
79
 
81
- /** Defaults on when shellEnv is undefined. */
82
80
  test("defaults on when shellEnv is undefined", () => {
83
81
  bootstrapMcpEnv({});
84
82
  expect(process.env[TEST_VAR]).toBe("from_fake_shell");
85
83
  });
86
84
 
87
- /** Runs when shellEnv is true. */
88
85
  test("runs when shellEnv is true", () => {
89
86
  bootstrapMcpEnv({ shellEnv: true });
90
87
  expect(process.env[TEST_VAR]).toBe("from_fake_shell");
91
88
  });
92
89
 
93
- /** Tests that uses explicit shell path when shellEnv is a string. */
94
90
  test("uses explicit shell path when shellEnv is a string", () => {
95
91
  bootstrapMcpEnv({ shellEnv: fakeShell });
96
92
  expect(process.env[TEST_VAR]).toBe("from_fake_shell");
97
93
  });
98
94
 
99
- /** Tests that skips capture when shellEnv is false. */
100
95
  test("skips capture when shellEnv is false", () => {
101
96
  bootstrapMcpEnv({ shellEnv: false });
102
97
  expect(process.env[TEST_VAR]).toBeUndefined();
@@ -9,7 +9,6 @@ import { tmpdir } from "node:os";
9
9
  import { join } from "node:path";
10
10
  import { zipStore } from "./zip.ts";
11
11
 
12
- /** ZipStore preserves unix executable mode on extract. */
13
12
  test("zipStore preserves unix executable mode on extract", () => {
14
13
  const work = mkdtempSync(join(tmpdir(), "zip-exec-"));
15
14
  const data = Buffer.from("#!/bin/sh\necho hi\n");
@@ -17,12 +17,10 @@ import { cliSchemaExport } from "./schema.ts";
17
17
  import { mcpRequest, nestedMcpFixture, testProgram } from "./test-fixtures.ts";
18
18
  import { cliValidateProgram } from "./validate.ts";
19
19
 
20
- /** Tests that sanitizeToolSegment normalizes dotted app keys. */
21
20
  test("sanitizeToolSegment normalizes dotted app keys", () => {
22
21
  expect(sanitizeToolSegment("minimal.ts")).toBe("minimal_ts");
23
22
  });
24
23
 
25
- /** McpToolDescription formats CLI path and root-leaf prefix. */
26
24
  test("mcpToolDescription formats CLI path and root-leaf prefix", () => {
27
25
  expect(mcpToolDescription(["stat", "owner", "lookup"], "nested.ts", "Resolve owner info.")).toBe(
28
26
  "stat owner lookup — Resolve owner info.",
@@ -31,7 +29,6 @@ test("mcpToolDescription formats CLI path and root-leaf prefix", () => {
31
29
  expect(mcpToolDescription([], "helloapp", "Tiny demo.")).toBe("helloapp — Tiny demo.");
32
30
  });
33
31
 
34
- /** Tests that collectMcpTools lists user leaf commands only. */
35
32
  test("collectMcpTools lists user leaf commands only", () => {
36
33
  const tools = collectMcpTools(nestedMcpFixture);
37
34
  const names = tools.map((t) => t.name);
@@ -192,7 +189,6 @@ test("outputSchema cannot be set on both leaf and mcpTool", () => {
192
189
  expect(() => cliValidateProgram(root)).toThrow(/Set outputSchema on the leaf only/);
193
190
  });
194
191
 
195
- /** Tests that collectMcpTools merges parent options into inputSchema. */
196
192
  test("collectMcpTools merges parent options into inputSchema", () => {
197
193
  const tools = collectMcpTools(nestedMcpFixture);
198
194
  const lookup = tools.find((t) => t.name === "stat_owner_lookup")!;
@@ -230,14 +226,12 @@ test("collectMcpTools includes outputSchema when set on leaf", () => {
230
226
  });
231
227
  });
232
228
 
233
- /** Tests that collectMcpTools omits outputSchema when leaf has none. */
234
229
  test("collectMcpTools omits outputSchema when leaf has none", () => {
235
230
  const tools = collectMcpTools(nestedMcpFixture);
236
231
  const lookup = tools.find((t) => t.name === "stat_owner_lookup")!;
237
232
  expect(lookup.outputSchema).toBeUndefined();
238
233
  });
239
234
 
240
- /** McpToolCallToArgv builds nested lookup argv. */
241
235
  test("mcpToolCallToArgv builds nested lookup argv", () => {
242
236
  const tools = collectMcpTools(nestedMcpFixture);
243
237
  const lookup = tools.find((t) => t.name === "stat_owner_lookup")!;
@@ -249,7 +243,6 @@ test("mcpToolCallToArgv builds nested lookup argv", () => {
249
243
  expect(argv).toEqual(["stat", "owner", "lookup", "--json", "--user-name", "alice", "./x"]);
250
244
  });
251
245
 
252
- /** McpToolCallToArgv expands varargs positionals. */
253
246
  test("mcpToolCallToArgv expands varargs positionals", () => {
254
247
  const tools = collectMcpTools(nestedMcpFixture);
255
248
  const read = tools.find((t) => t.name === "read")!;
@@ -324,7 +317,6 @@ test("mcpServer on non-root node is rejected", () => {
324
317
  expect(() => cliValidateProgram(root)).toThrow(/mcpServer is only supported on the program root/);
325
318
  });
326
319
 
327
- /** McpTool on root is rejected. */
328
320
  test("mcpTool on root is rejected", () => {
329
321
  const root = testProgram({
330
322
  key: "app",
@@ -358,7 +350,6 @@ test("mcpTool on routing node is rejected", () => {
358
350
  expect(() => cliValidateProgram(root)).toThrow(/mcpTool is only supported on leaf commands/);
359
351
  });
360
352
 
361
- /** BuildToolCallSuccess returns stdout only. */
362
353
  test("buildToolCallSuccess returns stdout only", () => {
363
354
  const result = buildToolCallSuccess("hello\n", "");
364
355
  expect(result.isError).toBe(false);
@@ -366,7 +357,6 @@ test("buildToolCallSuccess returns stdout only", () => {
366
357
  expect(result.structuredContent).toBeUndefined();
367
358
  });
368
359
 
369
- /** BuildToolCallSuccess adds stderr as second content block. */
370
360
  test("buildToolCallSuccess adds stderr as second content block", () => {
371
361
  const result = buildToolCallSuccess("out\n", "warn\n");
372
362
  expect(result.content).toEqual([
@@ -376,7 +366,6 @@ test("buildToolCallSuccess adds stderr as second content block", () => {
376
366
  expect(result.structuredContent).toBeUndefined();
377
367
  });
378
368
 
379
- /** BuildToolCallSuccess stderr-only still includes stdout slot. */
380
369
  test("buildToolCallSuccess stderr-only still includes stdout slot", () => {
381
370
  const result = buildToolCallSuccess("", "warn\n");
382
371
  expect(result.content).toEqual([
@@ -385,26 +374,22 @@ test("buildToolCallSuccess stderr-only still includes stdout slot", () => {
385
374
  ]);
386
375
  });
387
376
 
388
- /** BuildToolCallSuccess parses JSON structuredContent. */
389
377
  test("buildToolCallSuccess parses JSON structuredContent", () => {
390
378
  const result = buildToolCallSuccess('{"a":1}\n', "");
391
379
  expect(result.structuredContent).toEqual({ a: 1 });
392
380
  expect(result.content[0]?.text).toBe('{"a":1}\n');
393
381
  });
394
382
 
395
- /** BuildToolCallSuccess skips structuredContent for plain text. */
396
383
  test("buildToolCallSuccess skips structuredContent for plain text", () => {
397
384
  const result = buildToolCallSuccess("lookup user=x\n", "");
398
385
  expect(result.structuredContent).toBeUndefined();
399
386
  });
400
387
 
401
- /** BuildToolCallSuccess parses JSON primitives. */
402
388
  test("buildToolCallSuccess parses JSON primitives", () => {
403
389
  const result = buildToolCallSuccess("true\n", "");
404
390
  expect(result.structuredContent).toBe(true);
405
391
  });
406
392
 
407
- /** MCP initialize returns tools and resources capabilities. */
408
393
  test("MCP initialize returns tools and resources capabilities", async () => {
409
394
  const responses = await mcpRequest([{ jsonrpc: "2.0", id: 1, method: "initialize", params: {} }]);
410
395
  const res = responses.get(1) as { result: { capabilities: Record<string, unknown> } };
@@ -412,7 +397,6 @@ test("MCP initialize returns tools and resources capabilities", async () => {
412
397
  expect(res.result.capabilities.resources).toBeDefined();
413
398
  });
414
399
 
415
- /** MCP tools/list includes stat_owner_lookup. */
416
400
  test("MCP tools/list includes stat_owner_lookup", async () => {
417
401
  const responses = await mcpRequest([{ jsonrpc: "2.0", id: 2, method: "tools/list", params: {} }]);
418
402
  const res = responses.get(2) as {
@@ -423,7 +407,6 @@ test("MCP tools/list includes stat_owner_lookup", async () => {
423
407
  expect(lookup?.inputSchema.required).toContain("path");
424
408
  });
425
409
 
426
- /** MCP resources/read returns schema JSON. */
427
410
  test("MCP resources/read returns schema JSON", async () => {
428
411
  const responses = await mcpRequest([
429
412
  { jsonrpc: "2.0", id: 3, method: "resources/read", params: { uri: "nested_ts://schema" } },
@@ -493,21 +476,18 @@ test("MCP tools/call errors on missing required positional", async () => {
493
476
  expect(res.result.content[0]?.text).toContain("Missing argument: path");
494
477
  });
495
478
 
496
- /** MCP ping returns empty result. */
497
479
  test("MCP ping returns empty result", async () => {
498
480
  const responses = await mcpRequest([{ jsonrpc: "2.0", id: 99, method: "ping", params: {} }]);
499
481
  const res = responses.get(99) as { result: Record<string, never> };
500
482
  expect(res.result).toEqual({});
501
483
  });
502
484
 
503
- /** Tests that minimal.ts mcp without opt-in fails. */
504
485
  test("minimal.ts mcp without opt-in fails", async () => {
505
486
  const { stderr, exitCode } = await $`bun run examples/minimal.ts mcp`.nothrow().quiet();
506
487
  expect(exitCode).toBe(1);
507
488
  expect(stderr.toString()).toContain("MCP is not available");
508
489
  });
509
490
 
510
- /** MCP resources/list includes custom resource. */
511
491
  test("MCP resources/list includes custom resource", async () => {
512
492
  const responses = await mcpRequest(
513
493
  [{ jsonrpc: "2.0", id: 10, method: "resources/list", params: {} }],
@@ -537,7 +517,6 @@ test("MCP resources/read returns docs topic resource body", async () => {
537
517
  expect(res.result.contents[0]?.text).toBe("# MCP test readme\n");
538
518
  });
539
519
 
540
- /** MCP resources/read returns custom resource body. */
541
520
  test("MCP resources/read returns custom resource body", async () => {
542
521
  const responses = await mcpRequest(
543
522
  [{ jsonrpc: "2.0", id: 11, method: "resources/read", params: { uri: "test://hello" } }],
@@ -547,7 +526,6 @@ test("MCP resources/read returns custom resource body", async () => {
547
526
  expect(res.result.contents[0]?.text).toBe("hello resource");
548
527
  });
549
528
 
550
- /** MCP resources/read unknown URI returns error. */
551
529
  test("MCP resources/read unknown URI returns error", async () => {
552
530
  const responses = await mcpRequest(
553
531
  [{ jsonrpc: "2.0", id: 12, method: "resources/read", params: { uri: "missing://nope" } }],