agents-inc 0.154.0 → 0.156.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 (213) hide show
  1. package/CHANGELOG.md +55 -0
  2. package/dist/chunk-2H7UWE2G.js +246 -0
  3. package/dist/chunk-2H7UWE2G.js.map +1 -0
  4. package/dist/{chunk-LA3JPESW.js → chunk-4A4L3YIW.js} +5 -5
  5. package/dist/chunk-4G2YHZIM.js +132 -0
  6. package/dist/chunk-4G2YHZIM.js.map +1 -0
  7. package/dist/{chunk-BZ4CZBOM.js → chunk-5F2YR5XV.js} +3 -3
  8. package/dist/{chunk-CHNA5RVS.js → chunk-5OKLCVM4.js} +3 -3
  9. package/dist/{chunk-ZU6DAR4S.js → chunk-5QZAK6J7.js} +7 -7
  10. package/dist/{chunk-ZU6DAR4S.js.map → chunk-5QZAK6J7.js.map} +1 -1
  11. package/dist/{chunk-NFH6SA62.js → chunk-6RLV45HN.js} +10 -10
  12. package/dist/{chunk-NFH6SA62.js.map → chunk-6RLV45HN.js.map} +1 -1
  13. package/dist/{chunk-GUDGCFSF.js → chunk-CLFHC2DK.js} +15 -106
  14. package/dist/chunk-CLFHC2DK.js.map +1 -0
  15. package/dist/chunk-D2CAV7MG.js +61 -0
  16. package/dist/chunk-D2CAV7MG.js.map +1 -0
  17. package/dist/{chunk-UW44KSYL.js → chunk-F2AMBBIA.js} +6 -6
  18. package/dist/{chunk-UW44KSYL.js.map → chunk-F2AMBBIA.js.map} +1 -1
  19. package/dist/{chunk-QQTYMW7N.js → chunk-F5T6TV4Z.js} +206 -73
  20. package/dist/chunk-F5T6TV4Z.js.map +1 -0
  21. package/dist/{chunk-K3O3YQYG.js → chunk-G47TDUK3.js} +2 -2
  22. package/dist/{chunk-AURY6RT6.js → chunk-GS2NZ3GD.js} +8 -8
  23. package/dist/chunk-GS2NZ3GD.js.map +1 -0
  24. package/dist/{chunk-5MFJ24VM.js → chunk-H6UTKTLK.js} +104 -250
  25. package/dist/chunk-H6UTKTLK.js.map +1 -0
  26. package/dist/{chunk-MJFIO5SX.js → chunk-HG4JPXJT.js} +11 -11
  27. package/dist/chunk-HG4JPXJT.js.map +1 -0
  28. package/dist/{chunk-IXEDSKMH.js → chunk-HTYH7CKN.js} +3 -3
  29. package/dist/{chunk-JC7DBPRD.js → chunk-HXKOIWLU.js} +2 -2
  30. package/dist/chunk-HXKOIWLU.js.map +1 -0
  31. package/dist/{chunk-NSJ2S7R5.js → chunk-ILUVL7WM.js} +2 -2
  32. package/dist/{chunk-R54KIGN2.js → chunk-IO5YBKHV.js} +13 -2
  33. package/dist/chunk-IO5YBKHV.js.map +1 -0
  34. package/dist/chunk-IXRZAHZF.js +53 -0
  35. package/dist/chunk-IXRZAHZF.js.map +1 -0
  36. package/dist/chunk-JCPANDNR.js +35 -0
  37. package/dist/chunk-JCPANDNR.js.map +1 -0
  38. package/dist/{chunk-NKCY2ULI.js → chunk-LJCNUP6M.js} +2 -2
  39. package/dist/{chunk-PRJD5MMQ.js → chunk-MHRC3KRX.js} +5 -5
  40. package/dist/chunk-MHRC3KRX.js.map +1 -0
  41. package/dist/chunk-MO5FGLVS.js +142 -0
  42. package/dist/chunk-MO5FGLVS.js.map +1 -0
  43. package/dist/{chunk-Q5FLW4JG.js → chunk-OKH64JZE.js} +2 -2
  44. package/dist/{chunk-WRRP47PY.js → chunk-PCC4LBKB.js} +2 -2
  45. package/dist/chunk-PMUABBPG.js +258 -0
  46. package/dist/chunk-PMUABBPG.js.map +1 -0
  47. package/dist/{chunk-2IMYK4WN.js → chunk-PNMM5HNX.js} +5 -5
  48. package/dist/{chunk-AKQ5QISO.js → chunk-QWVXOCXO.js} +6 -6
  49. package/dist/{chunk-IPJOMAWC.js → chunk-RWOYPOMR.js} +12 -2
  50. package/dist/{chunk-IPJOMAWC.js.map → chunk-RWOYPOMR.js.map} +1 -1
  51. package/dist/{chunk-ONWEOS77.js → chunk-SY4X2LND.js} +4 -4
  52. package/dist/{chunk-XGMOXMS4.js → chunk-TBOVYLQJ.js} +2 -2
  53. package/dist/{chunk-R7JV22QK.js → chunk-TNGMF4UX.js} +20 -20
  54. package/dist/{chunk-R7JV22QK.js.map → chunk-TNGMF4UX.js.map} +1 -1
  55. package/dist/{chunk-7VZV4O6B.js → chunk-UMH2YZKG.js} +14 -5
  56. package/dist/chunk-UMH2YZKG.js.map +1 -0
  57. package/dist/{chunk-6CNRMCFM.js → chunk-VPASBA7P.js} +2 -2
  58. package/dist/{chunk-CBF4ZYV3.js → chunk-WCAUUBHO.js} +1376 -741
  59. package/dist/chunk-WCAUUBHO.js.map +1 -0
  60. package/dist/{chunk-V3ENMW7G.js → chunk-WFRTHH3A.js} +3 -3
  61. package/dist/{chunk-DRKSYJZ2.js → chunk-WTJ3AY33.js} +1 -1
  62. package/dist/{chunk-DRKSYJZ2.js.map → chunk-WTJ3AY33.js.map} +1 -1
  63. package/dist/{chunk-XMEIVWAS.js → chunk-WUQ3MTPF.js} +11 -5
  64. package/dist/{chunk-XMEIVWAS.js.map → chunk-WUQ3MTPF.js.map} +1 -1
  65. package/dist/{chunk-4VCWL2IG.js → chunk-XAXJWXI4.js} +92 -59
  66. package/dist/chunk-XAXJWXI4.js.map +1 -0
  67. package/dist/{chunk-B66SC72V.js → chunk-Y5Y7XHVU.js} +4 -4
  68. package/dist/{chunk-FMYHWKGG.js → chunk-YO2LTXB4.js} +66 -16
  69. package/dist/chunk-YO2LTXB4.js.map +1 -0
  70. package/dist/{chunk-TUQF577Z.js → chunk-ZUAZHDKP.js} +40 -41
  71. package/dist/chunk-ZUAZHDKP.js.map +1 -0
  72. package/dist/commands/build/marketplace.js +98 -121
  73. package/dist/commands/build/marketplace.js.map +1 -1
  74. package/dist/commands/build/plugins.js +8 -8
  75. package/dist/commands/compile.js +19 -24
  76. package/dist/commands/compile.js.map +1 -1
  77. package/dist/commands/doctor.js +220 -79
  78. package/dist/commands/doctor.js.map +1 -1
  79. package/dist/commands/edit.js +549 -75
  80. package/dist/commands/edit.js.map +1 -1
  81. package/dist/commands/eject.js +26 -21
  82. package/dist/commands/eject.js.map +1 -1
  83. package/dist/commands/init.js +41 -39
  84. package/dist/commands/list.js +11 -11
  85. package/dist/commands/list.js.map +1 -1
  86. package/dist/commands/new/marketplace.js +243 -0
  87. package/dist/commands/new/marketplace.js.map +1 -0
  88. package/dist/commands/search.js +16 -14
  89. package/dist/commands/search.js.map +1 -1
  90. package/dist/commands/share.js +67 -0
  91. package/dist/commands/share.js.map +1 -0
  92. package/dist/commands/uninstall.js +61 -74
  93. package/dist/commands/uninstall.js.map +1 -1
  94. package/dist/commands/update.js +9 -9
  95. package/dist/commands/update.js.map +1 -1
  96. package/dist/components/common/prompt-confirm.js +1 -1
  97. package/dist/components/common/removal-plan-confirm.js +10 -0
  98. package/dist/components/common/select-list.js +2 -2
  99. package/dist/components/wizard/category-grid.js +5 -5
  100. package/dist/components/wizard/checkbox-grid.js +5 -5
  101. package/dist/components/wizard/domain-selection.js +11 -11
  102. package/dist/components/wizard/run-wizard-session.js +29 -28
  103. package/dist/components/wizard/scroll-affordance.js +2 -2
  104. package/dist/components/wizard/skill-agent-summary.js +6 -6
  105. package/dist/components/wizard/source-grid.js +6 -6
  106. package/dist/components/wizard/stack-selection.js +8 -8
  107. package/dist/components/wizard/step-agents.js +10 -11
  108. package/dist/components/wizard/step-build.js +9 -9
  109. package/dist/components/wizard/step-confirm.js +10 -10
  110. package/dist/components/wizard/step-sources.js +10 -10
  111. package/dist/components/wizard/step-stack.js +9 -9
  112. package/dist/components/wizard/summary-panel.js +9 -9
  113. package/dist/components/wizard/toast.js +2 -2
  114. package/dist/components/wizard/wizard-layout.js +14 -14
  115. package/dist/components/wizard/wizard-tabs.js +2 -2
  116. package/dist/components/wizard/wizard.js +27 -27
  117. package/dist/copy-local-skills-NSUTBVLJ.js +14 -0
  118. package/dist/hooks/init.js +42 -62
  119. package/dist/hooks/init.js.map +1 -1
  120. package/dist/load-agent-defs-X4E57I2U.js +15 -0
  121. package/dist/{loader-JIZDTR4G.js → loader-G6BFG2VA.js} +3 -3
  122. package/dist/recompile-project-agents-JE4MM72I.js +20 -0
  123. package/dist/{source-loader-OE6EJFPU.js → source-loader-3DL3NYUX.js} +7 -5
  124. package/dist/source-loader-3DL3NYUX.js.map +1 -0
  125. package/dist/src/agents/developer/ai-developer/critical-reminders.md +1 -1
  126. package/dist/src/agents/developer/ai-developer/critical-requirements.md +1 -1
  127. package/dist/src/agents/developer/ai-developer/identity.md +1 -1
  128. package/dist/src/agents/developer/ai-developer/playbook.md +1 -1
  129. package/dist/src/agents/developer/api-developer/identity.md +1 -1
  130. package/dist/src/agents/developer/cli-developer/identity.md +1 -1
  131. package/dist/src/agents/developer/web-developer/identity.md +1 -1
  132. package/dist/src/agents/meta/codex-keeper/identity.md +1 -1
  133. package/dist/src/agents/meta/convention-keeper/identity.md +1 -1
  134. package/dist/src/agents/meta/skill-summoner/identity.md +1 -1
  135. package/dist/src/agents/researcher/ai-researcher/identity.md +1 -1
  136. package/dist/src/agents/researcher/api-researcher/identity.md +1 -1
  137. package/dist/src/agents/researcher/cli-researcher/identity.md +1 -1
  138. package/dist/src/agents/researcher/web-researcher/identity.md +1 -1
  139. package/dist/src/agents/reviewer/reviewer/playbook.md +1 -1
  140. package/dist/src/agents/tester/ai-tester/identity.md +1 -1
  141. package/dist/src/agents/tester/api-tester/critical-reminders.md +1 -1
  142. package/dist/src/agents/tester/api-tester/critical-requirements.md +1 -1
  143. package/dist/src/agents/tester/api-tester/identity.md +2 -2
  144. package/dist/src/agents/tester/cli-tester/identity.md +1 -1
  145. package/dist/src/agents/tester/web-tester/identity.md +3 -3
  146. package/dist/stores/wizard-store.js +7 -5
  147. package/package.json +10 -7
  148. package/src/agents/developer/ai-developer/critical-reminders.md +1 -1
  149. package/src/agents/developer/ai-developer/critical-requirements.md +1 -1
  150. package/src/agents/developer/ai-developer/identity.md +1 -1
  151. package/src/agents/developer/ai-developer/playbook.md +1 -1
  152. package/src/agents/developer/api-developer/identity.md +1 -1
  153. package/src/agents/developer/cli-developer/identity.md +1 -1
  154. package/src/agents/developer/web-developer/identity.md +1 -1
  155. package/src/agents/meta/codex-keeper/identity.md +1 -1
  156. package/src/agents/meta/convention-keeper/identity.md +1 -1
  157. package/src/agents/meta/skill-summoner/identity.md +1 -1
  158. package/src/agents/researcher/ai-researcher/identity.md +1 -1
  159. package/src/agents/researcher/api-researcher/identity.md +1 -1
  160. package/src/agents/researcher/cli-researcher/identity.md +1 -1
  161. package/src/agents/researcher/web-researcher/identity.md +1 -1
  162. package/src/agents/reviewer/reviewer/playbook.md +1 -1
  163. package/src/agents/tester/ai-tester/identity.md +1 -1
  164. package/src/agents/tester/api-tester/critical-reminders.md +1 -1
  165. package/src/agents/tester/api-tester/critical-requirements.md +1 -1
  166. package/src/agents/tester/api-tester/identity.md +2 -2
  167. package/src/agents/tester/cli-tester/identity.md +1 -1
  168. package/src/agents/tester/web-tester/identity.md +3 -3
  169. package/src/schemas/custom-metadata.schema.json +3 -0
  170. package/src/schemas/metadata.schema.json +3 -0
  171. package/src/schemas/project-config.schema.json +4 -8
  172. package/src/schemas/project-source-config.schema.json +2 -2
  173. package/dist/chunk-4VCWL2IG.js.map +0 -1
  174. package/dist/chunk-5MFJ24VM.js.map +0 -1
  175. package/dist/chunk-7VZV4O6B.js.map +0 -1
  176. package/dist/chunk-AURY6RT6.js.map +0 -1
  177. package/dist/chunk-CBF4ZYV3.js.map +0 -1
  178. package/dist/chunk-FMYHWKGG.js.map +0 -1
  179. package/dist/chunk-GUDGCFSF.js.map +0 -1
  180. package/dist/chunk-JC7DBPRD.js.map +0 -1
  181. package/dist/chunk-MJFIO5SX.js.map +0 -1
  182. package/dist/chunk-OJJLYHM3.js +0 -34
  183. package/dist/chunk-OJJLYHM3.js.map +0 -1
  184. package/dist/chunk-PRJD5MMQ.js.map +0 -1
  185. package/dist/chunk-QQTYMW7N.js.map +0 -1
  186. package/dist/chunk-QUDQTO3O.js +0 -41
  187. package/dist/chunk-QUDQTO3O.js.map +0 -1
  188. package/dist/chunk-R54KIGN2.js.map +0 -1
  189. package/dist/chunk-TUQF577Z.js.map +0 -1
  190. package/dist/copy-local-skills-WVHJFRPK.js +0 -14
  191. package/dist/load-agent-defs-5OT54J5M.js +0 -15
  192. package/dist/recompile-project-agents-VREEPBDV.js +0 -20
  193. /package/dist/{chunk-LA3JPESW.js.map → chunk-4A4L3YIW.js.map} +0 -0
  194. /package/dist/{chunk-BZ4CZBOM.js.map → chunk-5F2YR5XV.js.map} +0 -0
  195. /package/dist/{chunk-CHNA5RVS.js.map → chunk-5OKLCVM4.js.map} +0 -0
  196. /package/dist/{chunk-K3O3YQYG.js.map → chunk-G47TDUK3.js.map} +0 -0
  197. /package/dist/{chunk-IXEDSKMH.js.map → chunk-HTYH7CKN.js.map} +0 -0
  198. /package/dist/{chunk-NSJ2S7R5.js.map → chunk-ILUVL7WM.js.map} +0 -0
  199. /package/dist/{chunk-NKCY2ULI.js.map → chunk-LJCNUP6M.js.map} +0 -0
  200. /package/dist/{chunk-Q5FLW4JG.js.map → chunk-OKH64JZE.js.map} +0 -0
  201. /package/dist/{chunk-WRRP47PY.js.map → chunk-PCC4LBKB.js.map} +0 -0
  202. /package/dist/{chunk-2IMYK4WN.js.map → chunk-PNMM5HNX.js.map} +0 -0
  203. /package/dist/{chunk-AKQ5QISO.js.map → chunk-QWVXOCXO.js.map} +0 -0
  204. /package/dist/{chunk-ONWEOS77.js.map → chunk-SY4X2LND.js.map} +0 -0
  205. /package/dist/{chunk-XGMOXMS4.js.map → chunk-TBOVYLQJ.js.map} +0 -0
  206. /package/dist/{chunk-6CNRMCFM.js.map → chunk-VPASBA7P.js.map} +0 -0
  207. /package/dist/{chunk-V3ENMW7G.js.map → chunk-WFRTHH3A.js.map} +0 -0
  208. /package/dist/{chunk-B66SC72V.js.map → chunk-Y5Y7XHVU.js.map} +0 -0
  209. /package/dist/{copy-local-skills-WVHJFRPK.js.map → components/common/removal-plan-confirm.js.map} +0 -0
  210. /package/dist/{load-agent-defs-5OT54J5M.js.map → copy-local-skills-NSUTBVLJ.js.map} +0 -0
  211. /package/dist/{loader-JIZDTR4G.js.map → load-agent-defs-X4E57I2U.js.map} +0 -0
  212. /package/dist/{recompile-project-agents-VREEPBDV.js.map → loader-G6BFG2VA.js.map} +0 -0
  213. /package/dist/{source-loader-OE6EJFPU.js.map → recompile-project-agents-JE4MM72I.js.map} +0 -0
@@ -10,14 +10,14 @@ import {
10
10
  generateAgentPluginManifest,
11
11
  getPluginAgentsDir,
12
12
  getPluginManifestPath,
13
- isAgentName,
13
+ hasProvenanceMarker,
14
14
  loadProjectConfig,
15
15
  loadProjectSourceConfig,
16
16
  resolveAgents,
17
17
  writeCompiledAgentsByScope,
18
18
  writeContentHash,
19
19
  writePluginManifest
20
- } from "./chunk-CBF4ZYV3.js";
20
+ } from "./chunk-WCAUUBHO.js";
21
21
  import {
22
22
  agentFrontmatterValidationSchema,
23
23
  copy,
@@ -27,31 +27,45 @@ import {
27
27
  formatZodIssues,
28
28
  getErrorMessage,
29
29
  glob,
30
+ isAgentName,
30
31
  loadAllAgents,
31
32
  loadProjectAgents,
32
33
  log,
33
34
  readFile,
35
+ readFileOptional,
34
36
  remove,
35
37
  verbose,
36
38
  warn
37
- } from "./chunk-4VCWL2IG.js";
39
+ } from "./chunk-XAXJWXI4.js";
38
40
  import {
39
41
  typedEntries,
40
42
  typedFromEntries,
41
43
  typedKeys
42
44
  } from "./chunk-VASLW636.js";
43
45
  import {
44
- CLAUDE_DIR,
45
46
  DIRS,
46
- PROJECT_ROOT,
47
- STANDARD_DIRS
48
- } from "./chunk-R54KIGN2.js";
47
+ PROJECT_ROOT
48
+ } from "./chunk-IO5YBKHV.js";
49
49
 
50
50
  // src/cli/lib/agents/list-compiled-agents.ts
51
51
  import path from "path";
52
+ import { partition } from "remeda";
52
53
  async function listAgentMdFiles(agentsDir) {
53
54
  return glob("*.md", agentsDir);
54
55
  }
56
+ async function splitAgentsByProvenance(agentsDir) {
57
+ const files = await listAgentMdFiles(agentsDir);
58
+ const classified = await Promise.all(files.map((file) => readAgentProvenance(agentsDir, file)));
59
+ const [marked, unmarked] = partition(classified, (agent) => agent.compiledHere);
60
+ return { marked: marked.map(agentName), unmarked: unmarked.map(agentName) };
61
+ }
62
+ async function readAgentProvenance(agentsDir, file) {
63
+ const content = await readFileOptional(path.join(agentsDir, file));
64
+ return { name: path.basename(file, ".md"), compiledHere: hasProvenanceMarker(content) };
65
+ }
66
+ function agentName(agent) {
67
+ return agent.name;
68
+ }
55
69
  async function listCompiledAgentNames(agentsDir) {
56
70
  const files = await listAgentMdFiles(agentsDir);
57
71
  return files.map((f) => path.basename(f, ".md"));
@@ -69,33 +83,22 @@ async function pruneStaleCompiledAgents(agentsDir, keep) {
69
83
 
70
84
  // src/cli/lib/agents/agent-fetcher.ts
71
85
  import path2 from "path";
72
- async function getAgentDefinitions(remoteSource, options = {}) {
86
+ async function getAgentDefinitions(remoteSource) {
73
87
  if (remoteSource) {
74
- return fetchAgentDefinitionsFromRemote(remoteSource, options);
88
+ return fetchAgentDefinitionsFromRemote(remoteSource);
75
89
  }
76
- return getLocalAgentDefinitions(options);
90
+ return getLocalAgentDefinitions();
77
91
  }
78
- async function getLocalAgentDefinitions(options = {}) {
92
+ async function getLocalAgentDefinitions() {
79
93
  const agentsDir = path2.join(PROJECT_ROOT, DIRS.agents);
80
94
  if (!await directoryExists(agentsDir)) {
81
95
  throw new Error(
82
96
  `Agent partials not found at '${agentsDir}'. Ensure the CLI is properly installed.`
83
97
  );
84
98
  }
85
- const localTemplatesDir = options.projectDir ? path2.join(options.projectDir, CLAUDE_DIR, STANDARD_DIRS.TEMPLATES) : void 0;
86
- const useLocalTemplates = localTemplatesDir !== void 0 && await directoryExists(localTemplatesDir);
87
- if (useLocalTemplates) {
88
- verbose(`Using local templates from: ${localTemplatesDir}`);
89
- }
90
- const templatesDir = useLocalTemplates ? localTemplatesDir : path2.join(PROJECT_ROOT, DIRS.templates);
91
- if (!await directoryExists(templatesDir)) {
92
- verbose(`Templates directory not found: ${templatesDir}`);
93
- }
94
99
  verbose(`Agent partials loaded from CLI: ${agentsDir}`);
95
- verbose(`Templates directory: ${templatesDir}`);
96
100
  return {
97
101
  agentsDir,
98
- templatesDir,
99
102
  sourcePath: PROJECT_ROOT
100
103
  };
101
104
  }
@@ -108,23 +111,18 @@ async function fetchAgentDefinitionsFromRemote(source, options = {}) {
108
111
  }
109
112
  const agentsDirRelPath = options.agentsDir ?? sourceProjectConfig?.agentsDir ?? DIRS.agents;
110
113
  const agentsDir = path2.join(result.path, agentsDirRelPath);
111
- const templatesDir = path2.join(agentsDir, path2.basename(DIRS.templates));
112
114
  if (!await directoryExists(agentsDir)) {
113
115
  throw new Error(`Agent partials not found at '${agentsDir}'`);
114
116
  }
115
- if (!await directoryExists(templatesDir)) {
116
- verbose(`Templates directory not found: ${templatesDir}`);
117
- }
118
117
  verbose(`Agent partials fetched from: ${result.path}`);
119
118
  return {
120
119
  agentsDir,
121
- templatesDir,
122
120
  sourcePath: result.path
123
121
  };
124
122
  }
125
123
 
126
124
  // src/cli/lib/agents/agent-recompiler.ts
127
- import { partition } from "remeda";
125
+ import { partition as partition2 } from "remeda";
128
126
  import path3 from "path";
129
127
  async function getExistingAgentNames(pluginDir) {
130
128
  return listCompiledAgentNames(getPluginAgentsDir(pluginDir));
@@ -147,7 +145,7 @@ async function resolveAgentNames(params) {
147
145
  return getExistingAgentNames(pluginDir);
148
146
  }
149
147
  function buildRecompileResult(outcomes, priorWarnings) {
150
- const [succeeded, failedOutcomes] = partition(
148
+ const [succeeded, failedOutcomes] = partition2(
151
149
  outcomes,
152
150
  (outcome) => outcome.ok
153
151
  );
@@ -174,8 +172,8 @@ function filterExcludedEntries(config) {
174
172
  const activeAgents = config.agents.filter((a) => !a.excluded);
175
173
  const filteredStack = config.stack === void 0 ? {} : {
176
174
  stack: Object.fromEntries(
177
- typedEntries(config.stack).map(([agentName, agentStack]) => [
178
- agentName,
175
+ typedEntries(config.stack).map(([agentName2, agentStack]) => [
176
+ agentName2,
179
177
  Object.fromEntries(
180
178
  typedEntries(agentStack).map(([category, assignments]) => [
181
179
  category,
@@ -212,7 +210,7 @@ async function recompileAgents(options) {
212
210
  verbose(`Recompiling ${agentNames.length} agents in ${outputDir ?? pluginDir}`);
213
211
  const pluginSkills = providedSkills ?? await discoverAllPluginSkills(projectDir ?? pluginDir);
214
212
  const allConfigAgents = filteredConfig ? buildCompileAgents(filteredConfig, allAgents) : {};
215
- const [knownAgents, missingAgents] = partition(
213
+ const [knownAgents, missingAgents] = partition2(
216
214
  agentNames,
217
215
  (name) => Boolean(allConfigAgents[name] || allAgents[name])
218
216
  );
@@ -265,9 +263,9 @@ async function compileAgentPlugin(options) {
265
263
  `Agent '${fileName}' has invalid or missing YAML frontmatter. Required fields: 'name' and 'description'. File: ${agentPath}`
266
264
  );
267
265
  }
268
- const agentName = frontmatter.name;
269
- verbose(`Compiling agent plugin: ${agentName} from ${agentPath}`);
270
- const pluginDir = path4.join(outputDir, `agent-${agentName}`);
266
+ const agentName2 = frontmatter.name;
267
+ verbose(`Compiling agent plugin: ${agentName2} from ${agentPath}`);
268
+ const pluginDir = path4.join(outputDir, `agent-${agentName2}`);
271
269
  const agentsDir = path4.join(pluginDir, "agents");
272
270
  await ensureDir(pluginDir);
273
271
  await ensureDir(agentsDir);
@@ -278,19 +276,19 @@ async function compileAgentPlugin(options) {
278
276
  getPluginManifestPath
279
277
  );
280
278
  const manifest = generateAgentPluginManifest({
281
- agentName,
279
+ agentName: agentName2,
282
280
  description: frontmatter.description,
283
281
  version
284
282
  });
285
283
  await writePluginManifest(pluginDir, manifest);
286
284
  await writeContentHash(pluginDir, contentHash, getPluginManifestPath);
287
- verbose(` Wrote plugin.json for ${agentName} (v${version})`);
288
- await copy(agentPath, path4.join(agentsDir, `${agentName}.md`));
289
- verbose(` Copied agent ${fileName} -> agents/${agentName}.md`);
285
+ verbose(` Wrote plugin.json for ${agentName2} (v${version})`);
286
+ await copy(agentPath, path4.join(agentsDir, `${agentName2}.md`));
287
+ verbose(` Copied agent ${fileName} -> agents/${agentName2}.md`);
290
288
  return {
291
289
  pluginPath: pluginDir,
292
290
  manifest,
293
- agentName
291
+ agentName: agentName2
294
292
  };
295
293
  }
296
294
  async function compileAllAgentPlugins(agentsDir, outputDir) {
@@ -322,6 +320,7 @@ Compiled ${results.length} agent plugins:`);
322
320
 
323
321
  export {
324
322
  listAgentMdFiles,
323
+ splitAgentsByProvenance,
325
324
  pruneStaleCompiledAgents,
326
325
  getAgentDefinitions,
327
326
  filterExcludedEntries,
@@ -329,4 +328,4 @@ export {
329
328
  compileAllAgentPlugins,
330
329
  printAgentCompilationSummary
331
330
  };
332
- //# sourceMappingURL=chunk-TUQF577Z.js.map
331
+ //# sourceMappingURL=chunk-ZUAZHDKP.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/cli/lib/agents/list-compiled-agents.ts","../src/cli/lib/agents/agent-fetcher.ts","../src/cli/lib/agents/agent-recompiler.ts","../src/cli/lib/agents/agent-plugin-compiler.ts"],"sourcesContent":["import path from \"path\";\nimport { partition } from \"remeda\";\nimport { glob, readFileOptional, remove } from \"../../utils/fs\";\nimport { isAgentName } from \"../../utils/type-guards\";\nimport { hasProvenanceMarker } from \"./agent-provenance\";\nimport type { AgentName } from \"../../types\";\n\n/** Compiled-agent basenames in a directory, split by whether this CLI compiled them. */\nexport type AgentProvenanceSplit = {\n /** Files carrying the provenance marker — provably written by this CLI. */\n marked: string[];\n /** Everything else in the directory, the user's own agents among them. */\n unmarked: string[];\n};\n\n/** Lists compiled-agent markdown filenames (e.g. \"web-developer.md\") in a directory. */\nexport async function listAgentMdFiles(agentsDir: string): Promise<string[]> {\n return glob(\"*.md\", agentsDir);\n}\n\n/**\n * Splits the agent files in a directory by the provenance marker each compiled agent carries.\n *\n * This is the only thing that identifies this CLI's own output once the configuration naming\n * it is gone, so the split errs one way by construction: a file that cannot be read yields no\n * marker and lands in `unmarked`, because \"cannot prove it is ours\" and \"is not ours\" call for\n * the same answer — leave it alone.\n */\nexport async function splitAgentsByProvenance(agentsDir: string): Promise<AgentProvenanceSplit> {\n const files = await listAgentMdFiles(agentsDir);\n const classified = await Promise.all(files.map((file) => readAgentProvenance(agentsDir, file)));\n const [marked, unmarked] = partition(classified, (agent) => agent.compiledHere);\n\n return { marked: marked.map(agentName), unmarked: unmarked.map(agentName) };\n}\n\ntype ClassifiedAgent = { name: string; compiledHere: boolean };\n\nasync function readAgentProvenance(agentsDir: string, file: string): Promise<ClassifiedAgent> {\n const content = await readFileOptional(path.join(agentsDir, file));\n return { name: path.basename(file, \".md\"), compiledHere: hasProvenanceMarker(content) };\n}\n\nfunction agentName(agent: ClassifiedAgent): string {\n return agent.name;\n}\n\n/** Lists compiled-agent names (filenames without the `.md` extension) in a directory. */\nexport async function listCompiledAgentNames(agentsDir: string): Promise<AgentName[]> {\n const files = await listAgentMdFiles(agentsDir);\n // Boundary cast: compiled .md filenames are agent names by convention; custom\n // agents from marketplace stacks may not be members of the AgentName union.\n return files.map((f) => path.basename(f, \".md\") as AgentName);\n}\n\n/**\n * Removes stale CLI-compiled agent files from `agentsDir`: deletes any `.md`\n * whose basename is a built-in CLI agent name (`isAgentName`) that is NOT in\n * `keep`. The built-in-name check protects hand-authored agents (whose basename\n * is not a built-in name) — it is never the removal criterion. Only call this\n * when `keep` is the COMPLETE set of agents that should live in `agentsDir`.\n */\nexport async function pruneStaleCompiledAgents(\n agentsDir: string,\n keep: ReadonlySet<AgentName>,\n): Promise<void> {\n // A non-built-in basename is a hand-authored agent — always preserved.\n const isStaleCompiledAgent = (file: string): boolean => {\n const name = path.basename(file, \".md\");\n return isAgentName(name) && !keep.has(name);\n };\n\n const files = await listAgentMdFiles(agentsDir);\n await Promise.all(\n files.filter(isStaleCompiledAgent).map((file) => remove(path.join(agentsDir, file))),\n );\n}\n","import path from \"path\";\nimport { directoryExists } from \"../../utils/fs\";\nimport { verbose } from \"../../utils/logger\";\nimport { PROJECT_ROOT, DIRS } from \"../../consts\";\nimport { fetchFromSource, type FetchOptions } from \"../loading\";\nimport { loadProjectSourceConfig } from \"../configuration\";\nimport type { AgentSourcePaths } from \"../../types\";\n\nexport async function getAgentDefinitions(remoteSource?: string): Promise<AgentSourcePaths> {\n if (remoteSource) {\n return fetchAgentDefinitionsFromRemote(remoteSource);\n }\n return getLocalAgentDefinitions();\n}\n\nexport async function getLocalAgentDefinitions(): Promise<AgentSourcePaths> {\n const agentsDir = path.join(PROJECT_ROOT, DIRS.agents);\n\n if (!(await directoryExists(agentsDir))) {\n throw new Error(\n `Agent partials not found at '${agentsDir}'. Ensure the CLI is properly installed.`,\n );\n }\n\n verbose(`Agent partials loaded from CLI: ${agentsDir}`);\n\n return {\n agentsDir,\n sourcePath: PROJECT_ROOT,\n };\n}\n\nexport async function fetchAgentDefinitionsFromRemote(\n source: string,\n options: FetchOptions & { agentsDir?: string } = {},\n): Promise<AgentSourcePaths> {\n verbose(`Fetching agent partials from remote: ${source}`);\n\n const result = await fetchFromSource(source, { subdir: \"\" });\n\n const sourceProjectConfig = options.agentsDir\n ? undefined\n : await loadProjectSourceConfig(result.path);\n if (sourceProjectConfig?.agentsDir) {\n verbose(`Using agentsDir from source config: ${sourceProjectConfig.agentsDir}`);\n }\n const agentsDirRelPath = options.agentsDir ?? sourceProjectConfig?.agentsDir ?? DIRS.agents;\n\n const agentsDir = path.join(result.path, agentsDirRelPath);\n\n if (!(await directoryExists(agentsDir))) {\n throw new Error(`Agent partials not found at '${agentsDir}'`);\n }\n\n verbose(`Agent partials fetched from: ${result.path}`);\n\n return {\n agentsDir,\n sourcePath: result.path,\n };\n}\n","import { partition } from \"remeda\";\nimport { writeCompiledAgentsByScope, type AgentWriteOutcome } from \"./write-compiled-agents\";\nimport { listCompiledAgentNames } from \"./list-compiled-agents\";\nimport path from \"path\";\n\nimport { getErrorMessage } from \"../../utils/errors\";\nimport type {\n AgentDefinition,\n AgentName,\n CompileAgentConfig,\n CompileConfig,\n ProjectConfig,\n SkillDefinitionMap,\n SkillScope,\n} from \"../../types\";\n\nimport { buildCompileAgents } from \"../installation/local-installer\";\nimport { ensureDir } from \"../../utils/fs\";\nimport { verbose } from \"../../utils/logger\";\nimport { typedEntries, typedFromEntries, typedKeys } from \"../../utils/typed-object\";\nimport { createLiquidEngine } from \"../compiler\";\nimport { loadProjectConfig, effectivelyExcludedSkillIds } from \"../configuration\";\nimport { loadAllAgents, loadProjectAgents } from \"../loading\";\nimport { getPluginAgentsDir } from \"../plugins\";\nimport { discoverAllPluginSkills } from \"../plugins/plugin-discovery\";\nimport { resolveAgents } from \"../resolver\";\n\nexport type RecompileAgentsOptions = {\n pluginDir: string;\n sourcePath: string;\n agents?: AgentName[];\n skills?: SkillDefinitionMap;\n projectDir?: string;\n outputDir?: string;\n /** When provided, routes agents by scope: global agents to ~/.claude/agents/, project agents to outputDir */\n agentScopeMap?: Map<AgentName, SkillScope>;\n};\n\nexport type RecompileAgentsResult = {\n compiled: AgentName[];\n /**\n * The subset of `compiled` whose file this pass actually wrote. `compiled` is\n * every agent that came through the pass with a correct file at the end of it;\n * `rewritten` is the ones whose content moved, so `compiled minus rewritten` is\n * the count a summary reports as unchanged.\n */\n rewritten: AgentName[];\n failed: AgentName[];\n warnings: string[];\n};\n\nasync function getExistingAgentNames(pluginDir: string): Promise<AgentName[]> {\n return listCompiledAgentNames(getPluginAgentsDir(pluginDir));\n}\n\ntype ResolveAgentNamesParams = {\n specifiedAgents?: AgentName[];\n projectConfig: ProjectConfig | null;\n allAgents: Partial<Record<AgentName, AgentDefinition>>;\n outputDir?: string;\n pluginDir: string;\n};\n\nasync function resolveAgentNames(params: ResolveAgentNamesParams): Promise<AgentName[]> {\n const { specifiedAgents, projectConfig, allAgents, outputDir, pluginDir } = params;\n\n if (specifiedAgents) {\n return specifiedAgents;\n }\n\n // A present config is authoritative over its agent roster — even when empty.\n // `agents: []` means \"no agents\", so it must NOT fall through to the\n // all-agents branch below; that branch exists only for the config-LESS case.\n if (projectConfig) {\n const agentNames = projectConfig.agents.map((a) => a.name);\n verbose(`Using agents from config: ${agentNames.join(\", \")}`);\n return agentNames;\n }\n\n if (outputDir) {\n const names = typedKeys<AgentName>(allAgents);\n verbose(`Using all available agents from source: ${names.join(\", \")}`);\n return names;\n }\n\n return getExistingAgentNames(pluginDir);\n}\n\n/** Splits write outcomes into the recompile result; logs each success at verbose level. */\nfunction buildRecompileResult(\n outcomes: AgentWriteOutcome[],\n priorWarnings: string[],\n): RecompileAgentsResult {\n const [succeeded, failedOutcomes] = partition(\n outcomes,\n (outcome): outcome is Extract<AgentWriteOutcome, { ok: true }> => outcome.ok,\n );\n succeeded.forEach((outcome) =>\n verbose(\n ` ${outcome.rewritten ? \"Rewrote\" : \"Unchanged\"}: ${outcome.name} (${outcome.scope} -> ${outcome.targetDir})`,\n ),\n );\n return {\n compiled: succeeded.map((outcome) => outcome.name),\n rewritten: succeeded.filter((outcome) => outcome.rewritten).map((outcome) => outcome.name),\n failed: failedOutcomes.map((outcome) => outcome.name),\n warnings: [\n ...priorWarnings,\n ...failedOutcomes.map(\n (outcome) => `Failed to compile ${outcome.name}: ${getErrorMessage(outcome.error)}`,\n ),\n ],\n };\n}\n\nexport function filterExcludedEntries(config: ProjectConfig): ProjectConfig {\n const excludedIds = effectivelyExcludedSkillIds(config.skills);\n const activeSkills = config.skills.filter((s) => !s.excluded);\n const activeAgents = config.agents.filter((a) => !a.excluded);\n\n // Also remove excluded skill refs from stack assignments. A config with no stack keeps\n // none — the key stays absent rather than becoming an explicit `undefined`.\n const filteredStack =\n config.stack === undefined\n ? {}\n : {\n stack: Object.fromEntries(\n typedEntries(config.stack).map(([agentName, agentStack]) => [\n agentName,\n Object.fromEntries(\n typedEntries(agentStack).map(([category, assignments]) => [\n category,\n assignments.filter((a) => !excludedIds.has(a.id)),\n ]),\n ),\n ]),\n ),\n };\n\n return { ...config, skills: activeSkills, agents: activeAgents, ...filteredStack };\n}\n\nexport async function recompileAgents(\n options: RecompileAgentsOptions,\n): Promise<RecompileAgentsResult> {\n const { pluginDir, sourcePath, skills: providedSkills, projectDir, outputDir } = options;\n\n const configDir = projectDir ?? pluginDir;\n const loadedConfig = await loadProjectConfig(configDir);\n const projectConfig = loadedConfig?.config ?? null;\n\n // Filter excluded entries once at the entry point — callees receive clean data\n const filteredConfig = projectConfig ? filterExcludedEntries(projectConfig) : null;\n\n const builtinAgents = await loadAllAgents(sourcePath);\n const projectAgents = projectDir ? await loadProjectAgents(projectDir) : {};\n\n // Priority: project agents > built-in agents\n const allAgents: Partial<Record<AgentName, AgentDefinition>> = {\n ...builtinAgents,\n ...projectAgents,\n };\n\n const agentNames = await resolveAgentNames({\n ...(options.agents !== undefined && { specifiedAgents: options.agents }),\n projectConfig: filteredConfig,\n allAgents,\n ...(outputDir !== undefined && { outputDir }),\n pluginDir,\n });\n\n if (agentNames.length === 0) {\n return { compiled: [], rewritten: [], failed: [], warnings: [\"No agents found to recompile\"] };\n }\n\n verbose(`Recompiling ${agentNames.length} agents in ${outputDir ?? pluginDir}`);\n\n // When skills are not provided, discover from all plugin directories.\n const pluginSkills: SkillDefinitionMap =\n providedSkills ?? (await discoverAllPluginSkills(projectDir ?? pluginDir));\n\n const allConfigAgents = filteredConfig ? buildCompileAgents(filteredConfig, allAgents) : {};\n\n // Restrict to only the agents we're compiling (agentNames).\n // buildCompileAgents returns entries for ALL agents in the config, but when\n // scopeFilter is active, we only want the agents matching that scope.\n // Without this filter, a project pass would compile global agents without\n // their stack (since the project config omits global agent stack entries)\n // and overwrite correctly compiled global agent files.\n const [knownAgents, missingAgents] = partition(agentNames, (name) =>\n Boolean(allConfigAgents[name] || allAgents[name]),\n );\n const missingWarnings = missingAgents.map(\n (name) => `Agent \"${name}\" not found in source definitions`,\n );\n const configAgents = typedFromEntries<AgentName, CompileAgentConfig>(\n knownAgents.map((name) => [name, allConfigAgents[name] ?? {}]),\n );\n\n const compileConfig: CompileConfig = {\n name: filteredConfig?.name || path.basename(pluginDir),\n description: filteredConfig?.description || \"Recompiled plugin\",\n agents: configAgents,\n };\n\n const engine = await createLiquidEngine(projectDir);\n const resolvedAgents = await resolveAgents(allAgents, pluginSkills, compileConfig, sourcePath);\n\n const agentsDir = outputDir ?? getPluginAgentsDir(pluginDir);\n await ensureDir(agentsDir);\n\n const outcomes = await writeCompiledAgentsByScope({\n resolvedAgents,\n sourcePath,\n engine,\n projectAgentsDir: agentsDir,\n ...(options.agentScopeMap !== undefined && { agentScopeMap: options.agentScopeMap }),\n });\n return buildRecompileResult(outcomes, missingWarnings);\n}\n","import path from \"path\";\nimport { getErrorMessage } from \"../../utils/errors\";\nimport { readFile, ensureDir, copy } from \"../../utils/fs\";\nimport { log, verbose, warn } from \"../../utils/logger\";\nimport {\n generateAgentPluginManifest,\n writePluginManifest,\n getPluginManifestPath,\n} from \"../plugins\";\nimport { listAgentMdFiles } from \"./list-compiled-agents\";\nimport { computeStringHash, determinePluginVersion, writeContentHash } from \"../versioning\";\nimport { extractFrontmatter } from \"../../utils/frontmatter\";\nimport type { AgentFrontmatter, PluginManifest } from \"../../types\";\nimport { agentFrontmatterValidationSchema, formatZodIssues } from \"../schemas\";\n\nexport type AgentPluginOptions = {\n agentPath: string;\n outputDir: string;\n};\n\nexport type CompiledAgentPlugin = {\n pluginPath: string;\n manifest: PluginManifest;\n agentName: string;\n};\n\nfunction parseAgentFrontmatter(\n content: string,\n filePath: string,\n): Pick<AgentFrontmatter, \"name\" | \"description\"> | null {\n const raw = extractFrontmatter(content);\n if (!raw) {\n return null;\n }\n\n const result = agentFrontmatterValidationSchema.safeParse(raw);\n if (!result.success) {\n warn(`Invalid agent frontmatter in ${filePath}: ${formatZodIssues(result.error.issues)}`);\n return null;\n }\n\n return { name: result.data.name, description: result.data.description };\n}\n\nexport async function compileAgentPlugin(\n options: AgentPluginOptions,\n): Promise<CompiledAgentPlugin> {\n const { agentPath, outputDir } = options;\n const fileName = path.basename(agentPath);\n\n const content = await readFile(agentPath);\n const frontmatter = parseAgentFrontmatter(content, agentPath);\n\n if (!frontmatter) {\n throw new Error(\n `Agent '${fileName}' has invalid or missing YAML frontmatter. ` +\n `Required fields: 'name' and 'description'. File: ${agentPath}`,\n );\n }\n\n const agentName = frontmatter.name;\n\n verbose(`Compiling agent plugin: ${agentName} from ${agentPath}`);\n\n const pluginDir = path.join(outputDir, `agent-${agentName}`);\n const agentsDir = path.join(pluginDir, \"agents\");\n\n await ensureDir(pluginDir);\n await ensureDir(agentsDir);\n\n const newHash = computeStringHash(content);\n const { version, contentHash } = await determinePluginVersion(\n newHash,\n pluginDir,\n getPluginManifestPath,\n );\n\n const manifest = generateAgentPluginManifest({\n agentName,\n description: frontmatter.description,\n version,\n });\n\n await writePluginManifest(pluginDir, manifest);\n\n await writeContentHash(pluginDir, contentHash, getPluginManifestPath);\n\n verbose(` Wrote plugin.json for ${agentName} (v${version})`);\n\n await copy(agentPath, path.join(agentsDir, `${agentName}.md`));\n verbose(` Copied agent ${fileName} -> agents/${agentName}.md`);\n\n return {\n pluginPath: pluginDir,\n manifest,\n agentName,\n };\n}\n\nexport async function compileAllAgentPlugins(\n agentsDir: string,\n outputDir: string,\n): Promise<CompiledAgentPlugin[]> {\n const results: CompiledAgentPlugin[] = [];\n\n const agentMdFiles = await listAgentMdFiles(agentsDir);\n\n for (const agentFile of agentMdFiles) {\n const agentPath = path.join(agentsDir, agentFile);\n\n try {\n const result = await compileAgentPlugin({\n agentPath,\n outputDir,\n });\n results.push(result);\n log(` [OK] agent-${result.agentName}`);\n } catch (error) {\n const errorMessage = getErrorMessage(error);\n warn(`Failed to compile agent from '${agentFile}': ${errorMessage}`);\n }\n }\n\n return results;\n}\n\nexport function printAgentCompilationSummary(results: CompiledAgentPlugin[]): void {\n log(`\\nCompiled ${results.length} agent plugins:`);\n for (const result of results) {\n log(` - agent-${result.agentName} (v${result.manifest.version})`);\n }\n}\n"],"mappings":"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","names":["path","path","partition","path","partition","agentName","path","path","path","agentName"]}
@@ -1,122 +1,52 @@
1
1
  #!/usr/bin/env node
2
+ import {
3
+ generateMarketplace,
4
+ getMarketplaceStats,
5
+ validateMarketplaceName,
6
+ validateSkillIdNamespace,
7
+ writeMarketplace
8
+ } from "../../chunk-4G2YHZIM.js";
2
9
  import {
3
10
  BaseCommand,
4
11
  EXIT_CODES
5
- } from "../../chunk-FMYHWKGG.js";
6
- import "../../chunk-7VZV4O6B.js";
7
- import "../../chunk-K3O3YQYG.js";
12
+ } from "../../chunk-YO2LTXB4.js";
13
+ import "../../chunk-UMH2YZKG.js";
14
+ import "../../chunk-G47TDUK3.js";
8
15
  import {
9
- readPluginManifest
10
- } from "../../chunk-CBF4ZYV3.js";
16
+ loadMarketplaceMatrix,
17
+ marketplaceHasNoVersion,
18
+ marketplaceNameNotPublishable,
19
+ marketplaceOwnerHasNoName,
20
+ validateKebabCaseName
21
+ } from "../../chunk-WCAUUBHO.js";
11
22
  import {
12
- ensureDir,
13
23
  getErrorMessage,
14
- glob,
15
24
  readFile,
16
25
  setVerbose,
17
- verbose,
18
26
  warn,
19
27
  writeFile
20
- } from "../../chunk-4VCWL2IG.js";
21
- import "../../chunk-IPJOMAWC.js";
28
+ } from "../../chunk-XAXJWXI4.js";
29
+ import "../../chunk-RWOYPOMR.js";
22
30
  import "../../chunk-VASLW636.js";
23
31
  import {
24
- DEFAULT_VERSION,
25
- KEBAB_CASE_PATTERN,
32
+ CATALOG_JSON,
33
+ CLI_INVOKE_COMMAND,
34
+ GENERATED_AT_BUILD,
26
35
  MARKETPLACE_JSON,
27
36
  PLUGINS_DIST_PATH,
28
37
  PLUGIN_MANIFEST_DIR,
29
- PLUGIN_MANIFEST_FILE
30
- } from "../../chunk-R54KIGN2.js";
38
+ STANDARD_FILES
39
+ } from "../../chunk-IO5YBKHV.js";
31
40
  import "../../chunk-VZRO7RYT.js";
32
41
 
33
42
  // src/cli/commands/build/marketplace.ts
34
43
  import { Flags } from "@oclif/core";
35
- import path2 from "path";
36
- import { sortBy as sortBy2 } from "remeda";
37
- import { z } from "zod";
38
-
39
- // src/cli/lib/marketplace-generator.ts
40
44
  import path from "path";
41
- import { countBy, sortBy } from "remeda";
42
- var PLUGIN_MANIFEST_PATH = `${PLUGIN_MANIFEST_DIR}/${PLUGIN_MANIFEST_FILE}`;
43
- var MARKETPLACE_SCHEMA_URL = "https://anthropic.com/claude-code/marketplace.schema.json";
44
- function convertManifestToMarketplacePlugin(manifest, pluginRoot, pluginDirName) {
45
- return {
46
- name: manifest.name,
47
- source: `./${pluginRoot}/${pluginDirName}`,
48
- ...manifest.description !== void 0 && { description: manifest.description },
49
- ...manifest.version !== void 0 && { version: manifest.version },
50
- ...manifest.author !== void 0 && { author: manifest.author },
51
- ...manifest.category !== void 0 && { category: manifest.category },
52
- ...manifest.keywords !== void 0 && { keywords: manifest.keywords }
53
- };
54
- }
55
- async function generateMarketplace(pluginsDir, options) {
56
- verbose(`Scanning plugins directory: ${pluginsDir}`);
57
- const manifestFiles = await glob(`**/${PLUGIN_MANIFEST_PATH}`, pluginsDir);
58
- verbose(`Found ${manifestFiles.length} plugin manifests`);
59
- const plugins = [];
60
- for (const manifestFile of manifestFiles) {
61
- const separator = manifestFile.indexOf("/");
62
- const pluginDirName = separator === -1 ? manifestFile : manifestFile.slice(0, separator);
63
- const pluginDir = path.join(pluginsDir, pluginDirName);
64
- const manifest = await readPluginManifest(pluginDir);
65
- if (!manifest) {
66
- warn(`Could not read plugin manifest: '${manifestFile}'`);
67
- continue;
68
- }
69
- const plugin = convertManifestToMarketplacePlugin(
70
- manifest,
71
- options.pluginRoot.replace(/^\.\//, ""),
72
- pluginDirName
73
- );
74
- plugins.push(plugin);
75
- verbose(` [OK] ${plugin.name}`);
76
- }
77
- const sortedPlugins = sortBy(plugins, (p) => p.name);
78
- return {
79
- $schema: MARKETPLACE_SCHEMA_URL,
80
- name: options.name,
81
- version: options.version ?? DEFAULT_VERSION,
82
- owner: {
83
- name: options.ownerName,
84
- ...options.ownerEmail ? { email: options.ownerEmail } : {}
85
- },
86
- metadata: {
87
- pluginRoot: options.pluginRoot
88
- },
89
- plugins: sortedPlugins,
90
- ...options.description ? { description: options.description } : {}
91
- };
92
- }
93
- async function writeMarketplace(outputPath, marketplace) {
94
- await ensureDir(path.dirname(outputPath));
95
- const content = `${JSON.stringify(marketplace, null, 2)}
96
- `;
97
- await writeFile(outputPath, content);
98
- }
99
- function getMarketplaceStats(marketplace) {
100
- return {
101
- total: marketplace.plugins.length,
102
- byCategory: countBy(marketplace.plugins, (p) => p.category ?? "uncategorized")
103
- };
104
- }
105
-
106
- // src/cli/lib/validate-kebab-name.ts
107
- function validateKebabCaseName(name, noun) {
108
- if (!name || name.trim() === "") {
109
- return `${noun} name is required`;
110
- }
111
- if (!KEBAB_CASE_PATTERN.test(name)) {
112
- return `${noun} name must be kebab-case (lowercase letters, numbers, and hyphens, starting with a letter)`;
113
- }
114
- return null;
115
- }
116
-
117
- // src/cli/commands/build/marketplace.ts
45
+ import { sortBy } from "remeda";
46
+ import { z } from "zod";
118
47
  var DEFAULT_OUTPUT_FILE = `${PLUGIN_MANIFEST_DIR}/${MARKETPLACE_JSON}`;
119
48
  var AUTHOR_STRING_PATTERN = /^(.*?)\s*<([^>]+)>\s*(?:\(([^)]+)\))?\s*$/;
49
+ var MARKETPLACE_NOUN = "Marketplace";
120
50
  var packageAuthorObjectSchema = z.object({
121
51
  name: z.string(),
122
52
  email: z.string().exactOptional(),
@@ -173,8 +103,8 @@ var BuildMarketplace = class _BuildMarketplace extends BaseCommand {
173
103
  const { flags } = await this.parse(_BuildMarketplace);
174
104
  setVerbose(flags.verbose);
175
105
  const projectRoot = process.cwd();
176
- const pluginsDir = path2.resolve(projectRoot, flags["plugins-dir"]);
177
- const outputPath = path2.resolve(projectRoot, flags.output);
106
+ const pluginsDir = path.resolve(projectRoot, flags["plugins-dir"]);
107
+ const outputPath = path.resolve(projectRoot, flags.output);
178
108
  const identity = await this.loadMarketplaceIdentity(projectRoot, flags.name);
179
109
  this.printHeader(pluginsDir, outputPath);
180
110
  try {
@@ -184,6 +114,7 @@ var BuildMarketplace = class _BuildMarketplace extends BaseCommand {
184
114
  flags["plugins-dir"],
185
115
  identity
186
116
  );
117
+ await this.writeCatalog(projectRoot, outputPath);
187
118
  this.printStats(marketplace);
188
119
  this.printSample(marketplace);
189
120
  this.log("");
@@ -197,7 +128,7 @@ var BuildMarketplace = class _BuildMarketplace extends BaseCommand {
197
128
  }
198
129
  }
199
130
  async loadMarketplaceIdentity(projectRoot, nameOverride) {
200
- const packageJsonPath = path2.join(projectRoot, "package.json");
131
+ const packageJsonPath = path.join(projectRoot, STANDARD_FILES.PACKAGE_JSON);
201
132
  let rawContent;
202
133
  try {
203
134
  rawContent = await readFile(packageJsonPath);
@@ -224,16 +155,17 @@ var BuildMarketplace = class _BuildMarketplace extends BaseCommand {
224
155
  );
225
156
  }
226
157
  const { name, version, description, author } = parseResult.data;
158
+ if (version.trim() === "") {
159
+ this.error(marketplaceHasNoVersion(packageJsonPath), { exit: EXIT_CODES.ERROR });
160
+ }
227
161
  const owner = parseAuthor(author);
228
- let resolvedName = name;
229
- if (nameOverride !== void 0) {
230
- const validationError = validateKebabCaseName(nameOverride, "Marketplace");
231
- if (validationError) {
232
- this.error(`Invalid --name '${nameOverride}': ${validationError}`, {
233
- exit: EXIT_CODES.INVALID_ARGS
234
- });
235
- }
236
- resolvedName = nameOverride;
162
+ if (owner.name.trim() === "") {
163
+ this.error(marketplaceOwnerHasNoName(packageJsonPath), { exit: EXIT_CODES.ERROR });
164
+ }
165
+ const resolvedName = this.resolvePublishableName(name, nameOverride, packageJsonPath);
166
+ const reservedError = validateMarketplaceName(resolvedName, name);
167
+ if (reservedError) {
168
+ this.error(reservedError, { exit: EXIT_CODES.ERROR });
237
169
  }
238
170
  return {
239
171
  name: resolvedName,
@@ -243,6 +175,32 @@ var BuildMarketplace = class _BuildMarketplace extends BaseCommand {
243
175
  ...owner.email !== void 0 && { ownerEmail: owner.email }
244
176
  };
245
177
  }
178
+ /**
179
+ * The name this marketplace publishes under, refused before anything is written when
180
+ * it is not one `claude plugin marketplace add` will accept.
181
+ *
182
+ * Both halves are judged by the same rule and refused with different sentences: a
183
+ * `--name` the author typed is an argument they can retype, while a name derived from
184
+ * package.json is a fact about their package — an npm scoped name is legitimate there
185
+ * and illegitimate here — so its way out is the flag rather than a package rename.
186
+ */
187
+ resolvePublishableName(packageName, nameOverride, packageJsonPath) {
188
+ if (nameOverride !== void 0) {
189
+ const invalidOverride = validateKebabCaseName(nameOverride, MARKETPLACE_NOUN);
190
+ if (invalidOverride) {
191
+ this.error(`Invalid --name '${nameOverride}': ${invalidOverride}`, {
192
+ exit: EXIT_CODES.INVALID_ARGS
193
+ });
194
+ }
195
+ return nameOverride;
196
+ }
197
+ if (validateKebabCaseName(packageName, MARKETPLACE_NOUN)) {
198
+ this.error(marketplaceNameNotPublishable(packageName, packageJsonPath), {
199
+ exit: EXIT_CODES.ERROR
200
+ });
201
+ }
202
+ return packageName;
203
+ }
246
204
  printHeader(pluginsDir, outputPath) {
247
205
  this.log("");
248
206
  this.log("Generating marketplace.json");
@@ -262,15 +220,41 @@ var BuildMarketplace = class _BuildMarketplace extends BaseCommand {
262
220
  });
263
221
  const stats = getMarketplaceStats(marketplace);
264
222
  this.log(`Found ${stats.total} plugins`);
223
+ if (marketplace.plugins.length === 0) {
224
+ this.error(noPluginsToPublish(pluginsDir, pluginsDirFlag), { exit: EXIT_CODES.ERROR });
225
+ }
226
+ const namespaceError = validateSkillIdNamespace(marketplace);
227
+ if (namespaceError) {
228
+ this.error(namespaceError, { exit: EXIT_CODES.ERROR });
229
+ }
265
230
  this.log("Writing marketplace.json...");
266
231
  await writeMarketplace(outputPath, marketplace);
267
232
  this.log(`Wrote ${outputPath}`);
268
233
  return marketplace;
269
234
  }
235
+ /**
236
+ * Writes the marketplace's catalogue beside its manifest.
237
+ *
238
+ * Unconditional, and there is no flag to make it otherwise: a consumer
239
+ * fetching a marketplace cannot tell an author who omitted a flag from a
240
+ * marketplace that is broken, so an absent catalogue has to mean the second.
241
+ *
242
+ * `generatedAt` is stamped rather than carried: see {@link GENERATED_AT_BUILD}
243
+ * for why a published artefact records a build and not a moment.
244
+ */
245
+ async writeCatalog(projectRoot, outputPath) {
246
+ const catalogPath = path.join(path.dirname(outputPath), CATALOG_JSON);
247
+ this.log(`Writing ${CATALOG_JSON}...`);
248
+ const matrix = await loadMarketplaceMatrix(projectRoot);
249
+ const catalog = { ...matrix, generatedAt: GENERATED_AT_BUILD };
250
+ await writeFile(catalogPath, `${JSON.stringify(catalog, null, 2)}
251
+ `);
252
+ this.log(`Wrote ${catalogPath}`);
253
+ }
270
254
  printStats(marketplace) {
271
255
  this.log("");
272
256
  this.log("Category breakdown:");
273
- const sortedCategories = sortBy2(
257
+ const sortedCategories = sortBy(
274
258
  Object.entries(getMarketplaceStats(marketplace).byCategory),
275
259
  ([, count]) => -count
276
260
  );
@@ -295,24 +279,17 @@ var BuildMarketplace = class _BuildMarketplace extends BaseCommand {
295
279
  }
296
280
  }
297
281
  };
282
+ function noPluginsToPublish(pluginsDir, pluginsDirFlag) {
283
+ return `No plugins found in ${pluginsDir}. A marketplace with no plugins is refused when it is read back, so none was written. Run '${CLI_INVOKE_COMMAND} build plugins' first, or point --plugins-dir at the directory holding them (it is '${pluginsDirFlag}' for this run).`;
284
+ }
298
285
  function parseAuthor(author) {
299
- if (!author) {
300
- warn("package.json is missing 'author' field \u2014 marketplace owner.email will be empty");
301
- return { name: "" };
302
- }
286
+ if (!author) return { name: "" };
303
287
  if (typeof author === "object") {
304
288
  return { name: author.name, ...author.email !== void 0 && { email: author.email } };
305
289
  }
306
290
  const [, matchedName, matchedEmail] = author.match(AUTHOR_STRING_PATTERN) ?? [];
307
291
  if (matchedName !== void 0 && matchedEmail !== void 0) {
308
- const name = matchedName.trim();
309
- const email = matchedEmail.trim();
310
- if (name === "") {
311
- warn(
312
- `package.json 'author' field "${author}" has no parseable name \u2014 marketplace owner.name will be empty`
313
- );
314
- }
315
- return { name, email };
292
+ return { name: matchedName.trim(), email: matchedEmail.trim() };
316
293
  }
317
294
  warn(
318
295
  `package.json 'author' field "${author}" has no parseable email \u2014 marketplace owner.email will be empty`