agents-inc 0.154.0 → 0.155.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 +41 -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
@@ -0,0 +1,142 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ orderDomains
4
+ } from "./chunk-F5T6TV4Z.js";
5
+ import {
6
+ DEFAULT_SELECTION_OPTIONS,
7
+ isScopePairCompatible,
8
+ validateSelection
9
+ } from "./chunk-WCAUUBHO.js";
10
+ import {
11
+ AGENT_NAMES
12
+ } from "./chunk-XAXJWXI4.js";
13
+ import {
14
+ getCategoryDomain
15
+ } from "./chunk-RWOYPOMR.js";
16
+ import {
17
+ DEFAULT_PUBLIC_SOURCE_NAME
18
+ } from "./chunk-IO5YBKHV.js";
19
+
20
+ // src/cli/lib/seed/seed-to-wizard.ts
21
+ var KNOWN_AGENTS = new Set(AGENT_NAMES);
22
+ function sourceForSkill(skill) {
23
+ return skill?.availableSources?.find((s) => s.primary)?.name ?? DEFAULT_PUBLIC_SOURCE_NAME;
24
+ }
25
+ function addToDomainSelections(selections, domain, category, skillId) {
26
+ const categorySelections = selections[domain] ??= {};
27
+ const skillList = categorySelections[category] ??= [];
28
+ if (!skillList.includes(skillId)) skillList.push(skillId);
29
+ }
30
+ function addToAgentStack(stack, agent, category, assignment) {
31
+ const agentStack = stack[agent] ??= {};
32
+ const assignments = agentStack[category] ??= [];
33
+ assignments.push(assignment);
34
+ }
35
+ function toSkillAssignment(skillId, load) {
36
+ return { id: skillId, preloaded: load === "preloaded" };
37
+ }
38
+ function readAgentMap(agents) {
39
+ const known = /* @__PURE__ */ new Map();
40
+ const switchedOff = /* @__PURE__ */ new Set();
41
+ const unknown = [];
42
+ for (const [name, entry] of Object.entries(agents)) {
43
+ if (!KNOWN_AGENTS.has(name)) unknown.push(name);
44
+ else if (entry.on === false) switchedOff.add(name);
45
+ else known.set(name, entry);
46
+ }
47
+ return { known, switchedOff, unknown };
48
+ }
49
+ function seedAgentScope(entry) {
50
+ return entry?.scope ?? DEFAULT_SELECTION_OPTIONS.scope;
51
+ }
52
+ function agentScopeConfig(name, entry) {
53
+ return {
54
+ name,
55
+ scope: seedAgentScope(entry),
56
+ ...entry?.model !== void 0 && { model: entry.model },
57
+ ...entry?.effort !== void 0 && { effort: entry.effort }
58
+ };
59
+ }
60
+ function unwritableAssignmentsError(assignments) {
61
+ return [
62
+ "This configuration cannot be installed: a project-scoped skill never reaches a sub-agent that rests at global scope, so these assignments have nowhere to be written:",
63
+ ...assignments.map(({ skillId, agent }) => ` ${skillId} -> ${agent}`),
64
+ "Re-share it with each sub-agent above pinned to the project, or each skill above at global scope."
65
+ ].join("\n");
66
+ }
67
+ function seedToWizardResult(payload, matrix) {
68
+ const domainSelections = {};
69
+ const assignedStack = {};
70
+ const skills = [];
71
+ const skippedSkillIds = [];
72
+ const unwritable = [];
73
+ const agentNames = /* @__PURE__ */ new Set();
74
+ const agentMap = readAgentMap(payload.agents);
75
+ const skippedAgentNames = new Set(agentMap.unknown);
76
+ for (const [skillId, entry] of Object.entries(payload.skills)) {
77
+ const skill = matrix.skills[skillId];
78
+ const domain = skill?.category ? getCategoryDomain(skill.category) : void 0;
79
+ if (!skill?.category || !domain) {
80
+ skippedSkillIds.push(skillId);
81
+ continue;
82
+ }
83
+ const id = skillId;
84
+ const category = skill.category;
85
+ addToDomainSelections(domainSelections, domain, category, id);
86
+ skills.push({
87
+ id,
88
+ scope: entry.scope,
89
+ // "eject" is an origin in its own right; anything else names the marketplace it came from.
90
+ origin: entry.install === "eject" ? "eject" : sourceForSkill(skill)
91
+ });
92
+ for (const [agentName, load] of Object.entries(entry.assignments)) {
93
+ if (agentMap.switchedOff.has(agentName)) continue;
94
+ if (!KNOWN_AGENTS.has(agentName)) {
95
+ skippedAgentNames.add(agentName);
96
+ continue;
97
+ }
98
+ const agent = agentName;
99
+ if (!isScopePairCompatible(entry.scope, seedAgentScope(agentMap.known.get(agent)))) {
100
+ unwritable.push({ skillId: id, agent });
101
+ continue;
102
+ }
103
+ agentNames.add(agent);
104
+ addToAgentStack(assignedStack, agent, category, toSkillAssignment(id, load));
105
+ }
106
+ }
107
+ if (unwritable.length > 0) throw new Error(unwritableAssignmentsError(unwritable));
108
+ for (const [name, entry] of agentMap.known) {
109
+ if (entry.on === true) agentNames.add(name);
110
+ }
111
+ const selectedAgents = [...agentNames];
112
+ return {
113
+ result: {
114
+ skills,
115
+ selectedAgents,
116
+ agentConfigs: selectedAgents.map((name) => agentScopeConfig(name, agentMap.known.get(name))),
117
+ assignedStack,
118
+ selectedStackId: payload.stackId,
119
+ domainSelections,
120
+ selectedDomains: orderDomains(Object.keys(domainSelections)),
121
+ // Nothing was dropped from a *saved config* — the skipped ids came off the wire and are
122
+ // reported to the user directly, so there is no config removal to explain.
123
+ unresolvableSkillIds: [],
124
+ cancelled: false,
125
+ // Revalidated here rather than taken on trust from the app that built the payload. That app
126
+ // validated against ITS catalog; this one skips ids it does not know and carries its own
127
+ // relationship rules, so a configuration that was consistent where it was authored can
128
+ // arrive with a requirement genuinely unmet. Running the same validator the wizard runs
129
+ // makes that this catalog's verdict on what it can install — reported through the spine
130
+ // `init` already has, beside the skips that explain it — rather than a fault in what was
131
+ // shared.
132
+ validation: validateSelection(skills.map((skill) => skill.id))
133
+ },
134
+ skippedSkillIds,
135
+ skippedAgentNames: [...skippedAgentNames]
136
+ };
137
+ }
138
+
139
+ export {
140
+ seedToWizardResult
141
+ };
142
+ //# sourceMappingURL=chunk-MO5FGLVS.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/cli/lib/seed/seed-to-wizard.ts"],"sourcesContent":["import { DEFAULT_SELECTION_OPTIONS } from \"@workspace/matrix\";\n\nimport { AGENT_NAMES } from \"../../types/agents.js\";\nimport { DEFAULT_PUBLIC_SOURCE_NAME } from \"../../consts.js\";\nimport { isScopePairCompatible } from \"../configuration/config-generator.js\";\nimport { getCategoryDomain } from \"../matrix/matrix-provider.js\";\nimport { validateSelection } from \"../matrix/matrix-resolver.js\";\nimport { orderDomains } from \"../wizard/domain-order.js\";\n\nimport type { WizardResultV2 } from \"../../components/wizard/wizard.js\";\nimport type { AgentName } from \"../../types/agents.js\";\nimport type { AgentScopeConfig, SkillConfig, SkillScope } from \"../../types/config.js\";\nimport type {\n Category,\n Domain,\n DomainSelections,\n MergedSkillsMatrix,\n ResolvedSkill,\n} from \"../../types/matrix.js\";\nimport type { SkillAssignment, SkillId } from \"../../types/skills.js\";\nimport type { StackAgentConfig } from \"../../types/stacks.js\";\nimport type { SeedAgent, SeedLoadState, SeedPayload } from \"@workspace/matrix/seed\";\n\nexport type SeedMapping = {\n result: WizardResultV2;\n /** Ids this matrix does not know. Reported, never fatal — see the decode policy. */\n skippedSkillIds: string[];\n skippedAgentNames: string[];\n};\n\nconst KNOWN_AGENTS = new Set<string>(AGENT_NAMES);\n\n/** A skill's primary source, or the default marketplace. Mirrors the wizard's own resolution. */\nfunction sourceForSkill(skill: ResolvedSkill | undefined): string {\n return skill?.availableSources?.find((s) => s.primary)?.name ?? DEFAULT_PUBLIC_SOURCE_NAME;\n}\n\nfunction addToDomainSelections(\n selections: DomainSelections,\n domain: Domain,\n category: Category,\n skillId: SkillId,\n): void {\n const categorySelections = (selections[domain] ??= {});\n const skillList = (categorySelections[category] ??= []);\n if (!skillList.includes(skillId)) skillList.push(skillId);\n}\n\n/**\n * The stack mirror of {@link addToDomainSelections}: one sub-agent's own category lists, appended\n * in payload order. A `(skill, sub-agent)` pair can only occur once — `skills` is keyed by id — so\n * there is nothing to de-duplicate here.\n */\nfunction addToAgentStack(\n stack: Partial<Record<AgentName, StackAgentConfig>>,\n agent: AgentName,\n category: Category,\n assignment: SkillAssignment,\n): void {\n const agentStack = (stack[agent] ??= {});\n const assignments = (agentStack[category] ??= []);\n assignments.push(assignment);\n}\n\n/** A load state is per `(skill, sub-agent)`; `preloaded` is the stack's word for the same thing. */\nfunction toSkillAssignment(skillId: SkillId, load: SeedLoadState): SkillAssignment {\n return { id: skillId, preloaded: load === \"preloaded\" };\n}\n\n/** The payload's `agents` map, split by what this catalog can do with each entry. */\ntype SeedAgentMap = {\n /** Known agents the map has something to say about, keyed by name. */\n known: Map<AgentName, SeedAgent>;\n /** Names explicitly switched off — dropped, and their assignment rows ignored with them. */\n switchedOff: Set<string>;\n /** Names this catalog does not know. Reported, never fatal — same policy as unknown skill ids. */\n unknown: string[];\n};\n\nfunction readAgentMap(agents: SeedPayload[\"agents\"]): SeedAgentMap {\n const known = new Map<AgentName, SeedAgent>();\n const switchedOff = new Set<string>();\n const unknown: string[] = [];\n\n for (const [name, entry] of Object.entries(agents)) {\n if (!KNOWN_AGENTS.has(name)) unknown.push(name);\n else if (entry.on === false) switchedOff.add(name);\n else known.set(name as AgentName, entry);\n }\n\n return { known, switchedOff, unknown };\n}\n\n/**\n * Where a sub-agent's front-matter is written is the payload's to say, per agent and\n * independently of any skill's scope: an entry may pin its agent into the project, and one that\n * names no scope goes to the user's own ~/.claude — the shared selection default, spelled once in\n * the matrix so the editor and this decode cannot disagree about it.\n */\nfunction seedAgentScope(entry: SeedAgent | undefined): SkillScope {\n return entry?.scope ?? DEFAULT_SELECTION_OPTIONS.scope;\n}\n\n/**\n * A sub-agent's own row. Model and effort ride along on the same terms as its scope — an absent\n * key means \"keep whatever the agent's metadata says\".\n */\nfunction agentScopeConfig(name: AgentName, entry: SeedAgent | undefined): AgentScopeConfig {\n return {\n name,\n scope: seedAgentScope(entry),\n ...(entry?.model !== undefined && { model: entry.model }),\n ...(entry?.effort !== undefined && { effort: entry.effort }),\n };\n}\n\n/** A `(skill, sub-agent)` assignment the config model has nowhere to write. */\ntype UnwritableAssignment = { skillId: SkillId; agent: AgentName };\n\n/**\n * Names every unwritable pair, not just the first: a sharer who fixes one only to be refused for\n * the next learns nothing the first message could not have told them. Both halves of each pair are\n * named because neither alone says what to change — the skill can move to global scope, or the\n * sub-agent can be pinned to the project, and only the sharer knows which they meant.\n */\nfunction unwritableAssignmentsError(assignments: UnwritableAssignment[]): string {\n return [\n \"This configuration cannot be installed: a project-scoped skill never reaches a sub-agent \" +\n \"that rests at global scope, so these assignments have nowhere to be written:\",\n ...assignments.map(({ skillId, agent }) => ` ${skillId} -> ${agent}`),\n \"Re-share it with each sub-agent above pinned to the project, or each skill above at global scope.\",\n ].join(\"\\n\");\n}\n\n/**\n * Turns a shared configuration into the shape the install pipeline already consumes, so\n * `init --from` reuses `writeProjectConfig` -> skill install -> `compileAgentsAllScopes`\n * unchanged rather than growing a second path that can drift from the wizard's.\n *\n * Unknown ids are skipped, never fatal. Payloads carry catalog slugs precisely so they survive\n * catalog churn: a config shared before a skill was renamed should still install everything else,\n * and failing the whole decode would make every rename retroactively break every shared id.\n *\n * A sub-agent reaches the roster two ways: named by a surviving skill's assignment, or switched on\n * in the `agents` map. The map is the only place a configuration can say anything about an agent\n * no skill mentions, which is what makes a bare (skill-less) agent shareable at all; it also\n * carries that agent's model and effort onto its `AgentScopeConfig`.\n *\n * The `assignments` map is per `(skill, sub-agent)` and carries a load state, so it decides three\n * things the wizard cannot express separately: which sub-agents are selected, which skills land in\n * each one's stack entry, and which of those preload. That is why the result carries an\n * `assignedStack` — the install pipeline's ownership rules broadcast every scope-compatible skill\n * to every selected agent, which would hand a bare sub-agent someone else's skills.\n *\n * An unwritable `(skill, sub-agent)` pair is the one thing here that IS fatal, and it is fatal for\n * the opposite reason to the skips: an unknown id is content this catalog does not have, while an\n * unwritable pair is content it has and cannot place. Because `assignedStack` replaces the derived\n * stack wholesale, no scope filter runs on these rows downstream — they reach the writers, which\n * put them in neither half of the split config and say nothing. Refusing at the decode is what\n * keeps a payload from installing as a quieter configuration than the one that was shared.\n */\nexport function seedToWizardResult(payload: SeedPayload, matrix: MergedSkillsMatrix): SeedMapping {\n const domainSelections: DomainSelections = {};\n const assignedStack: Partial<Record<AgentName, StackAgentConfig>> = {};\n const skills: SkillConfig[] = [];\n const skippedSkillIds: string[] = [];\n const unwritable: UnwritableAssignment[] = [];\n const agentNames = new Set<AgentName>();\n const agentMap = readAgentMap(payload.agents);\n const skippedAgentNames = new Set<string>(agentMap.unknown);\n\n for (const [skillId, entry] of Object.entries(payload.skills)) {\n const skill = matrix.skills[skillId as SkillId];\n const domain = skill?.category ? getCategoryDomain(skill.category) : undefined;\n\n if (!skill?.category || !domain) {\n skippedSkillIds.push(skillId);\n continue;\n }\n\n // Past the guard the matrix knows this id, and its category is a real one: the `local`\n // pseudo-category has no domain, so it left with the skips.\n const id = skillId as SkillId;\n const category = skill.category as Category;\n\n addToDomainSelections(domainSelections, domain, category, id);\n\n skills.push({\n id,\n scope: entry.scope,\n // \"eject\" is an origin in its own right; anything else names the marketplace it came from.\n origin: entry.install === \"eject\" ? \"eject\" : sourceForSkill(skill),\n });\n\n // Only assignments on skills that survived — an agent should not be switched on by a skill\n // this catalog cannot install.\n for (const [agentName, load] of Object.entries(entry.assignments)) {\n if (agentMap.switchedOff.has(agentName)) continue;\n if (!KNOWN_AGENTS.has(agentName)) {\n skippedAgentNames.add(agentName);\n continue;\n }\n\n const agent = agentName as AgentName;\n // Rows the decode was going to ignore anyway have already left, so what reaches here is a\n // pair the payload really asked for — and the config model's one rule about pairs applies.\n if (!isScopePairCompatible(entry.scope, seedAgentScope(agentMap.known.get(agent)))) {\n unwritable.push({ skillId: id, agent });\n continue;\n }\n\n agentNames.add(agent);\n // The assignment is the curation: this sub-agent holds this skill, at this load state, and\n // no sub-agent the payload did not name holds it at all.\n addToAgentStack(assignedStack, agent, category, toSkillAssignment(id, load));\n }\n }\n\n if (unwritable.length > 0) throw new Error(unwritableAssignmentsError(unwritable));\n\n // Bare agents: switched on by the map alone, with no skill to carry them in.\n for (const [name, entry] of agentMap.known) {\n if (entry.on === true) agentNames.add(name);\n }\n\n const selectedAgents = [...agentNames];\n\n return {\n result: {\n skills,\n selectedAgents,\n agentConfigs: selectedAgents.map((name) => agentScopeConfig(name, agentMap.known.get(name))),\n assignedStack,\n selectedStackId: payload.stackId,\n domainSelections,\n selectedDomains: orderDomains(Object.keys(domainSelections) as Domain[]),\n // Nothing was dropped from a *saved config* — the skipped ids came off the wire and are\n // reported to the user directly, so there is no config removal to explain.\n unresolvableSkillIds: [],\n cancelled: false,\n // Revalidated here rather than taken on trust from the app that built the payload. That app\n // validated against ITS catalog; this one skips ids it does not know and carries its own\n // relationship rules, so a configuration that was consistent where it was authored can\n // arrive with a requirement genuinely unmet. Running the same validator the wizard runs\n // makes that this catalog's verdict on what it can install — reported through the spine\n // `init` already has, beside the skips that explain it — rather than a fault in what was\n // shared.\n validation: validateSelection(skills.map((skill) => skill.id)),\n },\n skippedSkillIds,\n skippedAgentNames: [...skippedAgentNames],\n };\n}\n"],"mappings":"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","names":[]}
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  SCROLL_VIEWPORT
4
- } from "./chunk-R54KIGN2.js";
4
+ } from "./chunk-IO5YBKHV.js";
5
5
 
6
6
  // src/cli/components/hooks/use-section-scroll.ts
7
7
  import { useCallback, useEffect, useRef, useState } from "react";
@@ -118,4 +118,4 @@ export {
118
118
  useSectionScroll,
119
119
  computeRowScrollTop
120
120
  };
121
- //# sourceMappingURL=chunk-Q5FLW4JG.js.map
121
+ //# sourceMappingURL=chunk-OKH64JZE.js.map
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  StackSelection
4
- } from "./chunk-2IMYK4WN.js";
4
+ } from "./chunk-PNMM5HNX.js";
5
5
 
6
6
  // src/cli/components/wizard/step-stack.tsx
7
7
  import { Box } from "ink";
@@ -14,4 +14,4 @@ var StepStack = ({ onCancel }) => {
14
14
  export {
15
15
  StepStack
16
16
  };
17
- //# sourceMappingURL=chunk-WRRP47PY.js.map
17
+ //# sourceMappingURL=chunk-PCC4LBKB.js.map
@@ -0,0 +1,258 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ claimSlug,
4
+ computeFileHash,
5
+ injectForkedFromMetadata,
6
+ readLocalSkillMetadata,
7
+ resolveInstallPaths,
8
+ seedExternalSkillSchema,
9
+ seedPayloadSchema,
10
+ validateSkillPath,
11
+ writeMetadataYaml
12
+ } from "./chunk-WCAUUBHO.js";
13
+ import {
14
+ glob,
15
+ readFile,
16
+ readSkillMetadata,
17
+ writeFile
18
+ } from "./chunk-XAXJWXI4.js";
19
+ import {
20
+ getCategoryDomain
21
+ } from "./chunk-RWOYPOMR.js";
22
+ import {
23
+ typedEntries
24
+ } from "./chunk-VASLW636.js";
25
+ import {
26
+ GITHUB_SOURCE,
27
+ LOCAL_SKILLS_PATH,
28
+ STANDARD_FILES
29
+ } from "./chunk-IO5YBKHV.js";
30
+
31
+ // src/cli/lib/seed/external-skills.ts
32
+ import path from "path";
33
+ function pluginInstallError(ids) {
34
+ return [
35
+ "This configuration cannot be installed: these skills travel inside it, so no marketplace serves them and they cannot be installed as plugins:",
36
+ ...ids.map((id) => ` ${id}`),
37
+ "Re-share it with each skill above set to eject, which is the only way a carried skill installs."
38
+ ].join("\n");
39
+ }
40
+ function selectedExternals(payload) {
41
+ return typedEntries(payload.external ?? {}).flatMap(([id, skill]) => {
42
+ const entry = payload.skills[id];
43
+ return entry ? [{ id, skill, entry }] : [];
44
+ });
45
+ }
46
+ function askedForAsPlugin(externals) {
47
+ return externals.filter(({ entry }) => entry.install !== "eject").map(({ id }) => id);
48
+ }
49
+ function externalSlug(id) {
50
+ return id;
51
+ }
52
+ function skillAuthor(repo) {
53
+ const [owner = repo] = repo.split("/");
54
+ return `@${owner}`;
55
+ }
56
+ function repoRef(repo) {
57
+ return `${GITHUB_SOURCE.GITHUB_PREFIX}${repo}`;
58
+ }
59
+ function externalSkillDir(id, scope, projectDir) {
60
+ return path.join(resolveInstallPaths(projectDir, scope).skillsDir, id);
61
+ }
62
+ function externalCatalogueEntry(install) {
63
+ return {
64
+ id: install.id,
65
+ slug: externalSlug(install.id),
66
+ displayName: install.skill.displayName,
67
+ description: install.skill.description,
68
+ // Boundary cast held by the guard above it: the category was confirmed against the catalogue
69
+ // the payload names, and this one has just been shown to declare it too.
70
+ category: install.skill.categoryId,
71
+ author: skillAuthor(install.skill.repo),
72
+ path: `${LOCAL_SKILLS_PATH}/${install.id}/`,
73
+ conflictsWith: [],
74
+ requires: [],
75
+ alternatives: [],
76
+ discourages: [],
77
+ // Local and custom for the same reason: the bytes are on this machine and nowhere else, and
78
+ // the skill was authored outside the vocabulary this catalogue ships.
79
+ local: true,
80
+ custom: true,
81
+ localPath: install.skillDir
82
+ };
83
+ }
84
+ function seatExternalSkill({ id, skill, entry }, matrix, projectDir) {
85
+ const domain = getCategoryDomain(skill.categoryId);
86
+ if (domain === void 0) return [];
87
+ const install = {
88
+ id,
89
+ skill,
90
+ domain,
91
+ scope: entry.scope,
92
+ skillDir: externalSkillDir(id, entry.scope, projectDir)
93
+ };
94
+ matrix.skills[id] = externalCatalogueEntry(install);
95
+ claimSlug(matrix.slugMap, externalSlug(id), id);
96
+ return [install];
97
+ }
98
+ function registerExternalSkills(payload, matrix, projectDir) {
99
+ const externals = selectedExternals(payload);
100
+ const asPlugin = askedForAsPlugin(externals);
101
+ if (asPlugin.length > 0) throw new Error(pluginInstallError(asPlugin));
102
+ return externals.flatMap((external) => seatExternalSkill(external, matrix, projectDir));
103
+ }
104
+ async function writeExternalSkills(installs) {
105
+ for (const install of installs) {
106
+ await writeSkillTree(install);
107
+ await writeSkillManifest(install);
108
+ await registerSkillOnDisk(install);
109
+ }
110
+ }
111
+ async function writeSkillTree(install) {
112
+ for (const [relativePath, contents] of Object.entries(install.skill.files)) {
113
+ const filePath = path.join(install.skillDir, relativePath);
114
+ validateSkillPath(filePath, install.skillDir, relativePath);
115
+ await writeFile(filePath, contents);
116
+ }
117
+ }
118
+ var FRONTMATTER_BLOCK = /^---\r?\n([\s\S]*?)\r?\n---/;
119
+ var NAME_FIELD = /^name:.*$/m;
120
+ function withInstalledName(manifest, install) {
121
+ const named = `name: ${install.id}`;
122
+ const block = FRONTMATTER_BLOCK.exec(manifest);
123
+ if (!block) {
124
+ return `---
125
+ ${named}
126
+ description: ${install.skill.description}
127
+ ---
128
+
129
+ ${manifest}`;
130
+ }
131
+ const [whole, fields = ""] = block;
132
+ const renamed = NAME_FIELD.test(fields) ? fields.replace(NAME_FIELD, named) : `${named}
133
+ ${fields}`;
134
+ return `---
135
+ ${renamed}
136
+ ---${manifest.slice(whole.length)}`;
137
+ }
138
+ async function writeSkillManifest(install) {
139
+ const manifestPath = path.join(install.skillDir, STANDARD_FILES.SKILL_MD);
140
+ await writeFile(manifestPath, withInstalledName(await readFile(manifestPath), install));
141
+ }
142
+ function externalSkillMetadata(install, shipped) {
143
+ return {
144
+ author: skillAuthor(install.skill.repo),
145
+ usageGuidance: `Use when working with ${install.skill.displayName}`,
146
+ ...shipped,
147
+ displayName: install.skill.displayName,
148
+ slug: install.id,
149
+ category: install.skill.categoryId,
150
+ domain: install.domain,
151
+ cliDescription: install.skill.description,
152
+ custom: true
153
+ };
154
+ }
155
+ async function registerSkillOnDisk(install) {
156
+ const metadataPath = path.join(install.skillDir, STANDARD_FILES.METADATA_YAML);
157
+ const shipped = await readLocalSkillMetadata(install.skillDir);
158
+ await writeMetadataYaml(metadataPath, externalSkillMetadata(install, shipped));
159
+ await injectForkedFromMetadata(
160
+ install.skillDir,
161
+ install.id,
162
+ await computeFileHash(path.join(install.skillDir, STANDARD_FILES.SKILL_MD)),
163
+ { source: repoRef(install.skill.repo), path: install.skill.path }
164
+ );
165
+ }
166
+ function unnameableRepoMessage(id) {
167
+ return `${id} travels inside a shared configuration, and this installation does not record the repository its content came from`;
168
+ }
169
+ function uncarryableContentMessage(id, reason) {
170
+ return `${id} travels inside a shared configuration, and ${reason}`;
171
+ }
172
+ function repoFromRef(ref) {
173
+ if (ref === void 0 || !ref.startsWith(GITHUB_SOURCE.GITHUB_PREFIX)) return void 0;
174
+ return ref.slice(GITHUB_SOURCE.GITHUB_PREFIX.length);
175
+ }
176
+ async function readSkillTree(skillDir) {
177
+ const files = await glob("**/*", skillDir, { dot: true });
178
+ const entries = await Promise.all(
179
+ files.map(async (file) => [file, await readFile(path.join(skillDir, file))])
180
+ );
181
+ return Object.fromEntries(entries);
182
+ }
183
+ async function readCarriedSkill({ id, skillDir, provenance }) {
184
+ if (provenance.path === void 0) return { carries: "nothing" };
185
+ const repo = repoFromRef(provenance.source);
186
+ if (repo === void 0) return { carries: "unshareable", line: unnameableRepoMessage(id) };
187
+ const described = await readSkillMetadata(path.join(skillDir, STANDARD_FILES.METADATA_YAML));
188
+ if (!described.usable) {
189
+ return { carries: "unshareable", line: uncarryableContentMessage(id, described.reason) };
190
+ }
191
+ const parsed = seedExternalSkillSchema.safeParse({
192
+ displayName: described.metadata.displayName,
193
+ description: described.metadata.cliDescription,
194
+ categoryId: described.metadata.category,
195
+ repo,
196
+ path: provenance.path,
197
+ files: await readSkillTree(skillDir)
198
+ });
199
+ if (!parsed.success) {
200
+ const reason = parsed.error.issues.map((issue) => issue.message).join("; ");
201
+ return { carries: "unshareable", line: uncarryableContentMessage(id, reason) };
202
+ }
203
+ return { carries: "content", id, skill: parsed.data };
204
+ }
205
+ async function readCarriedSkills(owned) {
206
+ const reads = await Promise.all(owned.map(readCarriedSkill));
207
+ return {
208
+ external: Object.fromEntries(
209
+ reads.flatMap((read) => read.carries === "content" ? [[read.id, read.skill]] : [])
210
+ ),
211
+ uncarryable: reads.flatMap((read) => read.carries === "unshareable" ? [read.line] : [])
212
+ };
213
+ }
214
+
215
+ // src/cli/lib/seed/fetch-seed.ts
216
+ var SEED_API_URL = process.env.AGENTS_INC_API_URL ?? "https://api.agentsinc.sh";
217
+ var SEED_USER_AGENT = "agents-inc-cli";
218
+ async function fetchSeedConfig(id) {
219
+ const url = `${SEED_API_URL}/configs/${encodeURIComponent(id)}`;
220
+ let response;
221
+ try {
222
+ response = await fetch(url, {
223
+ headers: { accept: "application/json", "user-agent": SEED_USER_AGENT }
224
+ });
225
+ } catch {
226
+ return { ok: false, error: `Could not reach ${SEED_API_URL} \u2014 check your connection.` };
227
+ }
228
+ if (response.status === 404) {
229
+ return { ok: false, error: `No configuration found for id '${id}'.` };
230
+ }
231
+ if (!response.ok) {
232
+ return { ok: false, error: `Fetching configuration failed (HTTP ${response.status}).` };
233
+ }
234
+ let body;
235
+ try {
236
+ body = await response.json();
237
+ } catch {
238
+ return { ok: false, error: "The configuration store returned something that is not JSON." };
239
+ }
240
+ const parsed = seedPayloadSchema.safeParse(body);
241
+ if (!parsed.success) {
242
+ return {
243
+ ok: false,
244
+ error: `Configuration '${id}' is not in a format this version of the CLI can install. Shared ids are never migrated \u2014 re-share the configuration to mint a current one, or update the CLI if that id came from a newer version.`
245
+ };
246
+ }
247
+ return { ok: true, payload: parsed.data };
248
+ }
249
+
250
+ export {
251
+ registerExternalSkills,
252
+ writeExternalSkills,
253
+ readCarriedSkills,
254
+ SEED_API_URL,
255
+ SEED_USER_AGENT,
256
+ fetchSeedConfig
257
+ };
258
+ //# sourceMappingURL=chunk-PMUABBPG.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/cli/lib/seed/external-skills.ts","../src/cli/lib/seed/fetch-seed.ts"],"sourcesContent":["import path from \"path\";\n\nimport { seedExternalSkillSchema } from \"@workspace/matrix/seed\";\n\nimport { GITHUB_SOURCE, LOCAL_SKILLS_PATH, STANDARD_FILES } from \"../../consts.js\";\nimport { resolveInstallPaths } from \"../installation/install-base-dir.js\";\nimport { readSkillMetadata } from \"../loading/loader.js\";\nimport { getCategoryDomain } from \"../matrix/matrix-provider.js\";\nimport { claimSlug } from \"../matrix/skill-resolution.js\";\nimport { validateSkillPath } from \"../skills/skill-copier.js\";\nimport {\n injectForkedFromMetadata,\n readLocalSkillMetadata,\n writeMetadataYaml,\n} from \"../skills/skill-metadata.js\";\nimport { computeFileHash } from \"../versioning.js\";\nimport { glob, readFile, writeFile } from \"../../utils/fs.js\";\nimport { typedEntries } from \"../../utils/typed-object.js\";\n\nimport type { SkillScope } from \"../../types/config.js\";\nimport type { Domain, MergedSkillsMatrix, ResolvedSkill } from \"../../types/matrix.js\";\nimport type { CategoryPath, SkillId, SkillSlug } from \"../../types/skills.js\";\nimport type { ForkedFromMetadata, LocalSkillMetadata } from \"../skills/skill-metadata.js\";\nimport type {\n SeedExternalSkill,\n SeedPayload,\n SeedSkill,\n SeedSkillTree,\n} from \"@workspace/matrix/seed\";\n\n/**\n * One skill the payload carries rather than names, seated and ready to be written.\n *\n * `skillDir` and `domain` are resolved once, where the checks that make them safe already are:\n * the directory has to be the one the catalogue entry points at, because that is what tells the\n * copy step this skill is already where it belongs, and the domain is what the category guard has\n * just proved this catalogue declares.\n */\nexport type ExternalSkillInstall = {\n id: SkillId;\n scope: SkillScope;\n skill: SeedExternalSkill;\n domain: Domain;\n skillDir: string;\n};\n\n/** One external entry with the skill row that selected it — what the payload says about it. */\ntype SelectedExternal = { id: SkillId; skill: SeedExternalSkill; entry: SeedSkill };\n\n/**\n * Names every carried skill a payload asks to install as a plugin, not just the first.\n *\n * There is nothing to install them FROM: the payload is the source, so no marketplace serves\n * these ids. Coercing them to eject would install something the payload did not ask for, under a\n * mode the sharer's own screen still shows as plugin — so the ids are named and the run stops.\n */\nfunction pluginInstallError(ids: SkillId[]): string {\n return [\n \"This configuration cannot be installed: these skills travel inside it, so no marketplace \" +\n \"serves them and they cannot be installed as plugins:\",\n ...ids.map((id) => ` ${id}`),\n \"Re-share it with each skill above set to eject, which is the only way a carried skill installs.\",\n ].join(\"\\n\");\n}\n\n/**\n * The external entries this selection actually names.\n *\n * Presence in `skills` is selection and `external` is only where the bytes are, so content nobody\n * picked installs nothing — seating it would put a skill in the catalogue no part of the\n * configuration asked for.\n */\nfunction selectedExternals(payload: SeedPayload): SelectedExternal[] {\n return typedEntries<SkillId, SeedExternalSkill>(payload.external ?? {}).flatMap(([id, skill]) => {\n const entry = payload.skills[id];\n return entry ? [{ id, skill, entry }] : [];\n });\n}\n\nfunction askedForAsPlugin(externals: SelectedExternal[]): SkillId[] {\n return externals.filter(({ entry }) => entry.install !== \"eject\").map(({ id }) => id);\n}\n\n/**\n * Boundary cast: a carried skill's id is minted at intake and belongs to no generated union,\n * which is exactly what makes it external. It is its own slug too — a skill outside every\n * catalogue has no shorter name anything else would recognise, and the sending side says the same.\n */\nfunction externalSlug(id: SkillId): SkillSlug {\n return id as SkillSlug;\n}\n\n/** The repository's owner as a handle, which is all the authorship a carried skill records. */\nfunction skillAuthor(repo: string): string {\n const [owner = repo] = repo.split(\"/\");\n return `@${owner}`;\n}\n\n/** The repository ref a carried skill's provenance records, in the form every other ref wears. */\nfunction repoRef(repo: string): string {\n return `${GITHUB_SOURCE.GITHUB_PREFIX}${repo}`;\n}\n\n/** Where a carried skill's directory goes: under the skills directory of the scope it names. */\nfunction externalSkillDir(id: SkillId, scope: SkillScope, projectDir: string): string {\n return path.join(resolveInstallPaths(projectDir, scope).skillsDir, id);\n}\n\n/**\n * The catalogue entry a carried skill becomes on arrival.\n *\n * It declares no relationships and is named by none, which is honest: nothing outside the\n * catalogue can say what this skill conflicts with, and nothing inside it knows the skill exists.\n */\nfunction externalCatalogueEntry(install: ExternalSkillInstall): ResolvedSkill {\n return {\n id: install.id,\n slug: externalSlug(install.id),\n displayName: install.skill.displayName,\n description: install.skill.description,\n // Boundary cast held by the guard above it: the category was confirmed against the catalogue\n // the payload names, and this one has just been shown to declare it too.\n category: install.skill.categoryId as CategoryPath,\n author: skillAuthor(install.skill.repo),\n path: `${LOCAL_SKILLS_PATH}/${install.id}/`,\n conflictsWith: [],\n requires: [],\n alternatives: [],\n discourages: [],\n // Local and custom for the same reason: the bytes are on this machine and nowhere else, and\n // the skill was authored outside the vocabulary this catalogue ships.\n local: true,\n custom: true,\n localPath: install.skillDir,\n };\n}\n\n/**\n * Seats one carried skill in the catalogue, or leaves it unseated.\n *\n * A skill is PLACED in the taxonomy and never extends it, so a category this catalogue has no\n * definition for belongs to no domain, renders in no tab and reaches no sub-agent. Left unseated,\n * the id falls to the decode's own skip, which reports it by name.\n */\nfunction seatExternalSkill(\n { id, skill, entry }: SelectedExternal,\n matrix: MergedSkillsMatrix,\n projectDir: string,\n): ExternalSkillInstall[] {\n const domain = getCategoryDomain(skill.categoryId);\n if (domain === undefined) return [];\n\n const install: ExternalSkillInstall = {\n id,\n skill,\n domain,\n scope: entry.scope,\n skillDir: externalSkillDir(id, entry.scope, projectDir),\n };\n\n matrix.skills[id] = externalCatalogueEntry(install);\n // Completes the map over the matrix: `getSkillBySlug` is an asserting lookup, so an entry the\n // slug map does not carry throws for anything that addresses a skill by slug.\n claimSlug(matrix.slugMap, externalSlug(id), id);\n\n return [install];\n}\n\n/**\n * Seats the catalogue entries a payload carries, and says where each one's bytes go.\n *\n * Every other id in a payload is resolved against a catalogue the receiver already has, so one it\n * does not know is skipped and reported. A carried skill answers to no catalogue at all — which is\n * why its whole directory travels — so it has to BECOME a catalogue entry before the decode reads\n * the selection, or it is skipped like any other unknown id and the configuration installs\n * quietly smaller than it was shared.\n *\n * The entries are written into `matrix` in place, exactly as the local-skill merge writes the\n * skills it discovers on disk. That matrix is the object `initializeMatrix` seated, which is what\n * {@link getCategoryDomain} reads — every caller passes the loaded source's own.\n *\n * @throws {Error} If any carried skill asks to be installed as a plugin — see\n * {@link pluginInstallError}.\n */\nexport function registerExternalSkills(\n payload: SeedPayload,\n matrix: MergedSkillsMatrix,\n projectDir: string,\n): ExternalSkillInstall[] {\n const externals = selectedExternals(payload);\n const asPlugin = askedForAsPlugin(externals);\n\n if (asPlugin.length > 0) throw new Error(pluginInstallError(asPlugin));\n\n return externals.flatMap((external) => seatExternalSkill(external, matrix, projectDir));\n}\n\n/**\n * Writes each carried skill's directory where its own entry said, and registers it on disk.\n *\n * Three things have to be true afterwards, and each is a separate act: the files are there, the\n * skill answers to the id the configuration recorded, and a metadata.yaml describes it well\n * enough for the next `edit`, `compile` or `list` to find it again. The seat above lasts one run;\n * this is what makes the install survive.\n */\nexport async function writeExternalSkills(installs: ExternalSkillInstall[]): Promise<void> {\n for (const install of installs) {\n await writeSkillTree(install);\n await writeSkillManifest(install);\n await registerSkillOnDisk(install);\n }\n}\n\n/**\n * The directory as the payload holds it, keys and all.\n *\n * The keys came off the wire, so a payload may ask for any path it likes — including one that\n * climbs out of the skill's own directory. They answer to the same guard a marketplace's own\n * paths do.\n */\nasync function writeSkillTree(install: ExternalSkillInstall): Promise<void> {\n for (const [relativePath, contents] of Object.entries(install.skill.files)) {\n const filePath = path.join(install.skillDir, relativePath);\n validateSkillPath(filePath, install.skillDir, relativePath);\n await writeFile(filePath, contents);\n }\n}\n\n/** The frontmatter block at the head of a SKILL.md, and the `name` field inside it. */\nconst FRONTMATTER_BLOCK = /^---\\r?\\n([\\s\\S]*?)\\r?\\n---/;\nconst NAME_FIELD = /^name:.*$/m;\n\n/**\n * Names the skill by the id it installs under.\n *\n * Every loader reads a skill's id off this one field, and a compiled sub-agent references the id\n * the configuration recorded — the one minted at intake, which is also this directory's name. The\n * repository the skill came from knew about neither, so left as it was written the two never\n * meet: the sub-agent names a skill Claude Code knows as something else, and the next load\n * registers an id no configuration carries.\n *\n * Only the name. Everything else in the block is the author's and travels untouched.\n */\nfunction withInstalledName(manifest: string, install: ExternalSkillInstall): string {\n const named = `name: ${install.id}`;\n const block = FRONTMATTER_BLOCK.exec(manifest);\n\n // A manifest with no frontmatter at all describes no skill to Claude Code either. The payload\n // carries both fields one needs, so it is given one rather than installed unreadable.\n if (!block) {\n return `---\\n${named}\\ndescription: ${install.skill.description}\\n---\\n\\n${manifest}`;\n }\n\n const [whole, fields = \"\"] = block;\n const renamed = NAME_FIELD.test(fields)\n ? fields.replace(NAME_FIELD, named)\n : `${named}\\n${fields}`;\n\n // The block is anchored at the head of the file, so what follows it is the rest verbatim.\n return `---\\n${renamed}\\n---${manifest.slice(whole.length)}`;\n}\n\nasync function writeSkillManifest(install: ExternalSkillInstall): Promise<void> {\n const manifestPath = path.join(install.skillDir, STANDARD_FILES.SKILL_MD);\n await writeFile(manifestPath, withInstalledName(await readFile(manifestPath), install));\n}\n\n/**\n * What the payload confirmed, over what the repository shipped, over what neither says.\n *\n * The order is the whole of it. The taxonomy is the placement the user chose against the\n * catalogue this configuration names, and the repository's own idea of where its skill belongs\n * answers to a taxonomy nobody here shares — so that is written over the file. Everything else\n * the repository wrote is kept, because its author knows more about their skill than a default\n * does.\n *\n * The defaults underneath exist because `doctor` validates every installed metadata.yaml, and a\n * file this command writes that that command reports as an error is the CLI disagreeing with\n * itself — in a file the user cannot fix, since the skill is somebody else's repository. Neither\n * is invented: the authorship is the repository's owner, and the usage line is the same words the\n * stack loader already writes for every skill reference it has nothing more specific for.\n */\nfunction externalSkillMetadata(\n install: ExternalSkillInstall,\n shipped: LocalSkillMetadata | null,\n): LocalSkillMetadata {\n return {\n author: skillAuthor(install.skill.repo),\n usageGuidance: `Use when working with ${install.skill.displayName}`,\n ...shipped,\n displayName: install.skill.displayName,\n slug: install.id,\n category: install.skill.categoryId,\n domain: install.domain,\n cliDescription: install.skill.description,\n custom: true,\n };\n}\n\n/**\n * Registers the skill on disk, where the next command will look for it.\n *\n * `forkedFrom` is stamped through the one writer that stamps it, because it is the package's\n * single answer to \"did the CLI put this directory here?\" — `uninstall` reads it to decide what it\n * may delete, and the producer reads it to decide what the round trip owns. A carried skill IS the\n * round trip's; a skill the user wrote by hand is not, and carries nothing.\n *\n * The repository AND the directory inside it, because this is the only record of where these bytes\n * came from. Sharing this installation has to rebuild the entry the payload carried, and a\n * repository alone cannot say which of its directories travelled — see {@link readCarriedSkills}.\n */\nasync function registerSkillOnDisk(install: ExternalSkillInstall): Promise<void> {\n const metadataPath = path.join(install.skillDir, STANDARD_FILES.METADATA_YAML);\n const shipped = await readLocalSkillMetadata(install.skillDir);\n\n await writeMetadataYaml(metadataPath, externalSkillMetadata(install, shipped));\n await injectForkedFromMetadata(\n install.skillDir,\n install.id,\n await computeFileHash(path.join(install.skillDir, STANDARD_FILES.SKILL_MD)),\n { source: repoRef(install.skill.repo), path: install.skill.path },\n );\n}\n\n/**\n * One installed skill directory the round trip owns, and what its install recorded about it.\n *\n * Read by the caller rather than here: whether a directory is the CLI's copy or the user's own\n * work is a question about ownership, which `installation-payload.ts` already asks of every entry\n * before anything else. This module answers only the next one — whether the bytes have to travel.\n */\nexport type OwnedSkillDir = { id: string; skillDir: string; provenance: ForkedFromMetadata };\n\n/**\n * What one installation carries rather than names.\n *\n * The same shape the mapper's other readings wear: what can travel, and the lines naming what\n * cannot. Both halves matter — a payload quietly missing content it could not read still mints an\n * id, and that id installs a configuration nobody chose.\n */\nexport type ContentReading = {\n /** Skill id -> the entry a receiver seats it from. Keyed exactly as the wire keys `external`. */\n external: Record<string, SeedExternalSkill>;\n /** One line per skill whose content this installation cannot carry, for the refusal. */\n uncarryable: string[];\n};\n\n/** What one owned directory turns out to carry: content, a reason it cannot, or nothing. */\ntype CarriedRead =\n | { carries: \"content\"; id: string; skill: SeedExternalSkill }\n | { carries: \"nothing\" }\n | { carries: \"unshareable\"; line: string };\n\nfunction unnameableRepoMessage(id: string): string {\n return `${id} travels inside a shared configuration, and this installation does not record the repository its content came from`;\n}\n\nfunction uncarryableContentMessage(id: string, reason: string): string {\n return `${id} travels inside a shared configuration, and ${reason}`;\n}\n\n/**\n * The inverse of {@link repoRef}: the repository a ref names, or nothing when it names none this\n * contract can state.\n *\n * Provenance is written as a ref because that is the form every other source in a configuration\n * wears; the wire wants GitHub's own `owner/name`. Any other ref is a repository this contract has\n * no word for, which is a refusal rather than something to guess at.\n */\nfunction repoFromRef(ref: string | undefined): string | undefined {\n if (ref === undefined || !ref.startsWith(GITHUB_SOURCE.GITHUB_PREFIX)) return undefined;\n return ref.slice(GITHUB_SOURCE.GITHUB_PREFIX.length);\n}\n\n/** Every file under the skill, keyed by its path relative to it — dotfiles and nesting included. */\nasync function readSkillTree(skillDir: string): Promise<SeedSkillTree> {\n const files = await glob(\"**/*\", skillDir, { dot: true });\n const entries = await Promise.all(\n files.map(async (file) => [file, await readFile(path.join(skillDir, file))] as const),\n );\n return Object.fromEntries(entries);\n}\n\n/**\n * Rebuilds the entry a carried skill arrived as, from the directory the install wrote.\n *\n * The bytes as they stand rather than as they arrived: the manifest was renamed to the id this\n * install recorded, and a user may have edited the skill since. Both are what is installed here,\n * and what is installed here is what a share carries.\n *\n * Validated against the contract's own schema rather than by rules restated here — that is what\n * makes the weight limit, the manifest requirement and every field's shape one definition rather\n * than two that can drift.\n */\nasync function readCarriedSkill({ id, skillDir, provenance }: OwnedSkillDir): Promise<CarriedRead> {\n // The directory is what marks a skill as one no catalogue can resolve. Without it there is a\n // catalogue behind this id, so the receiver installs it from there and the bytes stay home.\n if (provenance.path === undefined) return { carries: \"nothing\" };\n\n const repo = repoFromRef(provenance.source);\n if (repo === undefined) return { carries: \"unshareable\", line: unnameableRepoMessage(id) };\n\n const described = await readSkillMetadata(path.join(skillDir, STANDARD_FILES.METADATA_YAML));\n if (!described.usable) {\n return { carries: \"unshareable\", line: uncarryableContentMessage(id, described.reason) };\n }\n\n const parsed = seedExternalSkillSchema.safeParse({\n displayName: described.metadata.displayName,\n description: described.metadata.cliDescription,\n categoryId: described.metadata.category,\n repo,\n path: provenance.path,\n files: await readSkillTree(skillDir),\n });\n if (!parsed.success) {\n const reason = parsed.error.issues.map((issue) => issue.message).join(\"; \");\n return { carries: \"unshareable\", line: uncarryableContentMessage(id, reason) };\n }\n\n return { carries: \"content\", id, skill: parsed.data };\n}\n\n/**\n * What a set of owned skill directories carries, and what it cannot.\n *\n * The mirror of {@link registerExternalSkills}: that seats an entry a payload carried and writes\n * its bytes, this reads those bytes back into the entry a payload carries. Every other id in a\n * configuration is resolved by the receiver against a catalogue it already has, so its content has\n * nothing to add; an added skill answers to no catalogue in either direction, and a share that\n * named it without carrying it would mint an id that installs a configuration missing it.\n */\nexport async function readCarriedSkills(owned: OwnedSkillDir[]): Promise<ContentReading> {\n const reads = await Promise.all(owned.map(readCarriedSkill));\n\n return {\n external: Object.fromEntries(\n reads.flatMap((read) => (read.carries === \"content\" ? [[read.id, read.skill]] : [])),\n ),\n uncarryable: reads.flatMap((read) => (read.carries === \"unshareable\" ? [read.line] : [])),\n };\n}\n","import { seedPayloadSchema, type SeedPayload } from \"@workspace/matrix/seed\";\n\n/** The config store behind agentsinc.sh. Overridable so tests never touch the network. */\nexport const SEED_API_URL = process.env.AGENTS_INC_API_URL ?? \"https://api.agentsinc.sh\";\n\n/**\n * Identifies this fetch as the CLI rather than a browser.\n *\n * `GET /configs/:id` is the only place either side can observe a config being *installed* rather\n * than merely built, and the worker can only separate that from someone opening a share link if\n * we say so. Without this the conversion signal does not exist.\n */\nexport const SEED_USER_AGENT = \"agents-inc-cli\";\n\nexport type FetchSeedResult = { ok: true; payload: SeedPayload } | { ok: false; error: string };\n\n/**\n * Fetches and validates a shared configuration.\n *\n * Every failure is a message rather than a throw: this runs before anything has been written, so\n * there is nothing to roll back and the caller's job is to explain rather than recover.\n */\nexport async function fetchSeedConfig(id: string): Promise<FetchSeedResult> {\n const url = `${SEED_API_URL}/configs/${encodeURIComponent(id)}`;\n\n let response: Response;\n try {\n response = await fetch(url, {\n headers: { accept: \"application/json\", \"user-agent\": SEED_USER_AGENT },\n });\n } catch {\n return { ok: false, error: `Could not reach ${SEED_API_URL} — check your connection.` };\n }\n\n if (response.status === 404) {\n return { ok: false, error: `No configuration found for id '${id}'.` };\n }\n if (!response.ok) {\n return { ok: false, error: `Fetching configuration failed (HTTP ${response.status}).` };\n }\n\n let body: unknown;\n try {\n body = await response.json();\n } catch {\n return { ok: false, error: \"The configuration store returned something that is not JSON.\" };\n }\n\n const parsed = seedPayloadSchema.safeParse(body);\n if (!parsed.success) {\n // Names the remedy rather than a cause it cannot observe. The payload was validated by the\n // store on the way IN, so a stored payload that no longer parses means the contract moved\n // underneath it — and every way that happens lands in this one `safeParse`: an id minted\n // before a version bump, an id minted after one, and a body that is simply broken. The CLI\n // cannot tell them apart, and the one thing true of all three is that re-sharing fixes it,\n // because the store content-addresses an id and a fresh share mints one under this version.\n return {\n ok: false,\n error: `Configuration '${id}' is not in a format this version of the CLI can install. Shared ids are never migrated — re-share the configuration to mint a current one, or update the CLI if that id came from a newer version.`,\n };\n }\n\n return { ok: true, payload: parsed.data };\n}\n"],"mappings":"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","names":[]}
@@ -7,20 +7,20 @@ import {
7
7
  } from "./chunk-XVAQG2CV.js";
8
8
  import {
9
9
  useRowScroll
10
- } from "./chunk-V3ENMW7G.js";
10
+ } from "./chunk-WFRTHH3A.js";
11
11
  import {
12
12
  useWizardStore
13
- } from "./chunk-QQTYMW7N.js";
13
+ } from "./chunk-F5T6TV4Z.js";
14
14
  import {
15
15
  matrix
16
- } from "./chunk-IPJOMAWC.js";
16
+ } from "./chunk-RWOYPOMR.js";
17
17
  import {
18
18
  typedKeys
19
19
  } from "./chunk-VASLW636.js";
20
20
  import {
21
21
  CLI_COLORS,
22
22
  UI_SYMBOLS
23
- } from "./chunk-R54KIGN2.js";
23
+ } from "./chunk-IO5YBKHV.js";
24
24
 
25
25
  // src/cli/components/wizard/stack-selection.tsx
26
26
  import { groupBy } from "remeda";
@@ -195,4 +195,4 @@ var StackSelection = ({ onCancel }) => {
195
195
  export {
196
196
  StackSelection
197
197
  };
198
- //# sourceMappingURL=chunk-2IMYK4WN.js.map
198
+ //# sourceMappingURL=chunk-PNMM5HNX.js.map
@@ -1,20 +1,20 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  getDomainDisplayName
4
- } from "./chunk-CHNA5RVS.js";
4
+ } from "./chunk-5OKLCVM4.js";
5
5
  import {
6
6
  CheckboxGrid
7
- } from "./chunk-ONWEOS77.js";
7
+ } from "./chunk-SY4X2LND.js";
8
8
  import {
9
9
  orderDomains,
10
10
  useWizardStore
11
- } from "./chunk-QQTYMW7N.js";
11
+ } from "./chunk-F5T6TV4Z.js";
12
12
  import {
13
13
  DOMAIN_DESCRIPTIONS
14
- } from "./chunk-CBF4ZYV3.js";
14
+ } from "./chunk-WCAUUBHO.js";
15
15
  import {
16
16
  matrix
17
- } from "./chunk-IPJOMAWC.js";
17
+ } from "./chunk-RWOYPOMR.js";
18
18
  import {
19
19
  typedEntries
20
20
  } from "./chunk-VASLW636.js";
@@ -58,4 +58,4 @@ var DomainSelection = () => {
58
58
  export {
59
59
  DomainSelection
60
60
  };
61
- //# sourceMappingURL=chunk-AKQ5QISO.js.map
61
+ //# sourceMappingURL=chunk-QWVXOCXO.js.map
@@ -1,5 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
+ typedKeys,
3
4
  typedValues
4
5
  } from "./chunk-VASLW636.js";
5
6
 
@@ -9674,6 +9675,14 @@ function hasSkill(id) {
9674
9675
  function findStack(stackId) {
9675
9676
  return matrix.suggestedStacks.find((s) => s.id === stackId);
9676
9677
  }
9678
+ function byCategoryDeclarationOrder() {
9679
+ const declarationRank = new Map(
9680
+ typedKeys(matrix.categories).map((category, rank) => [category, rank])
9681
+ );
9682
+ const afterEveryDeclared = declarationRank.size;
9683
+ const rankOf = (category) => declarationRank.get(category) ?? afterEveryDeclared;
9684
+ return (a, b) => rankOf(a) - rankOf(b);
9685
+ }
9677
9686
 
9678
9687
  export {
9679
9688
  BUILT_IN_MATRIX,
@@ -9684,6 +9693,7 @@ export {
9684
9693
  allSkills,
9685
9694
  getCategoryDomain,
9686
9695
  hasSkill,
9687
- findStack
9696
+ findStack,
9697
+ byCategoryDeclarationOrder
9688
9698
  };
9689
- //# sourceMappingURL=chunk-IPJOMAWC.js.map
9699
+ //# sourceMappingURL=chunk-RWOYPOMR.js.map