argsbarg 6.1.10 → 6.2.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 (130) hide show
  1. package/CHANGELOG.md +10 -1
  2. package/README.md +43 -41
  3. package/docs/README.md +3 -2
  4. package/docs/ai-skills.md +36 -23
  5. package/docs/cli-program.md +12 -11
  6. package/docs/config-schema.md +3 -3
  7. package/docs/configure.md +12 -16
  8. package/docs/developing.md +6 -6
  9. package/docs/mcp.md +21 -57
  10. package/docs/output-schema.md +2 -2
  11. package/examples/formats.ts +5 -6
  12. package/examples/full-example/README.md +7 -69
  13. package/examples/full-example/docs/cli-schema.json +1 -1659
  14. package/examples/full-example/docs/cli.md +2 -1538
  15. package/examples/full-example/docs/http.md +0 -7
  16. package/examples/full-example/docs/mcp.md +23 -59
  17. package/examples/full-example/docs/openapi.json +2 -782
  18. package/examples/full-example/docs/skill.md +18 -14
  19. package/examples/full-example/justfile +5 -17
  20. package/examples/full-example/scripts/create-identity.ts +2 -1
  21. package/examples/full-example/src/commands/status/command.test.ts +2 -2
  22. package/examples/full-example/src/commands/status/command.ts +7 -6
  23. package/examples/full-example/src/program.ts +4 -10
  24. package/examples/full-example-json/Formula/.gitkeep +0 -0
  25. package/examples/full-example-json/Formula/full-example-json.rb +35 -0
  26. package/examples/full-example-json/README.md +27 -0
  27. package/examples/full-example-json/biome.json +22 -0
  28. package/examples/full-example-json/bun.lock +48 -0
  29. package/examples/full-example-json/docs/README.md +27 -0
  30. package/examples/full-example-json/docs/cli-schema.json +2145 -0
  31. package/examples/full-example-json/docs/cli.md +1990 -0
  32. package/examples/full-example-json/docs/http.md +92 -0
  33. package/examples/full-example-json/docs/mcp.md +116 -0
  34. package/examples/full-example-json/docs/openapi.json +1246 -0
  35. package/examples/full-example-json/docs/skill.md +57 -0
  36. package/examples/full-example-json/justfile +171 -0
  37. package/examples/full-example-json/package.json +22 -0
  38. package/examples/full-example-json/scripts/create-identity.ts +12 -0
  39. package/examples/full-example-json/scripts/dev-formula.ts +97 -0
  40. package/examples/full-example-json/scripts/formula-shared.test.ts +68 -0
  41. package/examples/full-example-json/scripts/formula-shared.ts +170 -0
  42. package/examples/full-example-json/scripts/print-identity.ts +28 -0
  43. package/examples/full-example-json/scripts/release.ts +212 -0
  44. package/examples/full-example-json/src/commands/echo/command.ts +26 -0
  45. package/examples/full-example-json/src/commands/status/command.test.ts +10 -0
  46. package/examples/full-example-json/src/commands/status/command.ts +28 -0
  47. package/examples/full-example-json/src/index.ts +10 -0
  48. package/examples/full-example-json/src/program.ts +33 -0
  49. package/examples/full-example-json/src/types/md.d.ts +4 -0
  50. package/examples/full-example-json/tsconfig.json +17 -0
  51. package/examples/minimal.ts +17 -17
  52. package/examples/nested.ts +10 -10
  53. package/examples/option-required.ts +13 -13
  54. package/examples/servers.ts +10 -10
  55. package/index.d.ts +17 -43
  56. package/package.json +1 -1
  57. package/src/cli-tool/create.test.ts +44 -68
  58. package/src/cli-tool/create.ts +81 -17
  59. package/src/cli-tool/full-example-capabilities.test.ts +33 -18
  60. package/src/cli-tool/post-create.ts +31 -17
  61. package/src/cli-tool/program.ts +16 -7
  62. package/src/cli-tool/prompt.ts +27 -0
  63. package/src/cli-tool/run-create.ts +19 -7
  64. package/src/cli-tool/schemagen/schemagen.test.ts +3 -3
  65. package/src/configure/artifacts/install-validate.test.ts +20 -33
  66. package/src/configure/artifacts/paths.ts +9 -53
  67. package/src/configure/artifacts/status.test.ts +13 -16
  68. package/src/configure/artifacts/status.ts +5 -22
  69. package/src/configure/artifacts/target-base.ts +6 -15
  70. package/src/configure/artifacts/target-effective.ts +16 -54
  71. package/src/configure/artifacts/target-mcp-json.ts +2 -5
  72. package/src/configure/artifacts/target-registry.ts +0 -7
  73. package/src/configure/artifacts/target-scope.ts +7 -17
  74. package/src/configure/artifacts/target-skill.ts +6 -15
  75. package/src/configure/artifacts/target-types.ts +6 -54
  76. package/src/configure/artifacts/targets/agents-mcp.ts +11 -0
  77. package/src/configure/artifacts/targets/configure.ts +1 -5
  78. package/src/configure/artifacts/targets/index.ts +4 -44
  79. package/src/configure/artifacts/targets/skill.ts +12 -0
  80. package/src/configure/artifacts/targets.test.ts +21 -59
  81. package/src/configure/configure.test.ts +35 -46
  82. package/src/configure/index.ts +19 -19
  83. package/src/configure/prompt.ts +2 -12
  84. package/src/core/parse.test.ts +21 -32
  85. package/src/core/types.ts +18 -44
  86. package/src/core/validate.ts +28 -45
  87. package/src/docs/docs.test.ts +4 -4
  88. package/src/docs/mcp-guide.ts +41 -71
  89. package/src/docs/resolve.ts +1 -1
  90. package/src/exports/cli.ts +1 -1
  91. package/src/index.ts +1 -1
  92. package/src/skill/generate.ts +26 -45
  93. package/src/skill/install.ts +18 -38
  94. package/src/skill/naming.ts +3 -27
  95. package/src/test/integration/config.test.ts +3 -3
  96. package/src/test/integration/mcp.test.ts +4 -4
  97. package/{examples/mcp-test.ts → src/test/mcp-integration-fixture.ts} +20 -22
  98. package/src/configure/artifacts/target-mcp-cli.ts +0 -127
  99. package/src/configure/artifacts/targets/chatgpt-mcp.ts +0 -12
  100. package/src/configure/artifacts/targets/claude-code-mcp.ts +0 -15
  101. package/src/configure/artifacts/targets/claude-desktop-mcp.ts +0 -12
  102. package/src/configure/artifacts/targets/claude-skill.ts +0 -16
  103. package/src/configure/artifacts/targets/codex-mcp.ts +0 -25
  104. package/src/configure/artifacts/targets/codex-skill.ts +0 -14
  105. package/src/configure/artifacts/targets/cursor-mcp.ts +0 -15
  106. package/src/configure/artifacts/targets/cursor-skill.ts +0 -16
  107. package/src/configure/artifacts/targets/openclaw-mcp.ts +0 -25
  108. package/src/configure/artifacts/targets/openclaw-skill.ts +0 -17
  109. package/src/configure/artifacts/targets/opencode-mcp.ts +0 -96
  110. package/src/configure/artifacts/targets/opencode-skill.ts +0 -15
  111. /package/examples/{full-example → full-example-json}/src/commands/render-json/__generated__/RenderJsonInputSchema.json +0 -0
  112. /package/examples/{full-example → full-example-json}/src/commands/render-json/__generated__/index.ts +0 -0
  113. /package/examples/{full-example → full-example-json}/src/commands/render-json/command.test.ts +0 -0
  114. /package/examples/{full-example → full-example-json}/src/commands/render-json/command.ts +0 -0
  115. /package/examples/{full-example → full-example-json}/src/commands/render-json/types.ts +0 -0
  116. /package/examples/{full-example → full-example-json}/src/commands/status/__generated__/StatusJsonOutputSchema.json +0 -0
  117. /package/examples/{full-example → full-example-json}/src/commands/status/__generated__/index.ts +0 -0
  118. /package/examples/{full-example → full-example-json}/src/commands/status/types.ts +0 -0
  119. /package/examples/{full-example → full-example-json}/src/commands/workspaces/__generated__/WorkspaceNameInputSchema.json +0 -0
  120. /package/examples/{full-example → full-example-json}/src/commands/workspaces/__generated__/index.ts +0 -0
  121. /package/examples/{full-example → full-example-json}/src/commands/workspaces/command.test.ts +0 -0
  122. /package/examples/{full-example → full-example-json}/src/commands/workspaces/command.ts +0 -0
  123. /package/examples/{full-example → full-example-json}/src/commands/workspaces/types.ts +0 -0
  124. /package/examples/{full-example → full-example-json}/src/db/index.test.ts +0 -0
  125. /package/examples/{full-example → full-example-json}/src/db/index.ts +0 -0
  126. /package/examples/{full-example → full-example-json}/src/db/migrate.test.ts +0 -0
  127. /package/examples/{full-example → full-example-json}/src/db/migrate.ts +0 -0
  128. /package/examples/{full-example → full-example-json}/src/db/migrations/001_workspaces.sql +0 -0
  129. /package/examples/{full-example → full-example-json}/src/db/tables/workspaces.ts +0 -0
  130. /package/examples/{full-example → full-example-json}/src/types/argsbarg.d.ts +0 -0
@@ -1149,13 +1149,17 @@ test("configure.prefix is rejected", () => {
1149
1149
 
1150
1150
  /** Tests that generateSkillBundle includes frontmatter and compact command index. */
1151
1151
  test("generateSkillBundle includes frontmatter and compact command index", () => {
1152
- const bundle = generateSkillBundle(nestedMcpFixture, "cursor");
1153
- expect(bundle.dirName).toBe("nested_ts");
1154
- expect(bundle.skillMd).toMatch(/^---\nname: nested_ts\n/);
1152
+ const bundle = generateSkillBundle(nestedMcpFixture);
1153
+ expect(bundle.dirName).toBe("nested.ts");
1154
+ expect(bundle.skillMd).toMatch(/^---\nid: nested\.ts\nname: nested\.ts\n/);
1155
+ expect(bundle.skillMd).toContain("enabled: true");
1156
+ expect(bundle.skillMd).toContain("dotagentsprotocol.com");
1157
+ expect(bundle.skillMd).toContain("~/.claude/skills/nested.ts");
1155
1158
  expect(bundle.skillMd).toContain("## Commands");
1156
1159
  expect(bundle.skillMd).toContain("`nested.ts stat owner lookup <path>`");
1157
1160
  expect(bundle.skillMd).toContain("Invoke via shell:");
1158
1161
  expect(bundle.skillMd).toContain("For full detail, open `reference.md`");
1162
+ expect(bundle.skillMd).toContain("~/.agents/skills/nested.ts/");
1159
1163
  expect(bundle.skillMd).not.toContain("#### Options");
1160
1164
  expect(bundle.skillMd).not.toContain("CLI API reference");
1161
1165
  expect(bundle.skillMd).not.toContain("mcp.json");
@@ -1183,15 +1187,15 @@ test("generatePluginSkillBundle is MCP routing stub without shell catalog", () =
1183
1187
  expect(bundle.skillMd).not.toContain("## Commands");
1184
1188
  });
1185
1189
 
1186
- /** CliSkillInstall writes project Cursor skill files. */
1187
- test("cliSkillInstall writes project Cursor skill files", () => {
1190
+ /** CliSkillInstall writes project agent skill files. */
1191
+ test("cliSkillInstall writes project agent skill files", () => {
1188
1192
  const cwd = mkdtempSync(join(tmpdir(), "argsbarg-skill-"));
1189
1193
  const prev = process.cwd();
1190
1194
  process.chdir(cwd);
1191
1195
  try {
1192
- const files = cliSkillInstall(nestedMcpFixture, "cursor", { rimraf: true });
1193
- expect(files.some((f) => f.includes(".cursor/skills/nested_ts/"))).toBe(true);
1194
- const skillDir = join(cwd, ".cursor", "skills", "nested_ts");
1196
+ const files = cliSkillInstall(nestedMcpFixture, { global: false, rimraf: true });
1197
+ expect(files.some((f) => f.includes(".agents/skills/nested.ts/"))).toBe(true);
1198
+ const skillDir = join(cwd, ".agents", "skills", "nested.ts");
1195
1199
  expect(existsSync(join(skillDir, "SKILL.md"))).toBe(true);
1196
1200
  expect(existsSync(join(skillDir, "reference.md"))).toBe(true);
1197
1201
  expect(readFileSync(join(skillDir, "SKILL.md"), "utf8")).toContain("## Commands");
@@ -1208,15 +1212,15 @@ test("cliSkillInstall writes project Cursor skill files", () => {
1208
1212
  }
1209
1213
  });
1210
1214
 
1211
- /** CliSkillInstall global uses HOME skills directory. */
1212
- test("cliSkillInstall global uses HOME skills directory", () => {
1215
+ /** CliSkillInstall global uses HOME agents skills directory. */
1216
+ test("cliSkillInstall global uses HOME agents skills directory", () => {
1213
1217
  const home = mkdtempSync(join(tmpdir(), "argsbarg-home-"));
1214
1218
  const prevHome = process.env.HOME;
1215
1219
  process.env.HOME = home;
1216
1220
  try {
1217
- const files = cliSkillInstall(nestedMcpFixture, "cursor", { global: true, rimraf: true });
1218
- expect(files.some((f) => f.includes(join(home, ".cursor", "skills", "nested_ts")))).toBe(true);
1219
- expect(existsSync(join(home, ".cursor", "skills", "nested_ts", "SKILL.md"))).toBe(true);
1221
+ const files = cliSkillInstall(nestedMcpFixture, { global: true, rimraf: true });
1222
+ expect(files.some((f) => f.includes(join(home, ".agents", "skills", "nested.ts")))).toBe(true);
1223
+ expect(existsSync(join(home, ".agents", "skills", "nested.ts", "SKILL.md"))).toBe(true);
1220
1224
  } finally {
1221
1225
  if (prevHome === undefined) {
1222
1226
  delete process.env.HOME;
@@ -1233,11 +1237,11 @@ test("cliSkillInstall rimraf overwrites existing directory", () => {
1233
1237
  const prev = process.cwd();
1234
1238
  process.chdir(cwd);
1235
1239
  try {
1236
- cliSkillInstall(nestedMcpFixture, "cursor", { rimraf: true });
1237
- writeFileSync(join(cwd, ".cursor", "skills", "nested_ts", "SKILL.md"), "stale", "utf8");
1238
- const files = cliSkillInstall(nestedMcpFixture, "cursor", { rimraf: true });
1240
+ cliSkillInstall(nestedMcpFixture, { global: false, rimraf: true });
1241
+ writeFileSync(join(cwd, ".agents", "skills", "nested.ts", "SKILL.md"), "stale", "utf8");
1242
+ const files = cliSkillInstall(nestedMcpFixture, { global: false, rimraf: true });
1239
1243
  expect(files.length).toBeGreaterThan(0);
1240
- expect(readFileSync(join(cwd, ".cursor", "skills", "nested_ts", "SKILL.md"), "utf8")).toContain(
1244
+ expect(readFileSync(join(cwd, ".agents", "skills", "nested.ts", "SKILL.md"), "utf8")).toContain(
1241
1245
  "stat owner lookup",
1242
1246
  );
1243
1247
  } finally {
@@ -1245,18 +1249,3 @@ test("cliSkillInstall rimraf overwrites existing directory", () => {
1245
1249
  rmSync(cwd, { recursive: true, force: true });
1246
1250
  }
1247
1251
  });
1248
-
1249
- /** CliSkillInstall claude target uses .claude/skills. */
1250
- test("cliSkillInstall claude target uses .claude/skills", () => {
1251
- const cwd = mkdtempSync(join(tmpdir(), "argsbarg-skill-claude-"));
1252
- const prev = process.cwd();
1253
- process.chdir(cwd);
1254
- try {
1255
- const files = cliSkillInstall(nestedMcpFixture, "claude", { rimraf: true });
1256
- expect(files.some((f) => f.includes(".claude/skills/nested_ts/"))).toBe(true);
1257
- expect(readFileSync(join(cwd, ".claude", "skills", "nested_ts", "SKILL.md"), "utf8")).toContain("Claude Code");
1258
- } finally {
1259
- process.chdir(prev);
1260
- rmSync(cwd, { recursive: true, force: true });
1261
- }
1262
- });
package/src/core/types.ts CHANGED
@@ -404,24 +404,20 @@ export interface CliCompletionConfig {
404
404
  enabled?: boolean;
405
405
  }
406
406
 
407
+ /** Opt-in agent skill install to `~/.agents/skills/<key>/` (default: disabled). */
408
+ export interface CliSkillConfig {
409
+ /** When `true`, install and sync the agent skill via `configure --sync`. Default false when omitted. */
410
+ enabled?: boolean;
411
+ }
412
+
407
413
  /** @experimental */
408
414
  export interface CliConfigureConfig {
409
415
  /** When `false`, hide/disable `configure` (default: enabled). */
410
416
  enabled?: boolean;
411
- /**
412
- * Default agent integration for sync (`configure --sync`).
413
- * - `'mcp'` when `mcpServer.enabled` (default): MCP targets in sync; paired skills excluded.
414
- * - `'skill'` when MCP is off (default): skill targets in sync; paired MCP excluded.
415
- * - `'both'`: sync MCP and skill for the same host when both are available.
416
- */
417
- agentIntegration?: InstallAgentIntegration;
418
417
  /** Per-artifact gates for configure sync and interactive wizard. See {@link resolveEffectiveInstallTargets}. */
419
418
  targets?: CliConfigureTargets;
420
419
  }
421
420
 
422
- /** Agent integration mode for install — MCP vs shell skill per host. */
423
- export type InstallAgentIntegration = "mcp" | "skill" | "both";
424
-
425
421
  /** Boolean or structured gate for one install artifact. */
426
422
  export type InstallTargetSpec =
427
423
  | boolean
@@ -441,32 +437,8 @@ export interface ResolvedInstallTarget {
441
437
  export interface CliConfigureTargets {
442
438
  /** App binary status only (Homebrew PATH); no self-install. */
443
439
  app?: InstallTargetSpec;
444
- /** ChatGPT desktop MCP. Default false. */
445
- chatgptMcp?: InstallTargetSpec;
446
- /** Claude Code MCP (`~/.claude.json`). Default false. */
447
- claudeCodeMcp?: InstallTargetSpec;
448
- /** Claude Desktop MCP. Default false. */
449
- claudeDesktopMcp?: InstallTargetSpec;
450
- /** Claude Code skill. Default false. */
451
- claudeSkill?: InstallTargetSpec;
452
- /** Codex MCP (`codex mcp add`). Default false. */
453
- codexMcp?: InstallTargetSpec;
454
- /** Codex skill. Default false. */
455
- codexSkill?: InstallTargetSpec;
456
440
  /** App config: interactive wizard step in `configure`. Default not in sync. */
457
441
  configure?: InstallTargetSpec;
458
- /** Cursor MCP. Default false. */
459
- cursorMcp?: InstallTargetSpec;
460
- /** Cursor skill. Default false. */
461
- cursorSkill?: InstallTargetSpec;
462
- /** OpenClaw MCP. Default false. */
463
- openclawMcp?: InstallTargetSpec;
464
- /** OpenClaw skill. Default false. */
465
- openclawSkill?: InstallTargetSpec;
466
- /** OpenCode MCP. Default false. */
467
- opencodeMcp?: InstallTargetSpec;
468
- /** OpenCode skill. Default false. */
469
- opencodeSkill?: InstallTargetSpec;
470
442
  }
471
443
 
472
444
  /**
@@ -672,26 +644,28 @@ export interface CliLogConfig {
672
644
  * May be a leaf or router, plus optional program-level MCP and install config.
673
645
  */
674
646
  export type CliProgram = CliNode & {
675
- /** Program version (printed by the `version` built-in and MCP serverInfo). */
676
- version: string;
677
647
  /** Schema-driven app config file, bootstrap, and MCP metadata. */
678
648
  appConfig?: CliAppConfig;
679
- /** When set with `enabled: true`, enables the `mcp` built-in subcommand. */
680
- mcpServer?: CliMcpServerConfig;
681
- /** When set with `enabled: true`, enables the `http` built-in HTTP server. */
682
- httpServer?: CliHttpServerConfig;
683
- /** Opt-out and defaults for `configure`. */
684
- configure?: CliConfigureConfig;
685
649
  /** Opt-out for shell completion generation (`completion bash|zsh|fish`). */
686
650
  completion?: CliCompletionConfig;
651
+ /** Opt-out and defaults for `configure`. */
652
+ configure?: CliConfigureConfig;
687
653
  /** Opt-out and optional topics for the `docs` built-in (default: enabled). */
688
654
  docs?: CliDocsConfig;
689
655
  /** Invoke and error hooks for user commands on CLI, HTTP, and MCP. */
690
656
  hooks?: CliProgramHooks;
691
- /** Optional readiness probe for HTTP/MCP `GET /health/readiness` only. */
692
- readiness?: (ctx: ReadinessContext) => boolean | Promise<boolean>;
657
+ /** When set with `enabled: true`, enables the `http` built-in HTTP server. */
658
+ httpServer?: CliHttpServerConfig;
693
659
  /** Framework logging (stderr + optional file). */
694
660
  log?: CliLogConfig;
661
+ /** When set with `enabled: true`, enables the `mcp` built-in subcommand. */
662
+ mcpServer?: CliMcpServerConfig;
663
+ /** Optional readiness probe for HTTP/MCP `GET /health/readiness` only. */
664
+ readiness?: (ctx: ReadinessContext) => boolean | Promise<boolean>;
665
+ /** Opt-in agent skill (`~/.agents/skills/<key>/`). Default disabled when omitted. */
666
+ skill?: CliSkillConfig;
667
+ /** Program version (printed by the `version` built-in and MCP serverInfo). */
668
+ version: string;
695
669
  };
696
670
 
697
671
  /** True when the node is a leaf (has a handler). */
@@ -2,7 +2,6 @@
2
2
  This module validates CLI schemas before execution.
3
3
  */
4
4
 
5
- import { AGENT_PAIRS, MCP_KEYS, mcpServerRequiredForArtifact } from "../configure/artifacts/target-registry.ts";
6
5
  import { reservedDocsTopicResourceUris } from "../docs/mcp-resources.ts";
7
6
  import { DOCS_BUILTIN_TOPIC_KEYS, docsEnabled } from "../docs/resolve.ts";
8
7
  import { HTTP_RESERVED_TOP_LEVEL_SEGMENTS } from "../http/paths.ts";
@@ -16,8 +15,6 @@ import {
16
15
  type CliProgram,
17
16
  CliSchemaValidationError,
18
17
  CliValueFormat,
19
- type InstallAgentIntegration,
20
- type InstallTargetSpec,
21
18
  isCliLeaf,
22
19
  isCliRouter,
23
20
  isJsonLeaf,
@@ -98,21 +95,7 @@ function validateConfigBlock(appConfigBlock: import("./types.ts").CliAppConfig):
98
95
  }
99
96
  }
100
97
 
101
- const PAIR_HOST_LABELS: Record<string, string> = {
102
- cursorMcp: "cursor",
103
- claudeCodeMcp: "claudeCode",
104
- codexMcp: "codex",
105
- opencodeMcp: "opencode",
106
- openclawMcp: "openclaw",
107
- };
108
-
109
- function installTargetExplicitTruthy(spec: InstallTargetSpec | undefined): boolean {
110
- if (spec === undefined || spec === false) return false;
111
- if (spec === true) return true;
112
- return spec.enabled !== false;
113
- }
114
-
115
- /** Validates `program.configure` targets and agentIntegration. */
98
+ /** Validates `program.configure` targets. */
116
99
  function validateConfigureConfig(program: CliProgram): void {
117
100
  const configure = program.configure;
118
101
  if (!configure) return;
@@ -121,48 +104,48 @@ function validateConfigureConfig(program: CliProgram): void {
121
104
  throw new CliSchemaValidationError("configure.prefix removed; app binary installs via Homebrew");
122
105
  }
123
106
 
107
+ if ("agentIntegration" in configure) {
108
+ throw new CliSchemaValidationError("configure.agentIntegration removed; use program.skill.enabled for skills");
109
+ }
110
+
124
111
  if (!configure.targets) return;
125
112
 
126
113
  const targets = configure.targets;
127
114
  if ("allSkills" in targets || "allMcps" in targets) {
128
- throw new CliSchemaValidationError(
129
- "configure.targets.allSkills/allMcps removed; use agentIntegration and per-key targets",
130
- );
115
+ throw new CliSchemaValidationError("configure.targets.allSkills/allMcps removed; use per-key targets");
131
116
  }
132
117
 
133
- const integration: InstallAgentIntegration =
134
- configure.agentIntegration ?? (program.mcpServer?.enabled === true ? "mcp" : "skill");
135
-
136
- const mcpEnabled = program.mcpServer?.enabled === true;
137
-
138
- for (const [mcpKey, skillKey] of AGENT_PAIRS) {
139
- const mcpSpec = targets[mcpKey];
140
- const skillSpec = targets[skillKey];
141
- const mcpOn = installTargetExplicitTruthy(mcpSpec);
142
- const skillOn = installTargetExplicitTruthy(skillSpec);
143
- const host = PAIR_HOST_LABELS[mcpKey] ?? mcpKey;
144
-
145
- if (mcpOn && skillOn && integration !== "both") {
118
+ const legacySkillKeys = ["cursorSkill", "claudeSkill", "codexSkill", "opencodeSkill", "openclawSkill"] as const;
119
+ for (const key of legacySkillKeys) {
120
+ if (key in targets) {
146
121
  throw new CliSchemaValidationError(
147
- `configure.targets: ${host} has both MCP and skill configured; set agentIntegration: 'both' or disable one side`,
122
+ `configure.targets.${key} removed; use program.skill.enabled for agent skill install`,
148
123
  );
149
124
  }
125
+ }
150
126
 
151
- if (integration === "skill" && mcpOn) {
152
- throw new CliSchemaValidationError(
153
- `configure.targets.${mcpKey} requires agentIntegration: 'both' when agentIntegration is 'skill'`,
154
- );
155
- }
156
- if (integration === "mcp" && skillOn) {
127
+ const legacyMcpKeys = [
128
+ "cursorMcp",
129
+ "claudeCodeMcp",
130
+ "claudeDesktopMcp",
131
+ "codexMcp",
132
+ "chatgptMcp",
133
+ "openclawMcp",
134
+ "opencodeMcp",
135
+ "agentsMcp",
136
+ ] as const;
137
+ for (const key of legacyMcpKeys) {
138
+ if (key in targets) {
157
139
  throw new CliSchemaValidationError(
158
- `configure.targets.${skillKey} requires agentIntegration: 'both' when agentIntegration is 'mcp'`,
140
+ `configure.targets.${key} removed; MCP installs to ~/.agents/mcp.json when mcpServer.enabled`,
159
141
  );
160
142
  }
161
143
  }
162
144
 
163
- for (const mcpKey of MCP_KEYS) {
164
- if (!mcpServerRequiredForArtifact(mcpKey, mcpEnabled) && installTargetExplicitTruthy(targets[mcpKey])) {
165
- throw new CliSchemaValidationError(`configure.targets.${mcpKey} requires mcpServer.enabled`);
145
+ const allowedKeys = new Set(["app", "configure"]);
146
+ for (const key of Object.keys(targets)) {
147
+ if (!allowedKeys.has(key)) {
148
+ throw new CliSchemaValidationError(`configure.targets.${key} is not a valid target key`);
166
149
  }
167
150
  }
168
151
  }
@@ -296,17 +296,17 @@ test("completions offer docs subcommands", () => {
296
296
  expect(bash).toContain("skill) echo");
297
297
  });
298
298
 
299
- test("generateMcpGuide includes schema URI and configure sync", () => {
299
+ test("generateMcpGuide includes schema URI and .agents install", () => {
300
300
  const guide = generateMcpGuide(docsFixture(true));
301
301
  expect(guide).toContain("myapp://schema");
302
+ expect(guide).toContain("~/.agents/mcp.json");
302
303
  expect(guide).toContain("~/.cursor/mcp.json");
303
304
  expect(guide).toContain("claude_desktop_config.json");
304
305
  expect(guide).toContain("## Installation");
305
306
  expect(guide).toContain("## Running directly");
306
307
  expect(guide).toContain("configure --sync");
307
- expect(guide).toContain("brew install myapp");
308
- expect(guide).toContain("OpenAI Codex");
309
- expect(guide).toContain("ChatGPT");
308
+ expect(guide).toContain("dotagentsprotocol.com");
309
+ expect(guide).not.toContain("OpenAI Codex");
310
310
  });
311
311
 
312
312
  test("docs --save writes topic file", async () => {
@@ -1,6 +1,7 @@
1
1
  import { defaultConfigEntryTitle } from "../config/entry.ts";
2
2
  import { displayAppConfigPath } from "../config/file.ts";
3
- import { expectedOpenCodeMcpEntry, OPENCODE_CONFIG_SCHEMA } from "../configure/artifacts/mcp-opencode.ts";
3
+ import { expectedMcpEntry } from "../configure/artifacts/mcp-config.ts";
4
+ import { resolveClaudeDesktopMcpPath, userHome } from "../configure/artifacts/paths.ts";
4
5
  import { collectOptionDefs } from "../core/parse.ts";
5
6
  import { CliOptionKind, type CliProgram } from "../core/types.ts";
6
7
  import { collectMcpTools, type McpToolDef, mcpServerId, resolveMcpSchemaUri } from "../mcp/tools.ts";
@@ -8,64 +9,41 @@ import { resolveCapabilities } from "../runtime/capabilities.ts";
8
9
  import { resolveDocsTopicResourceUri } from "./mcp-resources.ts";
9
10
  import { docsEnabled, docsUserTopicKeys, resolveDocsConfig } from "./resolve.ts";
10
11
 
11
- /** Extra host notes for generated `docs mcp` (manual fallbacks and ChatGPT Connectors). */
12
- function appendManualHostSetup(lines: string[], root: CliProgram, serverId: string): void {
13
- const openCodeEntry = expectedOpenCodeMcpEntry(root);
12
+ /** Extra manual client setup notes for generated `docs mcp`. */
13
+ function appendManualClientSetup(
14
+ lines: string[],
15
+ _root: CliProgram,
16
+ serverId: string,
17
+ entry: { command: string; args: string[] },
18
+ ): void {
19
+ const home = userHome();
20
+ const claudeDesktopPath = resolveClaudeDesktopMcpPath(home);
21
+ const mcpServersJson = JSON.stringify({ mcpServers: { [serverId]: entry } }, null, 2);
14
22
 
15
23
  lines.push(
16
- "| OpenCode | `~/.config/opencode/*` (when `~/.config/opencode` exists) |",
17
- "| OpenAI Codex | `~/.codex/config.toml` via `codex mcp add` (when `codex` is on PATH) |",
18
- "| ChatGPT desktop | `chatgpt_mcp_config.json` (when ChatGPT app data exists) |",
24
+ "### Manual client setup",
19
25
  "",
20
- "Claude Desktop paths by platform:",
21
- "",
22
- "- **macOS:** `~/Library/Application Support/Claude/claude_desktop_config.json`",
23
- "- **Windows:** `%APPDATA%\\Claude\\claude_desktop_config.json`",
24
- "- **Linux:** `~/.config/Claude/claude_desktop_config.json`",
25
- "",
26
- "ChatGPT desktop JSON (when auto-installed):",
27
- "",
28
- "- **macOS:** `~/Library/Application Support/ChatGPT/chatgpt_mcp_config.json`",
29
- "- **Windows:** `%APPDATA%\\OpenAI\\ChatGPT\\chatgpt_mcp_config.json`",
30
- "",
31
- "Restart Claude Desktop and ChatGPT desktop after changing their config files.",
32
- "",
33
- "### Manual fallbacks",
34
- "",
35
- "**OpenCode** (no `~/.config/opencode` yet):",
26
+ "Many clients do not read `~/.agents/mcp.json` yet. Copy the `mcpServers` entry from that file, or paste:",
36
27
  "",
37
28
  "```json",
38
- JSON.stringify(
39
- {
40
- $schema: OPENCODE_CONFIG_SCHEMA,
41
- mcp: { [serverId]: openCodeEntry },
42
- },
43
- null,
44
- 2,
45
- ),
46
- "```",
47
- "",
48
- "**Codex** (`codex` not on PATH):",
49
- "",
50
- "```toml",
51
- `[mcp_servers.${serverId}]`,
52
- `command = "${root.key}"`,
53
- 'args = ["mcp"]',
29
+ mcpServersJson,
54
30
  "```",
55
31
  "",
56
- `Or after installing Codex CLI: \`codex mcp add ${serverId} -- ${root.key} mcp\`.`,
57
- "",
58
- "### ChatGPT web (Connectors)",
32
+ "| Client | Config file |",
33
+ "| --- | --- |",
34
+ "| **Cursor** | `~/.cursor/mcp.json` (global) or `.cursor/mcp.json` (project) |",
35
+ "| **Claude Code** | `~/.claude.json` under `mcpServers`, or project `.mcp.json` |",
36
+ "| **Claude Desktop** | See platform paths below |",
59
37
  "",
60
- `OpenAI's documented path for **ChatGPT web/desktop** is **Settings → Connectors → Developer mode** with a **remote HTTPS MCP URL** — not local stdio. ChatGPT does not spawn \`${root.key} mcp\` directly.`,
38
+ "Restart Cursor or reload MCP after editing. Restart Claude Desktop after config changes.",
61
39
  "",
62
- "For local stdio, bridge and tunnel, then register the HTTPS URL in Connectors:",
40
+ "Claude Desktop config paths:",
63
41
  "",
64
- `1. Expose \`${root.key} mcp\` over HTTP (e.g. \`mcp-remote\`).`,
65
- "2. Tunnel if needed (ngrok, Cloudflare Tunnel).",
66
- "3. Add the public URL as a custom connector.",
42
+ "- **macOS:** `~/Library/Application Support/Claude/claude_desktop_config.json`",
43
+ "- **Windows:** `%APPDATA%\\Claude\\claude_desktop_config.json`",
44
+ "- **Linux:** `~/.config/Claude/claude_desktop_config.json`",
67
45
  "",
68
- "Desktop `chatgpt_mcp_config.json` is merged when the ChatGPT app is installed; support varies by build. Use Connectors when local JSON is absent or tools do not appear.",
46
+ `On this machine (macOS/Linux): \`${claudeDesktopPath}\``,
69
47
  "",
70
48
  );
71
49
  }
@@ -92,6 +70,7 @@ export function generateMcpGuide(root: CliProgram): string {
92
70
  throw new Error("MCP server not enabled");
93
71
  }
94
72
  const caps = resolveCapabilities(root);
73
+ const entry = expectedMcpEntry(root);
95
74
 
96
75
  const lines: string[] = [
97
76
  `# MCP server (${root.key})`,
@@ -100,17 +79,16 @@ export function generateMcpGuide(root: CliProgram): string {
100
79
  "",
101
80
  "## Installation",
102
81
  "",
103
- "### `configure`",
82
+ "### `.agents` auto-install",
83
+ "",
84
+ "When `mcpServer.enabled` is set, `configure --sync` merges this server into `~/.agents/mcp.json` per the [.agents protocol](https://dotagentsprotocol.com/).",
104
85
  "",
105
86
  ];
106
87
 
107
88
  if (caps.configure) {
108
- lines.push(
109
- `Install the CLI first so \`${root.key}\` is on your PATH (e.g. \`brew install ${root.key}\`). Host configs reference the app by name.`,
110
- "",
111
- );
89
+ lines.push(`Install the CLI first so \`${root.key}\` is on your PATH (e.g. \`brew install ${root.key}\`).`, "");
112
90
  } else {
113
- lines.push(`The CLI binary \`${root.key}\` must already be on your PATH. Host configs reference it by name.`, "");
91
+ lines.push(`The CLI binary \`${root.key}\` must already be on your PATH.`, "");
114
92
  }
115
93
 
116
94
  lines.push(
@@ -118,30 +96,22 @@ export function generateMcpGuide(root: CliProgram): string {
118
96
  `${root.key} configure --sync --yes`,
119
97
  "```",
120
98
  "",
121
- "Merges the server entry below into host config when each host is present:",
99
+ "Writes or updates `~/.agents/mcp.json` with a `mcpServers` entry for this app.",
122
100
  "",
123
- "| Host | Config file |",
124
- "| --- | --- |",
125
- "| Cursor | `~/.cursor/mcp.json` (when `~/.cursor` exists) |",
126
- "| Claude Code | `~/.claude.json` |",
127
- "| Claude Desktop | `claude_desktop_config.json` (when Claude Desktop app data exists) |",
128
101
  );
129
102
 
130
- appendManualHostSetup(lines, root, serverId);
103
+ appendManualClientSetup(lines, root, serverId, entry);
131
104
 
132
105
  lines.push(
133
106
  "### Manual `mcpServers` entry",
134
107
  "",
135
- "For Cursor, Claude, and ChatGPT desktop JSON configs, add under `mcpServers`:",
108
+ "Same shape as in `~/.agents/mcp.json`:",
136
109
  "",
137
110
  "```json",
138
111
  JSON.stringify(
139
112
  {
140
113
  mcpServers: {
141
- [serverId]: {
142
- command: root.key,
143
- args: ["mcp"],
144
- },
114
+ [serverId]: entry,
145
115
  },
146
116
  },
147
117
  null,
@@ -174,11 +144,11 @@ export function generateMcpGuide(root: CliProgram): string {
174
144
  `Default config file: \`${displayAppConfigPath(root)}\` (flat JSON keys).`,
175
145
  "",
176
146
  );
177
- for (const [key, entry] of Object.entries(root.appConfig.entries)) {
178
- const label = entry.title ?? defaultConfigEntryTitle(key);
179
- const req = entry.required === false ? "optional" : "required";
180
- const envNote = entry.env ? ` → env \`${entry.env}\`` : "";
181
- lines.push(`- **${label}** (\`${key}\`, ${req}${envNote}) — ${entry.description}`);
147
+ for (const [key, entryConfig] of Object.entries(root.appConfig.entries)) {
148
+ const label = entryConfig.title ?? defaultConfigEntryTitle(key);
149
+ const req = entryConfig.required === false ? "optional" : "required";
150
+ const envNote = entryConfig.env ? ` → env \`${entryConfig.env}\`` : "";
151
+ lines.push(`- **${label}** (\`${key}\`, ${req}${envNote}) — ${entryConfig.description}`);
182
152
  }
183
153
  lines.push(
184
154
  "",
@@ -99,7 +99,7 @@ export function docsTopicContent(program: CliProgram, topic: string): string {
99
99
  return generateCliGuide(program);
100
100
  }
101
101
  if (topic === "skill") {
102
- return `${generateSkillBundle(program, "cursor").skillMd}\n`;
102
+ return `${generateSkillBundle(program).skillMd}\n`;
103
103
  }
104
104
  const text = docsTopicText(program, topic);
105
105
  return text.endsWith("\n") ? text : `${text}\n`;
@@ -32,7 +32,7 @@ export type {
32
32
  CliProgram,
33
33
  CliRespondBody,
34
34
  CliRespondOptions,
35
- InstallAgentIntegration,
35
+ CliSkillConfig,
36
36
  InstallTargetSpec,
37
37
  ResolvedInstallTarget,
38
38
  } from "../core/types.ts";
package/src/index.ts CHANGED
@@ -52,8 +52,8 @@ export type {
52
52
  CliProgramHooks,
53
53
  CliRespondBody,
54
54
  CliRespondOptions,
55
+ CliSkillConfig,
55
56
  ErrorHookContext,
56
- InstallAgentIntegration,
57
57
  InstallTargetSpec,
58
58
  InvokeFailureKind,
59
59
  InvokeHookContext,
@@ -13,10 +13,7 @@ import {
13
13
  resolveMcpSchemaUri,
14
14
  sanitizeToolSegment,
15
15
  } from "../mcp/tools.ts";
16
- import type { SkillTarget } from "./naming.ts";
17
- import { skillDirNameForTarget, skillFrontmatterName } from "./naming.ts";
18
-
19
- export type { SkillTarget } from "./naming.ts";
16
+ import { skillDirName } from "./naming.ts";
20
17
 
21
18
  export interface SkillBundle {
22
19
  dirName: string;
@@ -103,16 +100,18 @@ function buildConfigurationSection(root: CliProgram): string[] {
103
100
  return lines;
104
101
  }
105
102
 
106
- /** Builds SKILL.md body for the given target. */
107
- function buildSkillMd(root: CliProgram, target: SkillTarget, dirName: string): string {
108
- const name = skillFrontmatterName(root.key, target);
103
+ /** Builds SKILL.md body for the agent skill bundle. */
104
+ function buildSkillMd(root: CliProgram, dirName: string): string {
105
+ const name = dirName;
109
106
  const description = skillDescription(root);
110
107
  const tools = collectMcpTools(root);
111
108
 
112
109
  const lines: string[] = [
113
110
  "---",
111
+ `id: ${dirName}`,
114
112
  `name: ${name}`,
115
113
  `description: ${description}`,
114
+ "enabled: true",
116
115
  "---",
117
116
  "",
118
117
  `# ${root.key}`,
@@ -151,42 +150,24 @@ function buildSkillMd(root: CliProgram, target: SkillTarget, dirName: string): s
151
150
  "",
152
151
  `For full detail, open \`reference.md\` in this skill directory (same as \`${root.key} docs cli\`).`,
153
152
  "",
153
+ "## Install location",
154
+ "",
155
+ "Install follows the [.agents protocol](https://dotagentsprotocol.com/):",
156
+ "",
157
+ `- Auto-install: \`${root.key} configure --sync --yes\` when \`skill.enabled\` → \`~/.agents/skills/${dirName}/\``,
158
+ `- Cursor and most coding agents read \`~/.agents/skills/\` natively`,
159
+ "",
160
+ "**Claude Code (manual):** symlink or copy into Claude's skill directory:",
161
+ "",
162
+ "```bash",
163
+ "mkdir -p ~/.claude/skills",
164
+ `ln -sf ~/.agents/skills/${dirName} ~/.claude/skills/${dirName}`,
165
+ "```",
166
+ "",
167
+ `Project override (optional): \`.agents/skills/${dirName}/\``,
168
+ "",
154
169
  );
155
170
 
156
- if (target === "cursor") {
157
- lines.push(
158
- "## Cursor install location",
159
- "",
160
- `- Project: \`.cursor/skills/${dirName}/\``,
161
- `- Global: \`~/.cursor/skills/${dirName}/\``,
162
- "",
163
- "Do not install under `~/.cursor/skills-cursor/` (reserved for Cursor built-ins).",
164
- "",
165
- );
166
- } else if (target === "claude") {
167
- lines.push(
168
- "## Claude Code",
169
- "",
170
- `- Invoke with \`/${dirName}\` or let Claude auto-match from the description.`,
171
- `- Project skills: \`.claude/skills/${dirName}/\``,
172
- `- Global skills: \`~/.claude/skills/${dirName}/\``,
173
- `- Bundled files in this directory are available via \`\${CLAUDE_SKILL_DIR}\` when the skill runs.`,
174
- "",
175
- );
176
- } else if (target === "codex") {
177
- lines.push(
178
- "## Codex",
179
- "",
180
- `- Global: \`~/.codex/skills/${dirName}/\``,
181
- "- Enable skills in `~/.codex/config.toml` if required.",
182
- "",
183
- );
184
- } else if (target === "opencode") {
185
- lines.push("## OpenCode", "", `- Global: \`~/.config/opencode/skills/${dirName}/\``, "");
186
- } else {
187
- lines.push("## OpenClaw", "", `- Global: \`~/.openclaw/skills/${dirName}/\``, "");
188
- }
189
-
190
171
  return lines.join("\n");
191
172
  }
192
173
 
@@ -243,12 +224,12 @@ export function generatePluginSkillBundle(root: CliProgram): PluginSkillBundle {
243
224
  };
244
225
  }
245
226
 
246
- /** Generates SKILL.md and reference.md for Cursor or Claude Code. */
247
- export function generateSkillBundle(root: CliProgram, target: SkillTarget): SkillBundle {
248
- const dirName = skillDirNameForTarget(root.key, target);
227
+ /** Generates SKILL.md and reference.md for agent skill install. */
228
+ export function generateSkillBundle(root: CliProgram): SkillBundle {
229
+ const dirName = skillDirName(root.key);
249
230
  return {
250
231
  dirName,
251
- skillMd: buildSkillMd(root, target, dirName),
232
+ skillMd: buildSkillMd(root, dirName),
252
233
  referenceMd: buildReferenceMd(root),
253
234
  };
254
235
  }