argsbarg 5.1.7 → 5.1.9

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 (92) hide show
  1. package/CHANGELOG.md +22 -1
  2. package/docs/cli-program.md +3 -1
  3. package/docs/config-schema.md +5 -3
  4. package/docs/configure.md +13 -7
  5. package/docs/distribution-homebrew.md +3 -2
  6. package/examples/full-example/justfile +2 -5
  7. package/examples/full-example/scripts/with-dev-formula.ts +6 -1
  8. package/index.d.ts +10 -1
  9. package/package.json +1 -1
  10. package/src/builtins/builtins.test.ts +1 -3
  11. package/src/builtins/completion-bash.ts +6 -27
  12. package/src/builtins/completion-group.ts +1 -2
  13. package/src/builtins/completion-simulate-shared.ts +2 -10
  14. package/src/builtins/completion-zsh.ts +7 -33
  15. package/src/builtins/config.test.ts +28 -0
  16. package/src/builtins/config.ts +40 -10
  17. package/src/builtins/configure-copy.ts +3 -6
  18. package/src/builtins/dispatch.ts +2 -10
  19. package/src/builtins/export.ts +1 -3
  20. package/src/builtins/presentation.ts +2 -7
  21. package/src/builtins/registry.ts +1 -5
  22. package/src/cli-tool/create.test.ts +3 -6
  23. package/src/cli-tool/create.ts +5 -22
  24. package/src/cli-tool/post-create.ts +1 -3
  25. package/src/cli-tool/program.ts +1 -2
  26. package/src/cli-tool/run-create.ts +2 -8
  27. package/src/cli.ts +6 -27
  28. package/src/config/bindings.test.ts +72 -0
  29. package/src/config/bindings.ts +115 -0
  30. package/src/config/bootstrap.ts +80 -65
  31. package/src/config/context.test.ts +45 -0
  32. package/src/config/context.ts +74 -14
  33. package/src/config/entry.ts +1 -3
  34. package/src/config/file.test.ts +46 -3
  35. package/src/config/file.ts +59 -19
  36. package/src/config/resolve.ts +1 -4
  37. package/src/config/schema.ts +1 -3
  38. package/src/config/validate.test.ts +3 -11
  39. package/src/config/validate.ts +30 -30
  40. package/src/config.integration.test.ts +1 -5
  41. package/src/configure/configure.test.ts +19 -5
  42. package/src/configure/index.ts +17 -15
  43. package/src/docs/api-guide.ts +1 -6
  44. package/src/docs/builtin.ts +1 -5
  45. package/src/docs/docs.test.ts +2 -6
  46. package/src/docs/mcp-guide.ts +3 -13
  47. package/src/docs/mcp-resources.test.ts +1 -3
  48. package/src/docs/mcp-resources.ts +1 -6
  49. package/src/docs/save.ts +2 -10
  50. package/src/formats.test.ts +1 -7
  51. package/src/formats.ts +1 -5
  52. package/src/headless.test.ts +5 -17
  53. package/src/help.ts +9 -51
  54. package/src/hidden-mcpb.test.ts +3 -12
  55. package/src/hidden.ts +1 -3
  56. package/src/install/binary-placement.test.ts +2 -6
  57. package/src/install/binary-placement.ts +1 -4
  58. package/src/install/gh-release-update.ts +5 -22
  59. package/src/install/mcp-codex.ts +1 -2
  60. package/src/install/mcp-config.ts +2 -12
  61. package/src/install/mcp-opencode.test.ts +1 -3
  62. package/src/install/mcp-opencode.ts +3 -15
  63. package/src/install/plan.ts +2 -10
  64. package/src/install/status.ts +3 -5
  65. package/src/install/target-base.ts +2 -11
  66. package/src/install/target-detect.ts +1 -5
  67. package/src/install/target-effective.ts +3 -13
  68. package/src/install/target-mcp-cli.ts +4 -26
  69. package/src/install/target-mcp-json.ts +3 -14
  70. package/src/install/target-plan-build.ts +1 -5
  71. package/src/install/target-registry.ts +13 -21
  72. package/src/install/target-scope.ts +8 -25
  73. package/src/install/target-types.ts +1 -6
  74. package/src/install/targets/app.ts +2 -2
  75. package/src/install/targets/opencode-mcp.ts +1 -6
  76. package/src/install/targets.test.ts +3 -10
  77. package/src/install/uninstall.ts +2 -9
  78. package/src/invoke.test.ts +1 -3
  79. package/src/mcp/bundle.ts +4 -19
  80. package/src/mcp/claude.test.ts +3 -3
  81. package/src/mcp/claude.ts +4 -17
  82. package/src/mcp/env.ts +1 -3
  83. package/src/mcp/server.ts +3 -12
  84. package/src/mcp/tools.ts +2 -11
  85. package/src/mcp.integration.test.ts +4 -10
  86. package/src/parse.test.ts +9 -34
  87. package/src/parse.ts +10 -44
  88. package/src/schema.ts +2 -10
  89. package/src/skill/hint.ts +1 -5
  90. package/src/skill/install.ts +1 -5
  91. package/src/test-fixtures.ts +1 -3
  92. package/src/validate.ts +29 -90
@@ -46,11 +46,7 @@ export abstract class InstallTarget {
46
46
 
47
47
  protected abstract isDetectedFromSnapshot(detected: DetectedSnapshot): boolean;
48
48
 
49
- statusLine(
50
- paths: InstallPaths,
51
- root: CliProgram,
52
- detected: InstalledArtifacts,
53
- ): string | undefined {
49
+ statusLine(paths: InstallPaths, root: CliProgram, detected: InstalledArtifacts): string | undefined {
54
50
  if (!this.isDetectedFromInstalled(detected)) return undefined;
55
51
  return this.formatStatusLine(paths, root);
56
52
  }
@@ -78,12 +74,7 @@ export abstract class InstallTarget {
78
74
 
79
75
  protected abstract buildUninstallActions(ctx: TargetPlanContext): UninstallAction[];
80
76
 
81
- contributeStatus(
82
- paths: InstallPaths,
83
- root: CliProgram,
84
- detected: InstalledArtifacts,
85
- status: InstallStatus,
86
- ): void {
77
+ contributeStatus(paths: InstallPaths, root: CliProgram, detected: InstalledArtifacts, status: InstallStatus): void {
87
78
  const line = this.statusLine(paths, root, detected);
88
79
  if (!line) return;
89
80
  this.assignStatusLine(status, line);
@@ -7,11 +7,7 @@ export { buildDetectedSnapshot, detectInstalledArtifacts } from "./target-scope.
7
7
  export type { InstalledArtifacts, InstallStatus } from "./target-types.ts";
8
8
 
9
9
  /** Builds a status inventory from detected artifacts. */
10
- export function buildInstallStatus(
11
- paths: InstallPaths,
12
- detected: InstalledArtifacts,
13
- root: CliProgram,
14
- ): InstallStatus {
10
+ export function buildInstallStatus(paths: InstallPaths, detected: InstalledArtifacts, root: CliProgram): InstallStatus {
15
11
  const status: InstallStatus = {};
16
12
  for (const target of INSTALL_TARGETS) {
17
13
  target.contributeStatus(paths, root, detected, status);
@@ -19,10 +19,7 @@ export type { InstallTargetSpec, ResolvedInstallTarget } from "../types.ts";
19
19
 
20
20
  export type { InstallPlanMode, InstallScope } from "./target-types.ts";
21
21
 
22
- export function resolveAgentIntegration(
23
- configure?: CliConfigureConfig,
24
- mcpEnabled = false,
25
- ): InstallAgentIntegration {
22
+ export function resolveAgentIntegration(configure?: CliConfigureConfig, mcpEnabled = false): InstallAgentIntegration {
26
23
  return configure?.agentIntegration ?? (mcpEnabled ? "mcp" : "skill");
27
24
  }
28
25
 
@@ -95,10 +92,7 @@ export function resolveEffectiveInstallTargets(
95
92
  const user = configure?.targets;
96
93
  const out = {} as Record<CliInstallArtifactKey, { enabled: boolean; includedInAll: boolean }>;
97
94
  for (const key of INSTALL_ARTIFACT_KEYS) {
98
- out[key] = resolveInstallTargetSpec(
99
- user?.[key],
100
- artifactDefaults(key, integration, mcpEnabled),
101
- );
95
+ out[key] = resolveInstallTargetSpec(user?.[key], artifactDefaults(key, integration, mcpEnabled));
102
96
  }
103
97
  applyAgentPairDedupe(out, user, integration);
104
98
  return out;
@@ -132,10 +126,6 @@ export function resolveInstallPlanMode(opts: {
132
126
  }
133
127
 
134
128
  /** @deprecated Use target registry. */
135
- export function isInstallTargetAvailable(
136
- key: CliInstallArtifactKey,
137
- root: CliProgram,
138
- paths: InstallPaths,
139
- ): boolean {
129
+ export function isInstallTargetAvailable(key: CliInstallArtifactKey, root: CliProgram, paths: InstallPaths): boolean {
140
130
  return installTargetForKey(key)?.isAvailable(root, paths) ?? false;
141
131
  }
@@ -1,10 +1,5 @@
1
1
  import type { CliProgram } from "../types.ts";
2
- import {
3
- checkCodexMcpConflict,
4
- codexMcpHasServer,
5
- mergeCodexMcpConfig,
6
- removeCodexMcpConfig,
7
- } from "./mcp-codex.ts";
2
+ import { checkCodexMcpConflict, codexMcpHasServer, mergeCodexMcpConfig, removeCodexMcpConfig } from "./mcp-codex.ts";
8
3
  import { expectedMcpEntry } from "./mcp-config.ts";
9
4
  import {
10
5
  checkOpenclawMcpConflict,
@@ -37,20 +32,9 @@ export interface McpCliHostSpec {
37
32
  hasServer: (home: string, name: string) => boolean;
38
33
  installMessage: string;
39
34
  uninstallMessage: string;
40
- merge: (
41
- home: string,
42
- name: string,
43
- entry: ReturnType<typeof expectedMcpEntry>,
44
- dry: boolean,
45
- yes: boolean,
46
- ) => string;
35
+ merge: (home: string, name: string, entry: ReturnType<typeof expectedMcpEntry>, dry: boolean, yes: boolean) => string;
47
36
  remove: (home: string, name: string, dry: boolean) => void;
48
- preflight: (
49
- home: string,
50
- name: string,
51
- entry: ReturnType<typeof expectedMcpEntry>,
52
- yes: boolean,
53
- ) => string | null;
37
+ preflight: (home: string, name: string, entry: ReturnType<typeof expectedMcpEntry>, yes: boolean) => string | null;
54
38
  }
55
39
 
56
40
  /** MCP host registered via an external CLI (codex, openclaw). */
@@ -108,13 +92,7 @@ export class McpCliInstallTarget extends InstallTarget {
108
92
  summary: `${this.spec.label}: ${displayInstallPath(configPath)}`,
109
93
  message: this.spec.installMessage.replace("{name}", ctx.paths.mcpName),
110
94
  run: () => {
111
- const written = this.spec.merge(
112
- userHome(),
113
- ctx.paths.mcpName,
114
- entry,
115
- ctx.dry,
116
- !!ctx.opts.yes,
117
- );
95
+ const written = this.spec.merge(userHome(), ctx.paths.mcpName, entry, ctx.dry, !!ctx.opts.yes);
118
96
  return [written];
119
97
  },
120
98
  },
@@ -25,14 +25,8 @@ export interface McpJsonHostSpec {
25
25
  label: string;
26
26
  pairedSkillKey?: CliInstallArtifactKey;
27
27
  configPath: (paths: InstallPaths) => string;
28
- detectedKey: keyof Pick<
29
- InstalledArtifacts,
30
- "cursorMcp" | "claudeMcp" | "claudeDesktopMcp" | "chatGptMcp"
31
- >;
32
- statusField: keyof Pick<
33
- InstallStatus,
34
- "cursorMcp" | "claudeMcp" | "claudeDesktopMcp" | "chatGptMcp"
35
- >;
28
+ detectedKey: keyof Pick<InstalledArtifacts, "cursorMcp" | "claudeMcp" | "claudeDesktopMcp" | "chatGptMcp">;
29
+ statusField: keyof Pick<InstallStatus, "cursorMcp" | "claudeMcp" | "claudeDesktopMcp" | "chatGptMcp">;
36
30
  isAvailable: (root: CliProgram, paths: InstallPaths) => boolean;
37
31
  /** Append server name to status line (default false). */
38
32
  statusIncludesServer?: boolean;
@@ -89,12 +83,7 @@ export class McpJsonInstallTarget extends InstallTarget {
89
83
 
90
84
  preflight(ctx: TargetPlanContext): string | null {
91
85
  const entry = expectedMcpEntry(ctx.root);
92
- return checkMcpConflict(
93
- this.spec.configPath(ctx.paths),
94
- ctx.paths.mcpName,
95
- entry,
96
- !!ctx.opts.yes,
97
- );
86
+ return checkMcpConflict(this.spec.configPath(ctx.paths), ctx.paths.mcpName, entry, !!ctx.opts.yes);
98
87
  }
99
88
 
100
89
  protected buildInstallActions(ctx: TargetPlanContext): InstallAction[] {
@@ -7,11 +7,7 @@ import { buildDetectedSnapshot, buildTargetPlanContext } from "./target-scope.ts
7
7
  import type { InstallAction, InstallOpts, UninstallAction } from "./target-types.ts";
8
8
 
9
9
  /** Builds install actions for normal mode (--all / scoped targets). */
10
- export function buildInstallPlanFromTargets(
11
- root: CliProgram,
12
- paths: InstallPaths,
13
- opts: InstallOpts,
14
- ): InstallAction[] {
10
+ export function buildInstallPlanFromTargets(root: CliProgram, paths: InstallPaths, opts: InstallOpts): InstallAction[] {
15
11
  const detected = buildDetectedSnapshot(root, paths);
16
12
  const ctx = buildTargetPlanContext(root, paths, opts, detected);
17
13
 
@@ -7,28 +7,23 @@ export { INSTALL_TARGETS } from "./targets/index.ts";
7
7
 
8
8
  export const INSTALL_ARTIFACT_KEYS: CliInstallArtifactKey[] = INSTALL_TARGETS.map((t) => t.key);
9
9
 
10
- export const SKILL_KEYS: CliInstallArtifactKey[] = INSTALL_TARGETS.filter(
11
- (t) => t.category === "skill",
12
- ).map((t) => t.key);
10
+ export const SKILL_KEYS: CliInstallArtifactKey[] = INSTALL_TARGETS.filter((t) => t.category === "skill").map(
11
+ (t) => t.key,
12
+ );
13
13
 
14
- export const MCP_KEYS: CliInstallArtifactKey[] = INSTALL_TARGETS.filter(
15
- (t) => t.category === "mcp",
16
- ).map((t) => t.key);
14
+ export const MCP_KEYS: CliInstallArtifactKey[] = INSTALL_TARGETS.filter((t) => t.category === "mcp").map((t) => t.key);
17
15
 
18
16
  /** Maps plan action kinds to install.targets artifact keys. */
19
- export const ACTION_KIND_TO_ARTIFACT: Record<InstallActionKind, CliInstallArtifactKey> =
20
- Object.fromEntries(INSTALL_TARGETS.map((t) => [t.actionKind, t.key])) as Record<
21
- InstallActionKind,
22
- CliInstallArtifactKey
23
- >;
17
+ export const ACTION_KIND_TO_ARTIFACT: Record<InstallActionKind, CliInstallArtifactKey> = Object.fromEntries(
18
+ INSTALL_TARGETS.map((t) => [t.actionKind, t.key]),
19
+ ) as Record<InstallActionKind, CliInstallArtifactKey>;
24
20
 
25
21
  /** Hosts with both MCP config and shell skill install targets. */
26
- export const AGENT_PAIRS: [CliInstallArtifactKey, CliInstallArtifactKey][] =
27
- INSTALL_TARGETS.flatMap((t) =>
28
- t.category === "mcp" && t.pairedKey !== undefined
29
- ? [[t.key, t.pairedKey] as [CliInstallArtifactKey, CliInstallArtifactKey]]
30
- : [],
31
- );
22
+ export const AGENT_PAIRS: [CliInstallArtifactKey, CliInstallArtifactKey][] = INSTALL_TARGETS.flatMap((t) =>
23
+ t.category === "mcp" && t.pairedKey !== undefined
24
+ ? [[t.key, t.pairedKey] as [CliInstallArtifactKey, CliInstallArtifactKey]]
25
+ : [],
26
+ );
32
27
 
33
28
  const targetByKey = new Map(INSTALL_TARGETS.map((t) => [t.key, t]));
34
29
 
@@ -47,10 +42,7 @@ export function isMcpArtifactKey(key: CliInstallArtifactKey): boolean {
47
42
  * Defaults: artifactDefaults in target-effective.ts.
48
43
  * Explicit spec rejection: validateConfigureConfig in validate.ts.
49
44
  */
50
- export function mcpServerRequiredForArtifact(
51
- key: CliInstallArtifactKey,
52
- mcpServerEnabled: boolean,
53
- ): boolean {
45
+ export function mcpServerRequiredForArtifact(key: CliInstallArtifactKey, mcpServerEnabled: boolean): boolean {
54
46
  return !isMcpArtifactKey(key) || mcpServerEnabled;
55
47
  }
56
48
 
@@ -1,5 +1,5 @@
1
1
  import { resolveCapabilities } from "../capabilities.ts";
2
- import { appConfigInstalled } from "../config/file.ts";
2
+ import { appConfigFileExists } from "../config/file.ts";
3
3
  import type { CliConfigureTargets, CliProgram } from "../types.ts";
4
4
  import type { InstallPaths } from "./paths.ts";
5
5
  import {
@@ -46,10 +46,7 @@ function emptyInstalledArtifacts(): InstalledArtifacts {
46
46
  }
47
47
 
48
48
  /** Detects which install artifacts are currently present. */
49
- export function detectInstalledArtifacts(
50
- paths: InstallPaths,
51
- root: CliProgram,
52
- ): InstalledArtifacts {
49
+ export function detectInstalledArtifacts(paths: InstallPaths, root: CliProgram): InstalledArtifacts {
53
50
  const out = emptyInstalledArtifacts();
54
51
  for (const target of INSTALL_TARGETS) {
55
52
  target.applyDetected(paths, root, out);
@@ -73,14 +70,11 @@ export function buildDetectedSnapshot(root: CliProgram, paths: InstallPaths): De
73
70
  const base = detectInstalledArtifacts(paths, root);
74
71
  return {
75
72
  ...base,
76
- appConfig: root.appConfig ? appConfigInstalled(root) : false,
73
+ appConfig: appConfigFileExists(root),
77
74
  };
78
75
  }
79
76
 
80
- function targetExplicitlyConfigured(
81
- user: CliConfigureTargets | undefined,
82
- key: CliInstallArtifactKey,
83
- ): boolean {
77
+ function targetExplicitlyConfigured(user: CliConfigureTargets | undefined, key: CliInstallArtifactKey): boolean {
84
78
  return user?.[key] !== undefined;
85
79
  }
86
80
 
@@ -220,10 +214,7 @@ export function buildTargetPlanContext(
220
214
  }
221
215
 
222
216
  /** Maps detected snapshot to artifact key (for tests and legacy callers). */
223
- export function detectedForArtifact(
224
- key: CliInstallArtifactKey,
225
- detected: DetectedSnapshot,
226
- ): boolean {
217
+ export function detectedForArtifact(key: CliInstallArtifactKey, detected: DetectedSnapshot): boolean {
227
218
  const target = installTargetForKey(key);
228
219
  if (key === "configure") {
229
220
  return detected.appConfig ?? false;
@@ -232,20 +223,12 @@ export function detectedForArtifact(
232
223
  }
233
224
 
234
225
  /** Resolved artifact keys for `--all`, `--mcp`, and `--skill` (availability-gated). */
235
- export function resolveInstallTargetPreview(
236
- program: CliProgram,
237
- paths: InstallPaths,
238
- ): InstallTargetPreview {
226
+ export function resolveInstallTargetPreview(program: CliProgram, paths: InstallPaths): InstallTargetPreview {
239
227
  const effective = resolveEffectiveInstallTargets(program.configure, program);
240
- const integration = resolveAgentIntegration(
241
- program.configure,
242
- program.mcpServer?.enabled === true,
243
- );
228
+ const integration = resolveAgentIntegration(program.configure, program.mcpServer?.enabled === true);
244
229
 
245
230
  const keysForScope = (scope: InstallScope, mode: InstallPlanMode): CliInstallArtifactKey[] =>
246
- INSTALL_ARTIFACT_KEYS.filter((key) =>
247
- shouldIncludeArtifact(key, program, paths, scope, mode, effective),
248
- );
231
+ INSTALL_ARTIFACT_KEYS.filter((key) => shouldIncludeArtifact(key, program, paths, scope, mode, effective));
249
232
 
250
233
  return {
251
234
  agentIntegration: integration,
@@ -3,12 +3,7 @@ import type { InstallPaths } from "./paths.ts";
3
3
 
4
4
  export type { InstallTargetSpec, ResolvedInstallTarget } from "../types.ts";
5
5
 
6
- export type InstallPlanMode =
7
- | "install-all"
8
- | "install-scoped"
9
- | "uninstall-all"
10
- | "uninstall-scoped"
11
- | "refresh";
6
+ export type InstallPlanMode = "install-all" | "install-scoped" | "uninstall-all" | "uninstall-scoped" | "refresh";
12
7
 
13
8
  export interface InstallScope {
14
9
  all?: boolean;
@@ -1,6 +1,6 @@
1
1
  import type { CliProgram } from "../../types.ts";
2
2
  import { isExternallyManagedBinary } from "../binary-placement.ts";
3
- import { displayInstallPath, type InstallPaths } from "../paths.ts";
3
+ import type { InstallPaths } from "../paths.ts";
4
4
  import { InstallTarget } from "../target-base.ts";
5
5
  import type {
6
6
  DetectedSnapshot,
@@ -25,7 +25,7 @@ class AppInstallTarget extends InstallTarget {
25
25
  return true;
26
26
  }
27
27
 
28
- isDetected(paths: InstallPaths, root: CliProgram): boolean {
28
+ isDetected(_paths: InstallPaths, root: CliProgram): boolean {
29
29
  return isExternallyManagedBinary(root.key) || false;
30
30
  }
31
31
 
@@ -57,12 +57,7 @@ class OpenCodeMcpInstallTarget extends InstallTarget {
57
57
 
58
58
  preflight(ctx: TargetPlanContext): string | null {
59
59
  const entry = expectedOpenCodeMcpEntry(ctx.root);
60
- return checkOpenCodeMcpConflict(
61
- ctx.paths.opencodeMcpPath,
62
- ctx.paths.mcpName,
63
- entry,
64
- !!ctx.opts.yes,
65
- );
60
+ return checkOpenCodeMcpConflict(ctx.paths.opencodeMcpPath, ctx.paths.mcpName, entry, !!ctx.opts.yes);
66
61
  }
67
62
 
68
63
  protected buildInstallActions(ctx: TargetPlanContext): InstallAction[] {
@@ -95,10 +95,7 @@ describe("resolveEffectiveInstallTargets", () => {
95
95
  isArtifactInScope(
96
96
  "cursorMcp",
97
97
  scope,
98
- resolveEffectiveInstallTargets(
99
- { targets: { cursorMcp: true }, agentIntegration: "both" },
100
- program,
101
- ),
98
+ resolveEffectiveInstallTargets({ targets: { cursorMcp: true }, agentIntegration: "both" }, program),
102
99
  "install-scoped",
103
100
  program,
104
101
  ),
@@ -117,13 +114,9 @@ describe("resolveEffectiveInstallTargets", () => {
117
114
  };
118
115
  const effective = resolveEffectiveInstallTargets(program.configure, program);
119
116
  const scope = { mcp: true, skill: true, configure: true };
120
- expect(isArtifactInScope("cursorSkill", scope, effective, "install-scoped", program)).toBe(
121
- true,
122
- );
117
+ expect(isArtifactInScope("cursorSkill", scope, effective, "install-scoped", program)).toBe(true);
123
118
  expect(isArtifactInScope("cursorMcp", scope, effective, "install-scoped", program)).toBe(true);
124
119
  expect(isArtifactInScope("configure", scope, effective, "install-scoped", program)).toBe(true);
125
- expect(isArtifactInScope("claudeSkill", scope, effective, "install-scoped", program)).toBe(
126
- true,
127
- );
120
+ expect(isArtifactInScope("claudeSkill", scope, effective, "install-scoped", program)).toBe(true);
128
121
  });
129
122
  });
@@ -8,11 +8,7 @@ import type { InstallOpts, UninstallAction } from "./target-types.ts";
8
8
  export type { InstallActionKind, InstallOpts, UninstallAction } from "./target-types.ts";
9
9
 
10
10
  /** Builds uninstall actions for scoped targets or --all (ignores install.targets on --all). */
11
- export function buildUninstallPlan(
12
- root: CliProgram,
13
- paths: InstallPaths,
14
- opts: InstallOpts,
15
- ): UninstallAction[] {
11
+ export function buildUninstallPlan(root: CliProgram, paths: InstallPaths, opts: InstallOpts): UninstallAction[] {
16
12
  return buildUninstallPlanFromTargets(root, paths, opts);
17
13
  }
18
14
 
@@ -24,10 +20,7 @@ export function uninstallSkillDir(dir: string, dry: boolean): string[] {
24
20
  }
25
21
 
26
22
  /** Skill directory for uninstall action summary prefix. */
27
- export function skillDirFromUninstallSummary(
28
- summary: string,
29
- paths: InstallPaths,
30
- ): string | undefined {
23
+ export function skillDirFromUninstallSummary(summary: string, paths: InstallPaths): string | undefined {
31
24
  const target = skillTargetForUninstallSummary(summary);
32
25
  return target?.skillDir(paths);
33
26
  }
@@ -188,9 +188,7 @@ test("ctx.positional returns undefined for absent optional slot", async () => {
188
188
  {
189
189
  key: "x",
190
190
  description: "",
191
- positionals: [
192
- { name: "opt", description: "", kind: CliOptionKind.String, argMin: 0, argMax: 1 },
193
- ],
191
+ positionals: [{ name: "opt", description: "", kind: CliOptionKind.String, argMin: 0, argMax: 1 }],
194
192
  handler: (ctx: CliContext) => {
195
193
  captured = ctx.positional("opt");
196
194
  },
package/src/mcp/bundle.ts CHANGED
@@ -3,15 +3,7 @@ Packs a CLI program into an MCP Bundle (`.mcpb`) for Claude Desktop.
3
3
  Expects `dist/<program.key>` as the compiled binary input.
4
4
  */
5
5
 
6
- import {
7
- cpSync,
8
- existsSync,
9
- mkdirSync,
10
- mkdtempSync,
11
- readFileSync,
12
- rmSync,
13
- writeFileSync,
14
- } from "node:fs";
6
+ import { cpSync, existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
15
7
  import { tmpdir } from "node:os";
16
8
  import { basename, join, resolve } from "node:path";
17
9
  import { buildProgramUserConfig } from "../config/manifest.ts";
@@ -56,10 +48,7 @@ function defaultAuthor(bundle?: CliMcpBundleConfig): {
56
48
  }
57
49
 
58
50
  /** Generates MCPB `manifest.json` object from program schema and MCP tools. */
59
- export function generateMcpManifest(
60
- program: CliProgram,
61
- binaryName: string,
62
- ): Record<string, unknown> {
51
+ export function generateMcpManifest(program: CliProgram, binaryName: string): Record<string, unknown> {
63
52
  const bundle = program.mcpServer?.bundle;
64
53
  const tools = collectMcpTools(program).map((t) => ({
65
54
  name: t.name,
@@ -123,9 +112,7 @@ export function packMcpBundle(program: CliProgram, opts: PackMcpBundleOpts = {})
123
112
  const binaryName = basename(binaryPath);
124
113
 
125
114
  if (!existsSync(binaryPath)) {
126
- throw new Error(
127
- `Binary not found: ${binaryPath}. Build with compile first (expected dist/${program.key}).`,
128
- );
115
+ throw new Error(`Binary not found: ${binaryPath}. Build with compile first (expected dist/${program.key}).`);
129
116
  }
130
117
 
131
118
  const staging = mkdtempSync(join(tmpdir(), "mcpb-"));
@@ -164,9 +151,7 @@ export function packMcpBundle(program: CliProgram, opts: PackMcpBundleOpts = {})
164
151
  export function runMcpBundle(program: CliProgram): void {
165
152
  const mcp = program.mcpServer;
166
153
  if (!mcp?.mcpd && !mcp?.claudePlugin) {
167
- throw new Error(
168
- "mcp bundle: enable mcpServer.mcpd and/or mcpServer.claudePlugin on the program root.",
169
- );
154
+ throw new Error("mcp bundle: enable mcpServer.mcpd and/or mcpServer.claudePlugin on the program root.");
170
155
  }
171
156
 
172
157
  const lines: string[] = [];
@@ -87,9 +87,9 @@ describe("claude plugin", () => {
87
87
  execSync("unzip -o -q ../out.zip", { cwd: extract });
88
88
  const binMode = statSync(join(extract, "bin", "myapp")).mode & 0o777;
89
89
  expect(binMode & 0o111).not.toBe(0);
90
- const pluginJson = JSON.parse(
91
- readFileSync(join(extract, ".claude-plugin", "plugin.json"), "utf8"),
92
- ) as { mcpServers: string };
90
+ const pluginJson = JSON.parse(readFileSync(join(extract, ".claude-plugin", "plugin.json"), "utf8")) as {
91
+ mcpServers: string;
92
+ };
93
93
  expect(pluginJson.mcpServers).toBe(".mcp.json");
94
94
  } finally {
95
95
  rmSync(work, { recursive: true, force: true });
package/src/mcp/claude.ts CHANGED
@@ -58,10 +58,7 @@ export function defaultClaudePluginPaths(program: CliProgram, cwd = process.cwd(
58
58
  }
59
59
 
60
60
  /** Generates `.claude-plugin/plugin.json` object. */
61
- export function generatePluginManifest(
62
- program: CliProgram,
63
- _binaryName: string,
64
- ): Record<string, unknown> {
61
+ export function generatePluginManifest(program: CliProgram, _binaryName: string): Record<string, unknown> {
65
62
  const bundle = program.mcpServer?.bundle;
66
63
  const manifest: Record<string, unknown> = {
67
64
  name: pluginName(program),
@@ -78,10 +75,7 @@ export function generatePluginManifest(
78
75
  }
79
76
 
80
77
  /** Generates plugin `.mcp.json` stdio server config. */
81
- export function generatePluginMcpJson(
82
- program: CliProgram,
83
- binaryName: string,
84
- ): Record<string, unknown> {
78
+ export function generatePluginMcpJson(program: CliProgram, binaryName: string): Record<string, unknown> {
85
79
  const mcp: Record<string, unknown> = {
86
80
  command: `\${CLAUDE_PLUGIN_ROOT}/bin/${binaryName}`,
87
81
  args: ["mcp"],
@@ -117,12 +111,7 @@ function collectZipEntries(rootDir: string, dir = rootDir): ZipFileEntry[] {
117
111
  return entries;
118
112
  }
119
113
 
120
- function writePluginTree(
121
- pluginRoot: string,
122
- program: CliProgram,
123
- binaryPath: string,
124
- binaryName: string,
125
- ): void {
114
+ function writePluginTree(pluginRoot: string, program: CliProgram, binaryPath: string, binaryName: string): void {
126
115
  const bundle = generatePluginSkillBundle(program);
127
116
  const skillMd = applyPluginSkillHint(program, bundle.skillMd);
128
117
 
@@ -155,9 +144,7 @@ export function packClaudePlugin(program: CliProgram, opts: PackMcpBundleOpts =
155
144
  const binaryName = basename(binaryPath);
156
145
 
157
146
  if (!existsSync(binaryPath)) {
158
- throw new Error(
159
- `Binary not found: ${binaryPath}. Build with compile first (expected dist/${program.key}).`,
160
- );
147
+ throw new Error(`Binary not found: ${binaryPath}. Build with compile first (expected dist/${program.key}).`);
161
148
  }
162
149
 
163
150
  const staging = mkdtempSync(join(tmpdir(), "claude-plugin-"));
package/src/mcp/env.ts CHANGED
@@ -51,9 +51,7 @@ export function bootstrapMcpEnv(config: { shellEnv?: boolean | string }): void {
51
51
  : (process.env.SHELL ?? (process.platform === "darwin" ? "/bin/zsh" : "/bin/bash"));
52
52
  const captured = captureShellEnv(shell);
53
53
  if (Object.keys(captured).length === 0) {
54
- process.stderr.write(
55
- `[argsbarg] shellEnv: failed to capture shell environment from ${shell}\n`,
56
- );
54
+ process.stderr.write(`[argsbarg] shellEnv: failed to capture shell environment from ${shell}\n`);
57
55
  } else {
58
56
  applyShellEnv(captured);
59
57
  }
package/src/mcp/server.ts CHANGED
@@ -7,12 +7,7 @@ import type { Cli } from "../cli.ts";
7
7
  import { bootstrapAppConfig } from "../config/bootstrap.ts";
8
8
  import { formatMcpMissingConfigMessage, missingRequiredConfig } from "../config/resolve.ts";
9
9
  import { buildToolCallSuccess } from "./result.ts";
10
- import {
11
- allMcpResources,
12
- collectMcpTools,
13
- mcpToolCallToArgv,
14
- resolveMcpServerInfo,
15
- } from "./tools.ts";
10
+ import { allMcpResources, collectMcpTools, mcpToolCallToArgv, resolveMcpServerInfo } from "./tools.ts";
16
11
 
17
12
  const MCP_PROTOCOL_VERSION = "2024-11-05";
18
13
 
@@ -110,10 +105,7 @@ async function handleRequestLine(cli: Cli, line: string): Promise<void> {
110
105
  return;
111
106
  }
112
107
  const rawArgs = params.arguments;
113
- if (
114
- rawArgs !== undefined &&
115
- (typeof rawArgs !== "object" || rawArgs === null || Array.isArray(rawArgs))
116
- ) {
108
+ if (rawArgs !== undefined && (typeof rawArgs !== "object" || rawArgs === null || Array.isArray(rawArgs))) {
117
109
  writeError(id, -32602, "Invalid params: arguments must be an object");
118
110
  return;
119
111
  }
@@ -162,8 +154,7 @@ async function handleRequestLine(cli: Cli, line: string): Promise<void> {
162
154
  });
163
155
  return;
164
156
  }
165
- const errText =
166
- invokeResult.stderr.trim() || invokeResult.errorMsg || `Exit code ${invokeResult.exitCode}`;
157
+ const errText = invokeResult.stderr.trim() || invokeResult.errorMsg || `Exit code ${invokeResult.exitCode}`;
167
158
  writeResponse({
168
159
  jsonrpc: "2.0",
169
160
  id,
package/src/mcp/tools.ts CHANGED
@@ -137,11 +137,7 @@ function positionalProperty(p: CliPositional): Record<string, unknown> {
137
137
  }
138
138
 
139
139
  /** Builds inputSchema for a leaf command. */
140
- function buildInputSchema(
141
- root: CliProgram,
142
- path: string[],
143
- leaf: CliLeaf,
144
- ): Record<string, unknown> {
140
+ function buildInputSchema(root: CliProgram, path: string[], leaf: CliLeaf): Record<string, unknown> {
145
141
  const properties: Record<string, unknown> = {};
146
142
  const required: string[] = [];
147
143
 
@@ -222,12 +218,7 @@ export function collectMcpTools(root: CliProgram): McpToolDef[] {
222
218
  /** Walks the command tree and appends leaf tools. */
223
219
  function walk(cmd: CliNode, path: string[]): void {
224
220
  if (isCliLeaf(cmd)) {
225
- if (
226
- cmd.key === "completion" ||
227
- cmd.key === "configure" ||
228
- cmd.key === "mcp" ||
229
- cmd.key === "version"
230
- ) {
221
+ if (cmd.key === "completion" || cmd.key === "configure" || cmd.key === "mcp" || cmd.key === "version") {
231
222
  return;
232
223
  }
233
224
  if (cmd.hidden || cmd.mcpTool?.enabled === false) {
@@ -7,12 +7,7 @@ import { join } from "node:path";
7
7
  import { $ } from "bun";
8
8
  import type { CliProgram } from "./index.ts";
9
9
  import { buildToolCallSuccess } from "./mcp/result.ts";
10
- import {
11
- collectMcpTools,
12
- mcpToolCallToArgv,
13
- mcpToolDescription,
14
- sanitizeToolSegment,
15
- } from "./mcp/tools.ts";
10
+ import { collectMcpTools, mcpToolCallToArgv, mcpToolDescription, sanitizeToolSegment } from "./mcp/tools.ts";
16
11
  import { cliSchemaExport } from "./schema.ts";
17
12
  import { mcpRequest, nestedMcpFixture, testProgram } from "./test-fixtures.ts";
18
13
  import { cliValidateProgram } from "./validate.ts";
@@ -489,10 +484,9 @@ test("minimal.ts mcp without opt-in fails", async () => {
489
484
  });
490
485
 
491
486
  test("MCP resources/list includes custom resource", async () => {
492
- const responses = await mcpRequest(
493
- [{ jsonrpc: "2.0", id: 10, method: "resources/list", params: {} }],
494
- { script: "examples/mcp-test.ts" },
495
- );
487
+ const responses = await mcpRequest([{ jsonrpc: "2.0", id: 10, method: "resources/list", params: {} }], {
488
+ script: "examples/mcp-test.ts",
489
+ });
496
490
  const res = responses.get(10) as { result: { resources: { uri: string }[] } };
497
491
  const uris = res.result.resources.map((r) => r.uri);
498
492
  expect(uris).toContain("mcp_test://schema");