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.
Files changed (94) hide show
  1. package/CHANGELOG.md +30 -1
  2. package/README.md +5 -5
  3. package/docs/ai-skills.md +8 -5
  4. package/docs/cli-program.md +4 -4
  5. package/docs/config-schema.md +1 -4
  6. package/docs/developing.md +1 -1
  7. package/docs/install.md +160 -39
  8. package/docs/mcp.md +21 -9
  9. package/docs/templates/cursor/rules/cli-program.mdc +1 -1
  10. package/examples/config-app/program.ts +0 -3
  11. package/examples/consumer-app/README.md +0 -1
  12. package/examples/consumer-app/src/program.ts +3 -3
  13. package/examples/mcp-test.ts +8 -24
  14. package/index.d.ts +60 -5
  15. package/package.json +1 -1
  16. package/src/builtins/builtins.test.ts +20 -4
  17. package/src/builtins/config.test.ts +31 -25
  18. package/src/builtins/config.ts +4 -3
  19. package/src/builtins/install.ts +50 -57
  20. package/src/builtins/mcp.ts +1 -1
  21. package/src/capabilities.ts +4 -4
  22. package/src/cli.ts +2 -0
  23. package/src/config/bootstrap.ts +167 -66
  24. package/src/config/context.test.ts +22 -36
  25. package/src/config/context.ts +5 -4
  26. package/src/config/file.test.ts +66 -56
  27. package/src/config/file.ts +33 -25
  28. package/src/config/resolve.test.ts +25 -1
  29. package/src/config/resolve.ts +43 -8
  30. package/src/config.integration.test.ts +17 -10
  31. package/src/docs/api-guide.test.ts +1 -1
  32. package/src/docs/docs.test.ts +1 -1
  33. package/src/docs/mcp-guide.ts +1 -1
  34. package/src/hidden-mcpb.test.ts +41 -1
  35. package/src/index.ts +4 -0
  36. package/src/install/{binary.ts → app.ts} +13 -13
  37. package/src/install/bootstrap.ts +22 -0
  38. package/src/install/detect-installed.ts +2 -97
  39. package/src/install/index.ts +187 -110
  40. package/src/install/install-validate.test.ts +61 -0
  41. package/src/install/install.test.ts +138 -42
  42. package/src/install/mcp-openclaw.test.ts +40 -0
  43. package/src/install/mcp-openclaw.ts +106 -0
  44. package/src/install/normalize.ts +35 -0
  45. package/src/install/paths.ts +27 -13
  46. package/src/install/plan.ts +30 -259
  47. package/src/install/shell.ts +2 -2
  48. package/src/install/status.test.ts +85 -0
  49. package/src/install/status.ts +22 -9
  50. package/src/install/target-base.ts +93 -0
  51. package/src/install/target-detect.ts +20 -0
  52. package/src/install/target-effective.ts +131 -0
  53. package/src/install/target-mcp-cli.ts +149 -0
  54. package/src/install/target-mcp-json.ts +130 -0
  55. package/src/install/target-plan-build.ts +67 -0
  56. package/src/install/target-registry.ts +57 -0
  57. package/src/install/target-scope.ts +266 -0
  58. package/src/install/target-skill.ts +104 -0
  59. package/src/install/target-types.ts +145 -0
  60. package/src/install/targets/app.ts +69 -0
  61. package/src/install/targets/chatgpt-mcp.ts +12 -0
  62. package/src/install/targets/claude-code-mcp.ts +15 -0
  63. package/src/install/targets/claude-desktop-mcp.ts +12 -0
  64. package/src/install/targets/claude-skill.ts +16 -0
  65. package/src/install/targets/codex-mcp.ts +25 -0
  66. package/src/install/targets/codex-skill.ts +14 -0
  67. package/src/install/targets/completions.ts +133 -0
  68. package/src/install/targets/configure.ts +59 -0
  69. package/src/install/targets/cursor-mcp.ts +15 -0
  70. package/src/install/targets/cursor-skill.ts +16 -0
  71. package/src/install/targets/index.ts +53 -0
  72. package/src/install/targets/openclaw-mcp.ts +25 -0
  73. package/src/install/targets/openclaw-skill.ts +17 -0
  74. package/src/install/targets/opencode-mcp.ts +101 -0
  75. package/src/install/targets/opencode-skill.ts +15 -0
  76. package/src/install/targets.test.ts +136 -0
  77. package/src/install/uninstall.ts +16 -152
  78. package/src/install/update.test.ts +17 -2
  79. package/src/install/update.ts +2 -5
  80. package/src/invoke.test.ts +7 -1
  81. package/src/mcp/bundle.ts +16 -4
  82. package/src/mcp/claude.test.ts +14 -1
  83. package/src/mcp/claude.ts +11 -4
  84. package/src/mcp/zip.test.ts +17 -0
  85. package/src/mcp/zip.ts +62 -9
  86. package/src/mcp.integration.test.ts +1 -1
  87. package/src/parse.test.ts +12 -1
  88. package/src/paths/host.ts +11 -11
  89. package/src/paths/remove-empty-dir.ts +13 -0
  90. package/src/skill/generate.ts +18 -4
  91. package/src/skill/install.ts +33 -6
  92. package/src/skill/naming.ts +28 -0
  93. package/src/types.ts +65 -4
  94. package/src/validate.ts +70 -0
@@ -5,19 +5,28 @@ import type { CliProgram } from "../types.ts";
5
5
  import { generateSkillBundle, type SkillTarget } from "./generate.ts";
6
6
  import { applySkillInstallHints } from "./hint.ts";
7
7
 
8
+ export { skillDirNameForTarget, skillFrontmatterName, skillSlug } from "./naming.ts";
9
+
8
10
  export interface SkillInstallOpts {
9
11
  global?: boolean;
10
- /** When true, remove an existing skill directory before writing. */
11
12
  rimraf?: boolean;
12
- /** When true, skip writes but return paths that would change. */
13
13
  dry?: boolean;
14
14
  }
15
15
 
16
16
  function resolveSkillDir(target: SkillTarget, dirName: string, global: boolean): string {
17
- const base = global
18
- ? join(userHome(), target === "cursor" ? ".cursor" : ".claude", "skills")
19
- : join(process.cwd(), target === "cursor" ? ".cursor" : ".claude", "skills");
20
- return join(base, dirName);
17
+ const home = userHome();
18
+ switch (target) {
19
+ case "cursor":
20
+ return join(global ? home : process.cwd(), ".cursor", "skills", dirName);
21
+ case "claude":
22
+ return join(global ? home : process.cwd(), ".claude", "skills", dirName);
23
+ case "codex":
24
+ return join(global ? home : process.cwd(), ".codex", "skills", dirName);
25
+ case "opencode":
26
+ return join(global ? home : process.cwd(), ".config", "opencode", "skills", dirName);
27
+ case "openclaw":
28
+ return join(global ? home : process.cwd(), ".openclaw", "skills", dirName);
29
+ }
21
30
  }
22
31
 
23
32
  /** Writes SKILL.md and reference.md; returns changed file paths. */
@@ -47,3 +56,21 @@ export function cliSkillInstall(
47
56
  changed.push(skillPath, refPath);
48
57
  return changed;
49
58
  }
59
+
60
+ /** Maps install action kind to skill target. */
61
+ export function skillTargetFromActionKind(kind: string): SkillTarget | undefined {
62
+ switch (kind) {
63
+ case "cursor-skill":
64
+ return "cursor";
65
+ case "claude-skill":
66
+ return "claude";
67
+ case "codex-skill":
68
+ return "codex";
69
+ case "opencode-skill":
70
+ return "opencode";
71
+ case "openclaw-skill":
72
+ return "openclaw";
73
+ default:
74
+ return undefined;
75
+ }
76
+ }
@@ -0,0 +1,28 @@
1
+ /** Agent skill install targets. */
2
+ export type SkillTarget = "cursor" | "claude" | "codex" | "opencode" | "openclaw";
3
+
4
+ import { sanitizeToolSegment } from "../mcp/tools.ts";
5
+
6
+ /** Kebab-case skill folder + frontmatter name for agents that require hyphen slugs. */
7
+ export function skillSlug(programKey: string): string {
8
+ return programKey
9
+ .replace(/[^a-zA-Z0-9]+/g, "-")
10
+ .replace(/^-+|-+$/g, "")
11
+ .toLowerCase();
12
+ }
13
+
14
+ /** Directory name for a skill target (underscore vs kebab conventions). */
15
+ export function skillDirNameForTarget(programKey: string, target: SkillTarget): string {
16
+ if (target === "cursor" || target === "claude") {
17
+ return sanitizeToolSegment(programKey);
18
+ }
19
+ return skillSlug(programKey);
20
+ }
21
+
22
+ /** Frontmatter `name` for SKILL.md by target. */
23
+ export function skillFrontmatterName(programKey: string, target: SkillTarget): string {
24
+ if (target === "cursor" || target === "claude") {
25
+ return sanitizeToolSegment(programKey);
26
+ }
27
+ return skillSlug(programKey);
28
+ }
package/src/types.ts CHANGED
@@ -133,6 +133,10 @@ export interface CliMcpBundleConfig {
133
133
  export interface CliMcpServerConfig {
134
134
  /** When `true`, enables the `mcp` built-in and MCP stdio server. */
135
135
  enabled: boolean;
136
+ /** When `true`, `mcp bundle` writes `dist/<key>.mcpb` for Claude Desktop. Default false. */
137
+ mcpd?: boolean;
138
+ /** When `true`, `mcp bundle` also writes `dist/claude-plugin/<name>.zip`. Default false. */
139
+ claudePlugin?: boolean;
136
140
  /** Resource URI for schema export (default: `<sanitized root key>://schema`). */
137
141
  schemaResourceUri?: string;
138
142
  /**
@@ -224,8 +228,6 @@ export interface CliAppConfigEntry {
224
228
  * App configuration block on the program root ({@link CliProgram.appConfig}).
225
229
  */
226
230
  export interface CliAppConfig {
227
- /** Default: `~/.config/<sanitized-key>/config` (or `%APPDATA%/<key>/config` on Windows). */
228
- path?: string;
229
231
  /** Built-in `config get` / `config set`. Default: enabled when `appConfig` is set. */
230
232
  commands?: boolean | { enabled?: boolean; mcpSet?: boolean };
231
233
  /** Block JSON Schema (draft-07). When omitted, synthesize all-string schema from `entries`. */
@@ -237,8 +239,15 @@ export interface CliAppConfig {
237
239
  export interface CliInstallConfig {
238
240
  /** When `false`, hide/disable `install` (default: enabled). */
239
241
  enabled?: boolean;
240
- /** Default bin directory (default: `~/.local/bin`). Overridden by `INSTALL_PREFIX` env and `--prefix`. */
241
- prefix?: string;
242
+ /**
243
+ * Default agent integration for full install (`install --all`).
244
+ * - `'mcp'` when `mcpServer.enabled` (default): MCP targets in `--all`; paired skills excluded.
245
+ * - `'skill'` when MCP is off (default): skill targets in `--all`; paired MCP excluded.
246
+ * - `'both'`: install MCP and skill for the same host when both are available.
247
+ */
248
+ agentIntegration?: InstallAgentIntegration;
249
+ /** Per-artifact gates for full install/uninstall. See {@link resolveEffectiveInstallTargets}. */
250
+ targets?: CliInstallTargets;
242
251
  /**
243
252
  * When set, enables `install --update` on the program root.
244
253
  * Should download or locate the latest release binary and return its path.
@@ -246,6 +255,58 @@ export interface CliInstallConfig {
246
255
  updateGetLatest?: CliUpdateGetLatest;
247
256
  }
248
257
 
258
+ /** Agent integration mode for install — MCP vs shell skill per host. */
259
+ export type InstallAgentIntegration = "mcp" | "skill" | "both";
260
+
261
+ /** Boolean or structured gate for one install artifact. */
262
+ export type InstallTargetSpec =
263
+ | boolean
264
+ | {
265
+ /** When false, artifact is never installed (even with scoped CLI flags). Default true. */
266
+ enabled?: boolean;
267
+ /** When true, included in bare `install` / `install --all`. Default varies by key. */
268
+ includedInAll?: boolean;
269
+ };
270
+
271
+ export interface ResolvedInstallTarget {
272
+ enabled: boolean;
273
+ includedInAll: boolean;
274
+ }
275
+
276
+ /** Per-artifact gates for full install/uninstall. See {@link resolveEffectiveInstallTargets}. */
277
+ export interface CliInstallTargets {
278
+ /** Copy app to `~/.local/bin/<key>`. Default includedInAll true (opt-out). */
279
+ app?: InstallTargetSpec;
280
+ /** ChatGPT desktop MCP. Default false. */
281
+ chatgptMcp?: InstallTargetSpec;
282
+ /** Claude Code MCP (`~/.claude.json`). Default false. */
283
+ claudeCodeMcp?: InstallTargetSpec;
284
+ /** Claude Desktop MCP. Default false. */
285
+ claudeDesktopMcp?: InstallTargetSpec;
286
+ /** Claude Code skill. Default false. */
287
+ claudeSkill?: InstallTargetSpec;
288
+ /** Codex MCP (`codex mcp add`). Default false. */
289
+ codexMcp?: InstallTargetSpec;
290
+ /** Codex skill. Default false. */
291
+ codexSkill?: InstallTargetSpec;
292
+ /** Shell completions for detected shells. Default includedInAll true (opt-out). */
293
+ completions?: InstallTargetSpec;
294
+ /** App config: wizard on install, file removal on uninstall. Default includedInAll true. */
295
+ configure?: InstallTargetSpec;
296
+ /** Cursor MCP. Default false. */
297
+ cursorMcp?: InstallTargetSpec;
298
+ /** Cursor skill. Default false. */
299
+ cursorSkill?: InstallTargetSpec;
300
+ /** OpenClaw MCP. Default false. */
301
+ openclawMcp?: InstallTargetSpec;
302
+ /** OpenClaw skill. Default false. */
303
+ openclawSkill?: InstallTargetSpec;
304
+ /** OpenCode MCP. Default false. */
305
+ opencodeMcp?: InstallTargetSpec;
306
+ /** OpenCode skill. Default false. */
307
+ opencodeSkill?: InstallTargetSpec;
308
+ }
309
+
249
310
  /**
250
311
  * One bundled documentation topic for the `docs` built-in (program root only).
251
312
  */
package/src/validate.ts CHANGED
@@ -6,6 +6,7 @@ import { reservedCommandNames, resolveCapabilities } from "./capabilities.ts";
6
6
  import { reservedDocsTopicResourceUris } from "./docs/mcp-resources.ts";
7
7
  import { DOCS_BUILTIN_TOPIC_KEYS } from "./docs/resolve.ts";
8
8
  import { validateFormatValue } from "./formats.ts";
9
+ import { AGENT_PAIRS } from "./install/target-registry.ts";
9
10
  import { resolveMcpSchemaUri } from "./mcp/tools.ts";
10
11
  import {
11
12
  type CliLeaf,
@@ -14,6 +15,8 @@ import {
14
15
  type CliProgram,
15
16
  CliSchemaValidationError,
16
17
  CliValueFormat,
18
+ type InstallAgentIntegration,
19
+ type InstallTargetSpec,
17
20
  isCliLeaf,
18
21
  isCliRouter,
19
22
  } from "./types.ts";
@@ -105,6 +108,69 @@ function validateConfigBlock(appConfigBlock: import("./types.ts").CliAppConfig):
105
108
  }
106
109
  }
107
110
 
111
+ const PAIR_HOST_LABELS: Record<string, string> = {
112
+ cursorMcp: "cursor",
113
+ claudeCodeMcp: "claudeCode",
114
+ codexMcp: "codex",
115
+ opencodeMcp: "opencode",
116
+ openclawMcp: "openclaw",
117
+ };
118
+
119
+ function installTargetExplicitTruthy(spec: InstallTargetSpec | undefined): boolean {
120
+ if (spec === undefined || spec === false) return false;
121
+ if (spec === true) return true;
122
+ return spec.enabled !== false;
123
+ }
124
+
125
+ /** Validates `program.install` targets and agentIntegration. */
126
+ function validateInstallConfig(program: CliProgram): void {
127
+ const install = program.install;
128
+ if (!install) return;
129
+
130
+ if ("prefix" in install) {
131
+ throw new CliSchemaValidationError(
132
+ "install.prefix removed; app installs to ~/.local/bin/<key>",
133
+ );
134
+ }
135
+
136
+ if (!install.targets) return;
137
+
138
+ const targets = install.targets;
139
+ if ("allSkills" in targets || "allMcps" in targets) {
140
+ throw new CliSchemaValidationError(
141
+ "install.targets.allSkills/allMcps removed; use agentIntegration and per-key targets",
142
+ );
143
+ }
144
+
145
+ const integration: InstallAgentIntegration =
146
+ install.agentIntegration ?? (program.mcpServer?.enabled === true ? "mcp" : "skill");
147
+
148
+ for (const [mcpKey, skillKey] of AGENT_PAIRS) {
149
+ const mcpSpec = targets[mcpKey];
150
+ const skillSpec = targets[skillKey];
151
+ const mcpOn = installTargetExplicitTruthy(mcpSpec);
152
+ const skillOn = installTargetExplicitTruthy(skillSpec);
153
+ const host = PAIR_HOST_LABELS[mcpKey] ?? mcpKey;
154
+
155
+ if (mcpOn && skillOn && integration !== "both") {
156
+ throw new CliSchemaValidationError(
157
+ `install.targets: ${host} has both MCP and skill configured; set agentIntegration: 'both' or disable one side`,
158
+ );
159
+ }
160
+
161
+ if (integration === "skill" && mcpOn) {
162
+ throw new CliSchemaValidationError(
163
+ `install.targets.${mcpKey} requires agentIntegration: 'both' when agentIntegration is 'skill'`,
164
+ );
165
+ }
166
+ if (integration === "mcp" && skillOn) {
167
+ throw new CliSchemaValidationError(
168
+ `install.targets.${skillKey} requires agentIntegration: 'both' when agentIntegration is 'mcp'`,
169
+ );
170
+ }
171
+ }
172
+ }
173
+
108
174
  /** Validates a program schema. */
109
175
  export function cliValidateProgram(program: CliProgram): void {
110
176
  if (!program.version || program.version.trim().length === 0) {
@@ -142,6 +208,10 @@ export function cliValidateProgram(program: CliProgram): void {
142
208
  }
143
209
  }
144
210
 
211
+ if (program.install !== undefined) {
212
+ validateInstallConfig(program);
213
+ }
214
+
145
215
  const caps = resolveCapabilities(program);
146
216
  const reserved = reservedCommandNames(caps);
147
217