agents-inc 0.164.0 → 0.166.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 (191) hide show
  1. package/CHANGELOG.md +63 -0
  2. package/README.md +8 -9
  3. package/dist/{chunk-X4SSJZLY.js → chunk-25MPBIK3.js} +12 -261
  4. package/dist/chunk-25MPBIK3.js.map +1 -0
  5. package/dist/{chunk-LT5GXEB2.js → chunk-2VUYFTUB.js} +8 -7
  6. package/dist/chunk-2VUYFTUB.js.map +1 -0
  7. package/dist/chunk-4AAOOAIN.js +49 -0
  8. package/dist/chunk-4AAOOAIN.js.map +1 -0
  9. package/dist/{chunk-ARYNOWKF.js → chunk-4NDBUJHK.js} +8 -8
  10. package/dist/{chunk-S63LXWMC.js → chunk-6L75SQZU.js} +2 -2
  11. package/dist/{chunk-7REKOTKG.js → chunk-6LF4CQBY.js} +3 -3
  12. package/dist/{chunk-K5ITEA3I.js → chunk-7JNJ52CD.js} +34 -17
  13. package/dist/chunk-7JNJ52CD.js.map +1 -0
  14. package/dist/{chunk-XPDVAJDH.js → chunk-A4KDXNOT.js} +3519 -1568
  15. package/dist/chunk-A4KDXNOT.js.map +1 -0
  16. package/dist/{chunk-XHPWTL4I.js → chunk-DAIEQJIF.js} +3 -3
  17. package/dist/{chunk-UITEKY2R.js → chunk-ENGYJCTF.js} +28 -4
  18. package/dist/chunk-ENGYJCTF.js.map +1 -0
  19. package/dist/{chunk-G2JJ5BO5.js → chunk-G4JK7WVO.js} +336 -140
  20. package/dist/chunk-G4JK7WVO.js.map +1 -0
  21. package/dist/{chunk-X37UYIE3.js → chunk-G6UREQ4V.js} +436 -739
  22. package/dist/chunk-G6UREQ4V.js.map +1 -0
  23. package/dist/chunk-GE3WKJ6Q.js +375 -0
  24. package/dist/chunk-GE3WKJ6Q.js.map +1 -0
  25. package/dist/{chunk-RGYDFBCT.js → chunk-HHIYT3PI.js} +5 -5
  26. package/dist/{chunk-2CQNPLVF.js → chunk-HWEKHVLE.js} +63 -42
  27. package/dist/chunk-HWEKHVLE.js.map +1 -0
  28. package/dist/{chunk-XVAQG2CV.js → chunk-JOEA52NR.js} +10 -8
  29. package/dist/chunk-JOEA52NR.js.map +1 -0
  30. package/dist/{chunk-3WVH2CTK.js → chunk-JQRJQ4SS.js} +15 -8
  31. package/dist/chunk-JQRJQ4SS.js.map +1 -0
  32. package/dist/{chunk-DSL66I4N.js → chunk-LFWLEDUG.js} +6 -6
  33. package/dist/{chunk-B3Y3QMWI.js → chunk-MAWNVT2C.js} +4 -4
  34. package/dist/{chunk-Q4IRRVXK.js → chunk-MPTNC32T.js} +3 -3
  35. package/dist/chunk-NBXXFIIW.js +73 -0
  36. package/dist/chunk-NBXXFIIW.js.map +1 -0
  37. package/dist/{chunk-B6FSLXYN.js → chunk-PMJWD27C.js} +3 -3
  38. package/dist/{chunk-XATLUKXK.js → chunk-PNB3524H.js} +6 -6
  39. package/dist/chunk-PXWG7KFO.js +39 -0
  40. package/dist/chunk-PXWG7KFO.js.map +1 -0
  41. package/dist/{chunk-4VL3CEOS.js → chunk-QHDPLLK6.js} +3 -3
  42. package/dist/{chunk-AOTCIUGX.js → chunk-RAHSOJQ2.js} +2 -2
  43. package/dist/{chunk-PHCPUQVR.js → chunk-RZDXDMT6.js} +2 -2
  44. package/dist/{chunk-6MV4JOCL.js → chunk-SAYZWCH6.js} +2 -2
  45. package/dist/{chunk-URXIQE7I.js → chunk-SCOQ34YM.js} +2 -2
  46. package/dist/{chunk-NQXO4LR3.js → chunk-SXVHSOTH.js} +16 -11
  47. package/dist/chunk-SXVHSOTH.js.map +1 -0
  48. package/dist/{chunk-QZX7SYKU.js → chunk-T6UWJAB3.js} +2 -2
  49. package/dist/{chunk-ZVXGW2IC.js → chunk-TODCQFRB.js} +4 -6
  50. package/dist/chunk-TODCQFRB.js.map +1 -0
  51. package/dist/{chunk-YRS3QZP2.js → chunk-TTY6DPJN.js} +3 -3
  52. package/dist/{chunk-QGUP3QJF.js → chunk-TZ2YJJKK.js} +22 -18
  53. package/dist/{chunk-QGUP3QJF.js.map → chunk-TZ2YJJKK.js.map} +1 -1
  54. package/dist/chunk-V3I7VQ7N.js +356 -0
  55. package/dist/chunk-V3I7VQ7N.js.map +1 -0
  56. package/dist/{chunk-AVK2HEKB.js → chunk-V5WXIM2F.js} +2 -6
  57. package/dist/{chunk-AVK2HEKB.js.map → chunk-V5WXIM2F.js.map} +1 -1
  58. package/dist/{chunk-NKGYKOB7.js → chunk-VAPTVR3J.js} +7 -8
  59. package/dist/chunk-VAPTVR3J.js.map +1 -0
  60. package/dist/chunk-VRXX4D6K.js +31 -0
  61. package/dist/chunk-VRXX4D6K.js.map +1 -0
  62. package/dist/{chunk-ABAZMMG4.js → chunk-WVUDLKIO.js} +2 -2
  63. package/dist/{chunk-ECURHW3T.js → chunk-WWIFNPJG.js} +13 -12
  64. package/dist/chunk-WWIFNPJG.js.map +1 -0
  65. package/dist/{chunk-J27W6TXS.js → chunk-XQHZPINL.js} +8 -4
  66. package/dist/chunk-XQHZPINL.js.map +1 -0
  67. package/dist/{chunk-V5GLL2JB.js → chunk-XZEVWPX6.js} +7 -7
  68. package/dist/chunk-Y3VIRVVE.js +932 -0
  69. package/dist/chunk-Y3VIRVVE.js.map +1 -0
  70. package/dist/{chunk-NTF4UXGK.js → chunk-Y47EV74W.js} +73 -30
  71. package/dist/chunk-Y47EV74W.js.map +1 -0
  72. package/dist/chunk-ZR4YPKXQ.js +159 -0
  73. package/dist/chunk-ZR4YPKXQ.js.map +1 -0
  74. package/dist/chunk-ZXKBERQU.js +250 -0
  75. package/dist/chunk-ZXKBERQU.js.map +1 -0
  76. package/dist/commands/build/marketplace.js +17 -17
  77. package/dist/commands/build/marketplace.js.map +1 -1
  78. package/dist/commands/build/plugins.js +11 -9
  79. package/dist/commands/build/plugins.js.map +1 -1
  80. package/dist/commands/compile.js +105 -27
  81. package/dist/commands/compile.js.map +1 -1
  82. package/dist/commands/doctor.js +309 -171
  83. package/dist/commands/doctor.js.map +1 -1
  84. package/dist/commands/edit.js +503 -314
  85. package/dist/commands/edit.js.map +1 -1
  86. package/dist/commands/eject.js +40 -23
  87. package/dist/commands/eject.js.map +1 -1
  88. package/dist/commands/init.js +44 -40
  89. package/dist/commands/list.js +44 -10
  90. package/dist/commands/list.js.map +1 -1
  91. package/dist/commands/new/marketplace.js +13 -10
  92. package/dist/commands/new/marketplace.js.map +1 -1
  93. package/dist/commands/search.js +12 -10
  94. package/dist/commands/search.js.map +1 -1
  95. package/dist/commands/share.js +102 -15
  96. package/dist/commands/share.js.map +1 -1
  97. package/dist/commands/uninstall.js +231 -103
  98. package/dist/commands/uninstall.js.map +1 -1
  99. package/dist/commands/update.js +49 -20
  100. package/dist/commands/update.js.map +1 -1
  101. package/dist/components/common/prompt-confirm.js +1 -1
  102. package/dist/components/common/removal-plan-confirm.js +2 -2
  103. package/dist/components/common/select-list.js +3 -3
  104. package/dist/components/common/spinner.js +6 -3
  105. package/dist/components/wizard/category-grid.js +5 -5
  106. package/dist/components/wizard/checkbox-grid.js +4 -4
  107. package/dist/components/wizard/domain-selection.js +9 -9
  108. package/dist/components/wizard/run-wizard-session.js +29 -29
  109. package/dist/components/wizard/scroll-affordance.js +2 -2
  110. package/dist/components/wizard/skill-agent-summary.js +5 -5
  111. package/dist/components/wizard/source-grid.js +6 -6
  112. package/dist/components/wizard/stack-selection.js +8 -8
  113. package/dist/components/wizard/step-agents.js +8 -8
  114. package/dist/components/wizard/step-build.js +8 -8
  115. package/dist/components/wizard/step-confirm.js +9 -9
  116. package/dist/components/wizard/step-sources.js +9 -9
  117. package/dist/components/wizard/step-stack.js +9 -9
  118. package/dist/components/wizard/summary-panel.js +8 -8
  119. package/dist/components/wizard/toast.js +2 -2
  120. package/dist/components/wizard/wizard-layout.js +12 -12
  121. package/dist/components/wizard/wizard-tabs.js +2 -2
  122. package/dist/components/wizard/wizard.js +27 -27
  123. package/dist/hooks/init.js +69 -43
  124. package/dist/hooks/init.js.map +1 -1
  125. package/dist/load-agent-defs-3C27ENC7.js +14 -0
  126. package/dist/recompile-project-agents-DGNBCU3N.js +18 -0
  127. package/dist/{source-loader-GRBVNRAW.js → source-loader-7KZ3MD5O.js} +6 -4
  128. package/dist/src/agents/_templates/agent-body.liquid +55 -0
  129. package/dist/src/agents/_templates/agent.liquid +1 -55
  130. package/dist/src/agents/meta/agent-summoner/output.md +1 -1
  131. package/dist/src/agents/meta/agent-summoner/playbook.md +15 -7
  132. package/dist/stores/wizard-store.js +4 -4
  133. package/package.json +10 -9
  134. package/src/agents/_templates/agent-body.liquid +55 -0
  135. package/src/agents/_templates/agent.liquid +1 -55
  136. package/src/agents/meta/agent-summoner/output.md +1 -1
  137. package/src/agents/meta/agent-summoner/playbook.md +15 -7
  138. package/src/schemas/project-config.schema.json +1 -1
  139. package/src/schemas/project-source-config.schema.json +1 -1
  140. package/dist/chunk-2CQNPLVF.js.map +0 -1
  141. package/dist/chunk-3WVH2CTK.js.map +0 -1
  142. package/dist/chunk-7ANJQLPJ.js +0 -35
  143. package/dist/chunk-7ANJQLPJ.js.map +0 -1
  144. package/dist/chunk-ECURHW3T.js.map +0 -1
  145. package/dist/chunk-FLW25ORT.js +0 -130
  146. package/dist/chunk-FLW25ORT.js.map +0 -1
  147. package/dist/chunk-G2JJ5BO5.js.map +0 -1
  148. package/dist/chunk-J27W6TXS.js.map +0 -1
  149. package/dist/chunk-JCPANDNR.js +0 -35
  150. package/dist/chunk-JCPANDNR.js.map +0 -1
  151. package/dist/chunk-JIERYE6B.js +0 -480
  152. package/dist/chunk-JIERYE6B.js.map +0 -1
  153. package/dist/chunk-JU4ZGJ7A.js +0 -668
  154. package/dist/chunk-JU4ZGJ7A.js.map +0 -1
  155. package/dist/chunk-K5ITEA3I.js.map +0 -1
  156. package/dist/chunk-LT5GXEB2.js.map +0 -1
  157. package/dist/chunk-NKGYKOB7.js.map +0 -1
  158. package/dist/chunk-NQXO4LR3.js.map +0 -1
  159. package/dist/chunk-NTF4UXGK.js.map +0 -1
  160. package/dist/chunk-UITEKY2R.js.map +0 -1
  161. package/dist/chunk-X37UYIE3.js.map +0 -1
  162. package/dist/chunk-X4SSJZLY.js.map +0 -1
  163. package/dist/chunk-XPDVAJDH.js.map +0 -1
  164. package/dist/chunk-XVAQG2CV.js.map +0 -1
  165. package/dist/chunk-ZBPEFQ4G.js +0 -12
  166. package/dist/chunk-ZBPEFQ4G.js.map +0 -1
  167. package/dist/chunk-ZVXGW2IC.js.map +0 -1
  168. package/dist/load-agent-defs-7IM3GBEQ.js +0 -13
  169. package/dist/recompile-project-agents-VR4NLGOU.js +0 -17
  170. /package/dist/{chunk-ARYNOWKF.js.map → chunk-4NDBUJHK.js.map} +0 -0
  171. /package/dist/{chunk-S63LXWMC.js.map → chunk-6L75SQZU.js.map} +0 -0
  172. /package/dist/{chunk-7REKOTKG.js.map → chunk-6LF4CQBY.js.map} +0 -0
  173. /package/dist/{chunk-XHPWTL4I.js.map → chunk-DAIEQJIF.js.map} +0 -0
  174. /package/dist/{chunk-RGYDFBCT.js.map → chunk-HHIYT3PI.js.map} +0 -0
  175. /package/dist/{chunk-DSL66I4N.js.map → chunk-LFWLEDUG.js.map} +0 -0
  176. /package/dist/{chunk-B3Y3QMWI.js.map → chunk-MAWNVT2C.js.map} +0 -0
  177. /package/dist/{chunk-Q4IRRVXK.js.map → chunk-MPTNC32T.js.map} +0 -0
  178. /package/dist/{chunk-B6FSLXYN.js.map → chunk-PMJWD27C.js.map} +0 -0
  179. /package/dist/{chunk-XATLUKXK.js.map → chunk-PNB3524H.js.map} +0 -0
  180. /package/dist/{chunk-4VL3CEOS.js.map → chunk-QHDPLLK6.js.map} +0 -0
  181. /package/dist/{chunk-AOTCIUGX.js.map → chunk-RAHSOJQ2.js.map} +0 -0
  182. /package/dist/{chunk-PHCPUQVR.js.map → chunk-RZDXDMT6.js.map} +0 -0
  183. /package/dist/{chunk-6MV4JOCL.js.map → chunk-SAYZWCH6.js.map} +0 -0
  184. /package/dist/{chunk-URXIQE7I.js.map → chunk-SCOQ34YM.js.map} +0 -0
  185. /package/dist/{chunk-QZX7SYKU.js.map → chunk-T6UWJAB3.js.map} +0 -0
  186. /package/dist/{chunk-YRS3QZP2.js.map → chunk-TTY6DPJN.js.map} +0 -0
  187. /package/dist/{chunk-ABAZMMG4.js.map → chunk-WVUDLKIO.js.map} +0 -0
  188. /package/dist/{chunk-V5GLL2JB.js.map → chunk-XZEVWPX6.js.map} +0 -0
  189. /package/dist/{load-agent-defs-7IM3GBEQ.js.map → load-agent-defs-3C27ENC7.js.map} +0 -0
  190. /package/dist/{recompile-project-agents-VR4NLGOU.js.map → recompile-project-agents-DGNBCU3N.js.map} +0 -0
  191. /package/dist/{source-loader-GRBVNRAW.js.map → source-loader-7KZ3MD5O.js.map} +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/cli/lib/exit-codes.ts","../src/cli/lib/seed/external-skills.ts","../../compile/src/carried-skill.ts","../src/cli/base-command.ts","../src/cli/lib/operations/source/ensure-marketplace.ts","../src/cli/lib/operations/source/require-marketplace.ts"],"sourcesContent":["export const EXIT_CODES = {\n SUCCESS: 0,\n ERROR: 1,\n INVALID_ARGS: 2,\n NETWORK_ERROR: 3,\n CANCELLED: 4,\n /**\n * The command ran to the end and part of what it set out to do did not happen.\n *\n * Distinct from {@link EXIT_CODES.ERROR} because the two ask opposite things of whoever reads\n * them: an `ERROR` aborted, so nothing landed and the run can be repeated; this one landed and\n * the repeat is the wrong move — what is owed is the remedy the output names, per failure.\n * Collapsing it into `ERROR` would re-make the defect it exists to close one value along, and\n * a spec asserting `not.toBe(0)` cannot tell a refusal from a partial apply either.\n *\n * It is raised at the END of a command, never mid-flight: the work completes first, which is\n * the whole difference between this and `this.error`.\n */\n COMPLETED_WITH_FAILURES: 5,\n} as const;\n","import os from \"os\";\nimport path from \"path\";\nimport { mkdtemp } from \"fs/promises\";\n\nimport { isDeepEqual, omit } from \"remeda\";\nimport { seedExternalSkillSchema } from \"@workspace/matrix/seed\";\nimport {\n carriedSkillAuthor,\n carriedSkillMetadata,\n withInstalledName,\n} from \"@workspace/compile/carried-skill\";\n\nimport { GITHUB_SOURCE, LOCAL_SKILLS_PATH, STANDARD_FILES } from \"../../consts.js\";\nimport { resolveInstallPaths } from \"../installation/install-base-dir.js\";\nimport { parseFrontmatter, 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 readForkedFromMetadata,\n readLocalSkillMetadata,\n writeMetadataYaml,\n} from \"../skills/skill-metadata.js\";\nimport { defaultUsageGuidance } from \"../stacks/stacks-loader.js\";\nimport { BUILT_IN_MATRIX } from \"../../types/generated/matrix.js\";\nimport { computeFileHash } from \"../versioning.js\";\nimport { copy, directoryExists, glob, readFile, remove, writeFile } from \"../../utils/fs.js\";\nimport { typedEntries, typedKeys } 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 * Names every carried skill claiming an id a catalogue already owns, not just the first.\n *\n * A skill id is the directory the skill installs into, so a carried skill taking a catalogue id\n * writes its own bytes where that catalogue's own copy belongs, and the id every sub-agent\n * references afterwards resolves to whatever the payload shipped. Nothing later can tell the two\n * apart either: the local-skill merge inherits an incumbent's `displayName`, `slug` and `category`\n * on the next load, so the impostor renders under the catalogue's own name and placement.\n *\n * **The union of two catalogues, and each half answers what the other cannot.** The LOADED matrix\n * catches the same defect one marketplace along — an external id colliding with a loaded custom\n * marketplace's own ids, which the shipped set has never heard of. The SHIPPED catalogue is the\n * half no payload can move: `sharedConfigSourceFlags` in `commands/init.tsx` passes\n * `payload.marketplace` to the loader, so a payload naming a marketplace that does not ship the id\n * it impersonates meets no incumbent in the loaded matrix at all — which is exactly why\n * `refuseCatalogueCollisions` in `loading/source-loader.ts` reads {@link BUILT_IN_MATRIX} and says\n * so: nothing a source ships is unforgeable, so the consumer's own load has to ask the question\n * again of a set the source cannot choose.\n */\nfunction claimingACatalogueId(\n externals: SelectedExternal[],\n matrix: MergedSkillsMatrix,\n): SkillId[] {\n return externals.filter(({ id }) => heldByEitherCatalogue(id, matrix)).map(({ id }) => id);\n}\n\n/** Every skill id the shipped catalogue owns — the half of the incumbent set a payload cannot move. */\nconst CATALOGUE_SKILL_IDS: ReadonlySet<SkillId> = new Set(typedKeys(BUILT_IN_MATRIX.skills));\n\nfunction heldByEitherCatalogue(id: SkillId, matrix: MergedSkillsMatrix): boolean {\n return heldByLoadedCatalogue(matrix.skills[id]) || CATALOGUE_SKILL_IDS.has(id);\n}\n\n/**\n * Whether the LOADED matrix's entry for an id is one a payload has no right to write over.\n *\n * An incumbent this installation merged off its own disk is not a collision on this axis.\n * `edit --from` applies destructively over an existing install and hands this the source's matrix,\n * which has already had the local-skill merge run over it — so a carried skill a previous apply\n * wrote arrives back here seated and `local`, and refusing it would make a shared configuration\n * installable exactly once. The same carve-out {@link claimSlug} makes for a claim it already\n * holds, on the axis the merge already treats as override-able.\n *\n * `local` is all the matrix can say, and it says less than it looks like: the merge writes that\n * flag on EVERYTHING it finds, so a skill the user wrote by hand wears it too, and a directory\n * carrying no `metadata.yaml` at all never reaches the matrix to be asked. Which directories this\n * installation may actually be written over is therefore settled on disk rather than here — see\n * {@link refuseUncarriedDestinations}.\n */\nfunction heldByLoadedCatalogue(incumbent: ResolvedSkill | undefined): boolean {\n return incumbent !== undefined && incumbent.local !== true;\n}\n\n/**\n * Every colliding id at once, and the fix rather than only the fault.\n *\n * Not truncated, unlike the marketplace refusal's list in `loading/source-loader.ts`: that one\n * reports a whole repository's directory scan, where hundreds of ids can collide at once, while\n * these are the skills one sharer added by hand to one configuration. {@link pluginInstallError}\n * draws from the same set and names all of it, and two refusals over one set disagreeing about\n * that would be an inconsistency with nothing behind it.\n */\nfunction catalogueIdCollisionError(ids: SkillId[]): string {\n return [\n \"This configuration cannot be installed: these skills travel inside it under ids a \" +\n \"catalogue already owns:\",\n ...ids.map((id) => ` ${id}`),\n \"A skill id is the directory the skill installs into, so each would be written over the \" +\n \"catalogue's own copy of that skill. Re-share it with each skill above added again, which \" +\n \"mints an id — 'external-<category>-<name>' — that no catalogue owns.\",\n ].join(\"\\n\");\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 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: carriedSkillAuthor(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: an entry the slug map does not carry is invisible to\n // 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 * Both refusals are decided before anything is seated, because the seat writes into `matrix` in\n * place: a guard placed after it would stop the run having already replaced entries every later\n * read in this process resolves, and a guard that threw on the first collision it met would have\n * overwritten whatever it seated on the way there.\n *\n * The third refusal is not here. Whether a DIRECTORY may be written over is a question about the\n * disk rather than about the catalogue — see {@link refuseUncarriedDestinations}.\n *\n * @throws {Error} If any carried skill asks to be installed as a plugin — see\n * {@link pluginInstallError} — or claims an id either catalogue already owns, see\n * {@link catalogueIdCollisionError}.\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 const colliding = claimingACatalogueId(externals, matrix);\n\n if (asPlugin.length > 0) throw new Error(pluginInstallError(asPlugin));\n if (colliding.length > 0) throw new Error(catalogueIdCollisionError(colliding));\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 *\n * Its callers have already asked {@link refuseUncarriedDestinations}, before they listed the\n * install or asked about it; it is asked again here because the question was put to a person,\n * and a directory written while they read it is no less theirs.\n *\n * Answers with the ids whose directories now read differently: a re-applied skill whose bytes\n * changed is a change the configuration's own entries cannot show.\n *\n * @throws {Error} If any destination is a directory this installation did not receive inside a\n * shared configuration — see {@link refuseUncarriedDestinations}.\n */\nexport async function writeExternalSkills(installs: ExternalSkillInstall[]): Promise<SkillId[]> {\n await refuseUncarriedDestinations(installs);\n\n const written = await Promise.all(installs.map(writeExternalSkill));\n return changedIds(written);\n}\n\nconst SCRATCH_DIR_PREFIX = \"agents-inc-carried-\";\n\n/**\n * The carried skills whose installed copy {@link writeExternalSkills} would change, asked of a\n * scratch copy of each directory so nothing installed is touched.\n *\n * For a run that may not write them: from a project, a carried skill the global install already\n * holds stays as that install holds it, and a revision that does not arrive is named rather than\n * dropped in silence. The comparison is the write's own, so \"would change\" and \"changed\" are one\n * definition.\n */\nexport async function carriedSkillsThatDiffer(\n installs: ExternalSkillInstall[],\n): Promise<SkillId[]> {\n if (installs.length === 0) return [];\n\n const scratch = await mkdtemp(path.join(os.tmpdir(), SCRATCH_DIR_PREFIX));\n try {\n const written = await Promise.all(\n installs.map(async (install) => writeExternalSkill(await scratchCopyOf(install, scratch))),\n );\n return changedIds(written);\n } finally {\n await remove(scratch);\n }\n}\n\n/** The install, pointed at a copy of its directory under `scratch` — taken now, if there is one. */\nasync function scratchCopyOf(\n install: ExternalSkillInstall,\n scratch: string,\n): Promise<ExternalSkillInstall> {\n const skillDir = path.join(scratch, install.id);\n if (await directoryExists(install.skillDir)) await copy(install.skillDir, skillDir);\n return { ...install, skillDir };\n}\n\n/** One carried skill as written, and whether its directory now reads differently. */\ntype WrittenSkill = { id: SkillId; changed: boolean };\n\n/** The skills whose directories now read differently. */\nfunction changedIds(written: WrittenSkill[]): SkillId[] {\n return written.filter(({ changed }) => changed).map(({ id }) => id);\n}\n\nasync function writeExternalSkill(install: ExternalSkillInstall): Promise<WrittenSkill> {\n const before = await readSkillDir(install.skillDir);\n\n await writeSkillTree(install);\n await writeSkillManifest(install);\n await registerSkillOnDisk(install);\n\n return { id: install.id, changed: !isDeepEqual(before, await readSkillDir(install.skillDir)) };\n}\n\n/** A skill directory as a load reads it: its files, and its metadata as data. */\ntype SkillDirReading = { files: SeedSkillTree; metadata: Record<string, unknown> | null };\n\n/**\n * What a load reads out of one skill directory, or nothing where there is none — less the day\n * `forkedFrom` was stamped, which every write moves whether or not anything else did. The metadata\n * is read as data because the stamp's place in the file differs between a first write and a\n * second (see `withForkedFrom` in `@workspace/compile/carried-skill`).\n */\nasync function readSkillDir(skillDir: string): Promise<SkillDirReading | null> {\n if (!(await directoryExists(skillDir))) return null;\n\n const files = omit(await readSkillTree(skillDir), [STANDARD_FILES.METADATA_YAML]);\n return { files, metadata: undated(await readLocalSkillMetadata(skillDir)) };\n}\n\nfunction undated(metadata: LocalSkillMetadata | null): Record<string, unknown> | null {\n if (metadata?.forkedFrom === undefined) return metadata;\n return { ...metadata, forkedFrom: omit(metadata.forkedFrom, [\"date\"]) };\n}\n\n/** One destination a carried skill's bytes may not be written to, and what stands there. */\ntype BlockedDestination = { id: SkillId; skillDir: string };\n\n/**\n * Refuses the run when any destination already holds content no shared configuration carried.\n *\n * **This is the disk half of the collision question, and the matrix cannot answer it.**\n * {@link heldByLoadedCatalogue} carves out every `local` incumbent so a re-apply works, and the\n * local-skill merge writes `local` on everything it merges — so that carve-out also exempts a\n * skill the user wrote by hand and a marketplace skill ejected here, neither of which is the\n * round trip's to replace. Worse, a directory with no readable `metadata.yaml` never reaches the\n * matrix at all, so no in-memory guard, with or without a provenance field on `ResolvedSkill`,\n * could ever see it. The bytes are the subject, so the bytes are what is asked.\n *\n * `forkedFrom.path` is the discriminator, not `forkedFrom` itself: {@link registerSkillOnDisk} is\n * the only writer of that field — `copySkillTo` deliberately omits it, because a marketplace skill\n * is installed again by its id — and {@link readCarriedSkill} reads it for this exact question one\n * layer up. So a directory that names the repository directory its bytes came from is one a\n * shared configuration put here, and everything else is somebody else's.\n *\n * Every destination is judged before any is written, for the same reason the two refusals in\n * {@link registerExternalSkills} are decided before anything is seated: a guard that threw on the\n * first blocked destination it met would have overwritten whatever it wrote on the way there.\n *\n * Exported for the `--from` producers, which ask it before they list what they would install or\n * ask whether to: a refusal that came after the question would ask a person to confirm an\n * install that was never going to happen.\n */\nexport async function refuseUncarriedDestinations(installs: ExternalSkillInstall[]): Promise<void> {\n const judged = await Promise.all(installs.map(judgeDestination));\n const blocked = judged.filter((destination) => destination !== null);\n\n if (blocked.length > 0) throw new Error(uncarriedDestinationError(blocked));\n}\n\n/** One destination: the row a refusal would name, or nothing standing there to protect. */\nasync function judgeDestination(install: ExternalSkillInstall): Promise<BlockedDestination | null> {\n const { id, skillDir } = install;\n if (!(await directoryExists(skillDir))) return null;\n if ((await readForkedFromMetadata(skillDir))?.path !== undefined) return null;\n return { id, skillDir };\n}\n\n/**\n * Every blocked destination at once, with the directory beside the id.\n *\n * The path is what makes this actionable and is what the collision message above cannot say: the\n * fix is the RECEIVER's rather than the sharer's, because the directory is theirs — so the message\n * has to name a path they can move, and a user must be able to copy any line of it and `cd` into\n * it. Both ways out are offered, because only the user knows whose skill matters more.\n */\nfunction uncarriedDestinationError(blocked: BlockedDestination[]): string {\n return [\n \"This configuration cannot be installed: these skills travel inside it under ids this \" +\n \"installation already keeps a skill directory for, and no shared configuration put those \" +\n \"directories there:\",\n ...blocked.map(({ id, skillDir }) => ` ${id} -> ${skillDir}`),\n \"A skill id is the directory the skill installs into, so each would be written over a skill \" +\n \"written here by hand or ejected from a marketplace. Move or rename the directory above, \" +\n \"or re-share the configuration with each skill added again, which mints an id — \" +\n \"'external-<category>-<name>' — that nothing here holds.\",\n ].join(\"\\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\nasync function writeSkillManifest(install: ExternalSkillInstall): Promise<void> {\n const manifestPath = path.join(install.skillDir, STANDARD_FILES.SKILL_MD);\n await writeFile(\n manifestPath,\n withInstalledName(await readFile(manifestPath), {\n id: install.id,\n description: install.skill.description,\n }),\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(\n metadataPath,\n carriedSkillMetadata({\n id: install.id,\n skill: install.skill,\n domain: install.domain,\n usageGuidance: defaultUsageGuidance(install.skill.categoryId),\n shipped,\n }),\n );\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\nconst NO_MANIFEST_DESCRIPTION = `no description can be read from its ${STANDARD_FILES.SKILL_MD}`;\n\n/** The description the skill's own SKILL.md states, or null where none can be read from it. */\nfunction manifestDescription(files: SeedSkillTree, skillDir: string): string | null {\n const manifest = files[STANDARD_FILES.SKILL_MD];\n if (manifest === undefined) return null;\n\n const frontmatter = parseFrontmatter(manifest, path.join(skillDir, STANDARD_FILES.SKILL_MD));\n return frontmatter === null ? null : frontmatter.description;\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 * The description is the manifest's own. The `cliDescription` beside it is the wizard's label,\n * cut to the length `doctor` accepts, so a re-share sending it would shorten the skill once per\n * round trip.\n *\n * Validated against the contract's own schema rather than by rules restated here — that is what\n * makes the weight limit and every field's shape one definition rather 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 files = await readSkillTree(skillDir);\n const description = manifestDescription(files, skillDir);\n if (description === null) {\n return { carries: \"unshareable\", line: uncarryableContentMessage(id, NO_MANIFEST_DESCRIPTION) };\n }\n\n const parsed = seedExternalSkillSchema.safeParse({\n displayName: described.metadata.displayName,\n description,\n categoryId: described.metadata.category,\n repo,\n path: provenance.path,\n files,\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 { parse as parseYaml, stringify as stringifyYaml } from \"yaml\"\n\nimport { GITHUB_PREFIX, STANDARD_FILES } from \"./paths.js\"\n\nimport type { SeedExternalSkill, SeedSkillTree } from \"@workspace/matrix\"\n\n/**\n * WHAT AN INSTALL DOES TO A SKILL A CONFIGURATION CARRIES rather than names —\n * one added in the editor, whose whole directory travels inside the payload —\n * on its way to disk.\n *\n * The CLI's `seed/external-skills.ts` writes with {@link withInstalledName} and\n * {@link carriedSkillMetadata}. The editor's output preview draws the whole\n * directory with {@link installedSkillTree}, which composes those two with the\n * half the CLI keeps because it needs a disk — reading the shipped\n * `metadata.yaml` back, and stamping `forkedFrom` through\n * `injectForkedFromMetadata` — and the CLI's `external-skills.test.ts` holds\n * that composition against a real install, byte for byte.\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/** The id a carried skill installs under, and the sentence the payload describes it with. */\nexport type InstalledSkillIdentity = { id: string; description: string }\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 */\nexport function withInstalledName(\n manifest: string,\n { id, description }: InstalledSkillIdentity\n): string {\n const named = `name: ${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: ${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\n/** The repository's owner as a handle, which is all the authorship a carried skill records. */\nexport function carriedSkillAuthor(repo: string): string {\n const [owner = repo] = repo.split(\"/\")\n return `@${owner}`\n}\n\n/** Where a carried skill was placed, and what its `metadata.yaml` falls back to. */\nexport type CarriedSkillPlacement = {\n id: string\n skill: Pick<\n SeedExternalSkill,\n \"displayName\" | \"description\" | \"categoryId\" | \"repo\"\n >\n /** The domain the receiving catalogue files the skill's category under. */\n domain: string\n /**\n * The usage line a skill stating none is given — the caller's own call rather than a sentence\n * spelled here, because the CLI's stack loader owns that sentence (`defaultUsageGuidance`) and a\n * second spelling of it drifted once already.\n */\n usageGuidance: string\n /** The `metadata.yaml` the repository shipped beside the skill, as the CLI reads it back. */\n shipped: Readonly<Record<string, unknown>> | null\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 the install 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 one the\n * caller's stack loader gives every skill reference it has nothing more specific for. The label is\n * shortened to the length that command accepts for the same reason.\n */\nexport function carriedSkillMetadata({\n id,\n skill,\n domain,\n usageGuidance,\n shipped,\n}: CarriedSkillPlacement): Record<string, unknown> {\n return {\n author: carriedSkillAuthor(skill.repo),\n usageGuidance,\n ...shipped,\n displayName: skill.displayName,\n slug: id,\n category: skill.categoryId,\n domain,\n cliDescription: shortLabel(skill.description),\n custom: true,\n }\n}\n\n/**\n * `CLI_DESCRIPTION_MAX_LENGTH` in the CLI's `schemas.ts`: the longest `cliDescription` its `doctor`\n * accepts without a warning.\n */\nconst CLI_DESCRIPTION_MAX_LENGTH = 60\n\nconst ELLIPSIS = \"…\"\n\n/**\n * The description as the wizard's short label: whole where it fits the length `doctor` accepts,\n * otherwise cut at the last word that fits and marked as cut. A sub-agent is compiled from the\n * SKILL.md's own description, so nothing it reads is shortened.\n */\nfunction shortLabel(description: string): string {\n if (description.length <= CLI_DESCRIPTION_MAX_LENGTH) return description\n\n const room = description.slice(\n 0,\n CLI_DESCRIPTION_MAX_LENGTH - ELLIPSIS.length\n )\n return `${toLastWholeWord(room)}${ELLIPSIS}`\n}\n\n/** The text up to its last whole word — all of it, where it holds no break. */\nfunction toLastWholeWord(text: string): string {\n const lastBreak = text.lastIndexOf(\" \")\n return (lastBreak > 0 ? text.slice(0, lastBreak) : text).trimEnd()\n}\n\n/** One carried skill as {@link installedSkillTree} needs it: its whole directory, and the day. */\nexport type CarriedSkillInstall = Omit<\n CarriedSkillPlacement,\n \"shipped\" | \"skill\"\n> & {\n skill: SeedExternalSkill\n /** The day the install ran, which only the machine running it knows. */\n date: string\n}\n\n/**\n * The directory a carried skill's install leaves, keyed as the payload keys it.\n *\n * Every file the payload carries, with the SKILL.md renamed by {@link withInstalledName} and a\n * `metadata.yaml` written beside it — over the one the repository shipped, when it shipped one.\n */\nexport async function installedSkillTree(\n install: CarriedSkillInstall\n): Promise<SeedSkillTree> {\n const manifest = withInstalledName(manifestOf(install.skill.files), {\n id: install.id,\n description: install.skill.description,\n })\n\n return {\n ...install.skill.files,\n [STANDARD_FILES.SKILL_MD]: manifest,\n [STANDARD_FILES.METADATA_YAML]: await metadataYaml(install, manifest),\n }\n}\n\n/**\n * The line `injectForkedFromMetadata` writes above the file:\n * `yamlSchemaComment(SCHEMA_PATHS.metadata)` in the CLI's `consts.ts`.\n */\nconst METADATA_SCHEMA_COMMENT =\n \"# yaml-language-server: $schema=https://raw.githubusercontent.com/agents-inc/agents-inc/main/packages/cli/src/schemas/metadata.schema.json\"\n\n/** `YAML_FORMATTING.LINE_WIDTH_NONE`: the CLI folds no line of a metadata file. */\nconst NO_LINE_FOLDING = 0\n\n/**\n * `registerSkillOnDisk`'s two writes as the bytes they leave: the shared metadata, then the\n * provenance `injectForkedFromMetadata` stamps over it.\n */\nasync function metadataYaml(\n install: CarriedSkillInstall,\n manifest: string\n): Promise<string> {\n const metadata = carriedSkillMetadata({\n ...install,\n shipped: shippedMetadata(install.skill.files),\n })\n const stamp = await provenanceStamp(install, manifest)\n\n return asMetadataFile(withForkedFrom(metadata, stamp))\n}\n\n/**\n * What `injectForkedFromMetadata` records about where the bytes came from: the id they install\n * under, the hash of the manifest as installed, the day, and the repository directory — the only\n * address a carried skill has.\n */\nasync function provenanceStamp(\n install: CarriedSkillInstall,\n manifest: string\n): Promise<Record<string, string>> {\n return {\n skillId: install.id,\n contentHash: await contentHashOf(manifest),\n date: install.date,\n source: `${GITHUB_PREFIX}${install.skill.repo}`,\n path: install.skill.path,\n }\n}\n\n/** The bytes `writeMetadataYaml` leaves for a mapping, under the schema comment. */\nconst asMetadataFile = (metadata: Record<string, unknown>): string =>\n `${METADATA_SCHEMA_COMMENT}\\n${stringifyYaml(metadata, {\n lineWidth: NO_LINE_FOLDING,\n })}`\n\n/**\n * The stamp, where `injectForkedFromMetadata` puts it. It reads the file back through\n * `localSkillMetadataSchema` first, and that schema's one declared key comes out of a parse ahead\n * of every passed-through one: a repository that shipped its own `forkedFrom` has the stamp at the\n * top of the file, and one that did not has it last.\n */\nfunction withForkedFrom(\n metadata: Record<string, unknown>,\n forkedFrom: Record<string, string>\n): Record<string, unknown> {\n if (!Object.hasOwn(metadata, \"forkedFrom\")) return { ...metadata, forkedFrom }\n\n const { forkedFrom: _shipped, ...rest } = metadata\n return { forkedFrom, ...rest }\n}\n\n/**\n * The `metadata.yaml` the repository shipped, read the way `readLocalSkillMetadata` reads it: a\n * file no parser can read, one that is not a mapping, or one whose `forkedFrom` block\n * `localSkillMetadataSchema` refuses, is no metadata at all.\n */\nfunction shippedMetadata(files: SeedSkillTree): Record<string, unknown> | null {\n const shipped = files[STANDARD_FILES.METADATA_YAML]\n if (shipped === undefined) return null\n\n const parsed = parsedYaml(shipped)\n return isMapping(parsed) && hasReadableProvenance(parsed) ? parsed : null\n}\n\nfunction parsedYaml(text: string): unknown {\n try {\n return parseYaml(text)\n } catch {\n // The CLI warns and reads no metadata; there is nobody here to warn.\n return undefined\n }\n}\n\nconst isMapping = (value: unknown): value is Record<string, unknown> =>\n typeof value === \"object\" && value !== null && !Array.isArray(value)\n\n/** The `forkedFrom` fields `localSkillMetadataSchema` requires, and the ones it allows. */\nconst PROVENANCE_REQUIRED = [\"skillId\", \"contentHash\", \"date\"] as const\nconst PROVENANCE_OPTIONAL = [\"source\", \"path\"] as const\n\n/** No `forkedFrom` at all, or one whose every field is a string the schema names. */\nfunction hasReadableProvenance(metadata: Record<string, unknown>): boolean {\n if (!Object.hasOwn(metadata, \"forkedFrom\")) return true\n\n const provenance = metadata.forkedFrom\n return (\n isMapping(provenance) &&\n PROVENANCE_REQUIRED.every((key) => typeof provenance[key] === \"string\") &&\n PROVENANCE_OPTIONAL.every(\n (key) =>\n !Object.hasOwn(provenance, key) || typeof provenance[key] === \"string\"\n )\n )\n}\n\n/** The `SKILL.md` a carried skill's directory holds, which the seed contract refuses one without. */\nfunction manifestOf(files: SeedSkillTree): string {\n const manifest = files[STANDARD_FILES.SKILL_MD]\n if (manifest === undefined) {\n throw new Error(\n `A carried skill's directory holds no ${STANDARD_FILES.SKILL_MD}, which seedSkillTreeSchema refuses`\n )\n }\n return manifest\n}\n\n/** `HASH_PREFIX_LENGTH`: how much of the digest the CLI's `computeStringHash` keeps. */\nconst CONTENT_HASH_LENGTH = 7\n\n/**\n * `computeStringHash` over the installed SKILL.md, which is what `computeFileHash` reads back — the\n * leading hex digits of its SHA-256. Web Crypto rather than `node:crypto`, because this package\n * runs in a browser.\n */\nasync function contentHashOf(text: string): Promise<string> {\n const digest = await crypto.subtle.digest(\n \"SHA-256\",\n new TextEncoder().encode(text)\n )\n return hexOf(new Uint8Array(digest)).slice(0, CONTENT_HASH_LENGTH)\n}\n\nconst hexOf = (bytes: Uint8Array): string =>\n Array.from(bytes, (byte) => byte.toString(16).padStart(2, \"0\")).join(\"\")\n","import { Command } from \"@oclif/core\";\n\nimport chalk from \"chalk\";\nimport { unique } from \"remeda\";\n\nimport { CLI_COLORS, DEFAULT_BRANDING, MIN_TERMINAL_SIZE } from \"./consts.js\";\nimport { getErrorMessage } from \"./utils/errors.js\";\nimport { verbose } from \"./utils/logger.js\";\nimport {\n completedWithFailures,\n installationConfigsUnreadable,\n type IncompleteWork,\n pluginsInstalled,\n propagatedRecompileSummary,\n registeredProjectConfigUnreadable,\n registeredProjectGone,\n registeredProjectOnAnotherProvider,\n savedSkillMetadataUnusableError,\n scopeBlockedStackAssignment,\n sharedConfigProjectScopeAtHome,\n skillAssignedToNoAgent,\n skillMetadataUnusableDetail,\n STATUS_MESSAGES,\n} from \"./utils/messages.js\";\nimport {\n clearTerminalScreen,\n formatTerminalTooSmallMessage,\n isTerminalLargeEnough,\n} from \"./utils/terminal.js\";\nimport { EXIT_CODES } from \"./lib/exit-codes.js\";\nimport { isActiveAt } from \"./lib/configuration/scope-predicates.js\";\nimport { resolveBranding } from \"./lib/configuration/config.js\";\nimport { isHomeDirectory, refuseUnofferedStack } from \"./lib/installation/index.js\";\nimport type { WizardResultV2 } from \"./components/wizard/wizard.js\";\nimport { getStackSkillIds } from \"./lib/stacks/index.js\";\nimport type {\n AgentName,\n MergedSkillsMatrix,\n ProjectConfig,\n SelectionValidation,\n SkillConfig,\n SkillId,\n} from \"./types/index.js\";\nimport { findConfigLoadFailures } from \"./lib/configuration/project-config.js\";\nimport { findUnusableSavedSkillMetadata } from \"./lib/skills/index.js\";\nimport type { PluginHost } from \"./lib/hosts/plugin-host.js\";\nimport { hostAt } from \"./lib/hosts/host-for.js\";\nimport { refuseUnofferedPlacements } from \"./lib/hosts/offered-placements.js\";\nimport {\n refuseUncarriedDestinations,\n type ExternalSkillInstall,\n} from \"./lib/seed/external-skills.js\";\nimport { refuseUnwritableStack } from \"@workspace/compile/config-source\";\nimport { requireMarketplace } from \"./lib/operations/source/require-marketplace.js\";\nimport {\n installPluginSkills,\n pluginInstallFailureError,\n unbackedPluginInstallError,\n unbackedPluginSkillIds,\n type PluginInstallResult,\n} from \"./lib/operations/skills/install-plugin-skills.js\";\nimport type { GateReport } from \"./lib/config-gate/index.js\";\nimport type { SourceLoadResult } from \"./lib/loading/source-loader.js\";\n\n/**\n * How often the size gate re-reads the terminal while it is blocked. `resize` is what normally\n * ends the wait; the poll is the belt for the terminals and multiplexers that resize without\n * ever emitting one, and it is the only reason a blocked command is not a hung one there.\n */\nconst TERMINAL_RESIZE_POLL_MS = 500;\n\n// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- @types/node declares this as `number`; it is undefined whenever stdout is not a TTY\nconst terminalColumns = (): number => process.stdout.columns ?? MIN_TERMINAL_SIZE.COLS;\n\n// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- @types/node declares this as `number`; it is undefined whenever stdout is not a TTY\nconst terminalRows = (): number => process.stdout.rows ?? MIN_TERMINAL_SIZE.ROWS;\n\nfunction isTerminalBigEnough(): boolean {\n return isTerminalLargeEnough(terminalColumns(), terminalRows());\n}\n\n/**\n * Resolves the moment the terminal satisfies `isSatisfied` — on the resize event where there is\n * one, on the poll where there is not. Both listeners are torn down before resolving, so a\n * command that got past the gate leaves nothing behind holding the process open.\n */\nfunction waitForTerminal(isSatisfied: () => boolean): Promise<void> {\n return new Promise<void>((resolve) => {\n const check = () => {\n if (!isSatisfied()) return;\n clearInterval(interval);\n process.stdout.off(\"resize\", check);\n resolve();\n };\n const interval = setInterval(check, TERMINAL_RESIZE_POLL_MS);\n process.stdout.on(\"resize\", check);\n });\n}\n\n/** A selected skill no sub-agent's stack carries, and the sub-agents the scope rule blocked. */\ntype UnassignedSkill = { skillId: SkillId; blockedBy: AgentName[] };\n\n/**\n * Every active skill this save selected that no agent's stack in the saved config references,\n * paired with the global-scoped sub-agents that could not have carried it.\n *\n * Only the selection is judged. A project's saved config also lists the global skills it\n * inherits, while the stack a shared configuration brings names only the sub-agents it carries —\n * a global sub-agent's rows stay in the global config — so an inherited skill is missing from\n * this stack without being unassigned.\n *\n * `blockedBy` is empty for a global-scoped skill: the scope rule had no say there, and the\n * skill reached nothing for a different reason (no selected sub-agent the resolver\n * considers it relevant to). Naming sub-agents there would blame the wrong rule.\n */\nfunction findUnassignedSkills(\n config: ProjectConfig,\n selected: readonly SkillConfig[],\n): UnassignedSkill[] {\n const assignedIds = new Set(config.stack ? getStackSkillIds(config.stack) : []);\n const selectedIds = new Set(selected.map((skill) => skill.id));\n const globalAgentNames = config.agents\n .filter((agent) => isActiveAt(agent, \"global\"))\n .map((agent) => agent.name);\n\n const unassignedIds = unique(\n config.skills\n .filter((skill) => !skill.excluded && selectedIds.has(skill.id))\n .map((skill) => skill.id)\n .filter((skillId) => !assignedIds.has(skillId)),\n );\n\n return unassignedIds.map((skillId) => ({\n skillId,\n blockedBy: hasActiveProjectEntry(config.skills, skillId) ? globalAgentNames : [],\n }));\n}\n\n/** True when an ACTIVE entry for this id sits at project scope — the only case the rule explains. */\nfunction hasActiveProjectEntry(skills: readonly SkillConfig[], skillId: SkillId): boolean {\n return skills.some((skill) => skill.id === skillId && isActiveAt(skill, \"project\"));\n}\n\n/**\n * What a decoded selection would file at PROJECT scope, split by kind because a skill's scope\n * and a sub-agent's are independent decisions in a payload — a refusal naming only one kind\n * would send the sharer to change the wrong entry.\n */\nfunction projectScopedContent(result: WizardResultV2): {\n skillIds: SkillId[];\n agentNames: AgentName[];\n} {\n return {\n skillIds: result.skills\n .filter((skill) => isActiveAt(skill, \"project\"))\n .map((skill) => skill.id),\n agentNames: result.agentConfigs\n .filter((agent) => isActiveAt(agent, \"project\"))\n .map((agent) => agent.name),\n };\n}\n\n/**\n * Nothing is inherited by every command, so this class declares no `baseFlags`.\n *\n * There was one — the marketplace flag — until naming a marketplace became `init`'s\n * decision alone (owner ruling 2026-08-09). Six commands were already opting out of it\n * through an exported empty-object cast; a flag one command wants is that command's flag,\n * so it is declared in `init` as `--marketplace` and the six opt-outs went with it.\n */\nexport abstract class BaseCommand extends Command {\n /**\n * Everything this run set out to do and did not, in the order it hit them.\n *\n * Non-empty is the whole of the exit-code decision — see {@link exitIfWorkIncomplete}. It is\n * deliberately not a boolean: a non-zero exit whose output does not say what failed and what\n * finishes it is worse than the silent success it replaces.\n *\n * Private, with {@link hasIncompleteWork} the only reading a subclass gets. A command records\n * through the two methods below and asks whether anything is owed; the list itself is this\n * class's, because it is this class that answers for it.\n */\n private readonly incompleteWork: IncompleteWork[] = [];\n\n async init(): Promise<void> {\n await super.init();\n await this.ensureTerminalSize();\n }\n\n /**\n * Blocks the command from launching in a terminal below\n * {@link MIN_TERMINAL_SIZE}. This runs once, before Ink mounts; the terminal\n * shrinking mid-session is caught by the matching guard in `WizardLayout`.\n */\n protected async ensureTerminalSize(): Promise<void> {\n if (isTerminalBigEnough()) return;\n\n this.clearTerminal();\n this.log(chalk.hex(CLI_COLORS.WARNING)(formatTerminalTooSmallMessage(terminalColumns())));\n\n await waitForTerminal(isTerminalBigEnough);\n }\n\n protected handleError(error: unknown): never {\n const message = getErrorMessage(error);\n this.error(message, { exit: EXIT_CODES.ERROR });\n }\n\n /**\n * The name this run prints itself under: `branding.name` where a config supplies one, and\n * {@link DEFAULT_BRANDING.NAME} everywhere else.\n *\n * **DEGRADE is the posture, and it is chosen here for every command that prints a name.**\n * `loadSourceConfig` raises for a config that exists and cannot be evaluated, and two of the\n * four callers must survive precisely that state: `doctor`'s whole job is naming it, and\n * `uninstall` is the only way out of it. A heading is decoration — nothing about a display name\n * is worth refusing a command over, and refusing here would turn the branding wiring into a new\n * way for an unreadable config to abort two commands that survive it today. `init` and `eject`\n * cannot reach the catch at all: {@link ensureConfigReadable} has already refused every config\n * they would read.\n *\n * The cause is not swallowed: it goes to `verbose`, and the command's own config reader reports\n * it in full where the user needs to act on it. Reporting it twice would put a warning about\n * the configuration above a heading, which is the one line that has to be the first thing on\n * screen.\n */\n protected async resolveBrandingName(projectDir: string): Promise<string> {\n try {\n const branding = await resolveBranding(projectDir);\n return branding.name;\n } catch (error) {\n verbose(`Could not read branding from the config: ${getErrorMessage(error)}`);\n return DEFAULT_BRANDING.NAME;\n }\n }\n\n protected logSuccess(message: string): void {\n this.log(`✓ ${message}`);\n }\n\n protected logWarning(message: string): void {\n this.warn(message);\n }\n\n protected logInfo(message: string): void {\n this.log(message);\n }\n\n protected clearTerminal(): void {\n clearTerminalScreen();\n }\n\n /**\n * Resolves the marketplace required for a plugin operation, or hard-exits with\n * an actionable error when it cannot be resolved. `onRegistered` is invoked\n * (when provided) if the marketplace had to be registered — init uses it to log.\n *\n * `host` is the caller's because a marketplace registration is handed no directory of its own:\n * every caller here holds the install root the run is about, and `hostAt` turns one into the\n * host whose registry the marketplace has to land in.\n */\n protected async requireMarketplaceOrExit(\n sourceResult: SourceLoadResult,\n purpose: string,\n host: PluginHost,\n onRegistered?: (marketplace: string) => void,\n ): Promise<string> {\n const required = await requireMarketplace(sourceResult, purpose, host);\n if (!required.ok) {\n this.error(required.error, { exit: EXIT_CODES.ERROR });\n }\n if (required.registered) {\n onRegistered?.(required.marketplace);\n }\n return required.marketplace;\n }\n\n /**\n * Reports every constraint a completed selection breaks — a conflicting pair, an unmet\n * requirement, an exclusive category with two picks.\n *\n * Shared by `init` and `edit` so one selection cannot be reported two ways. Both commands ask\n * the same question of the same matrix, so a roster that draws a warning through one must draw\n * the same warning through the other; `init` used to compute the answer and drop it, which is\n * the whole reason this lives here rather than on either command.\n *\n * These are advisory (`ValidationError` in types/matrix.ts): the selection is installed either\n * way and neither command's exit code turns on them, so they are warnings and not errors. The\n * loop is its own guard — an accepted selection carries no errors and says nothing.\n */\n protected reportValidationErrors(validation: SelectionValidation): void {\n for (const error of validation.errors) {\n this.warn(error.message);\n }\n }\n\n /**\n * Installs skill plugins and narrates the operation.\n *\n * Shared by `init` and `edit` for the same reason as {@link reportValidationErrors}:\n * both run the SAME install against the same marketplace, so a line one prints about\n * it the other owes. `edit` used to run it in silence — a real `claude plugin install`\n * was indistinguishable in the output from nothing having happened.\n *\n * The skills nothing carries are refused FIRST, by name: an install no marketplace\n * could serve is knowable before the Claude CLI is asked, and the generic\n * install-failure advice is unfollowable for a skill the user wrote themselves.\n */\n protected async installPluginSkillsReported(\n skills: SkillConfig[],\n marketplace: string,\n projectDir: string,\n matrix: MergedSkillsMatrix,\n ): Promise<PluginInstallResult> {\n const unbacked = unbackedPluginSkillIds(skills, matrix);\n if (unbacked.length > 0) {\n this.error(unbackedPluginInstallError(unbacked), { exit: EXIT_CODES.ERROR });\n }\n\n this.announcePluginInstall();\n const result = await installPluginSkills(skills, marketplace, projectDir);\n this.reportPluginInstalls(result);\n return result;\n }\n\n /**\n * The opening half of the narration above, exposed for the one caller that cannot\n * use the whole of it: an eject→plugin migration installs each plugin and deletes\n * that skill's working copy in the same step (see `executeMigration`), so the\n * install it performs is not this command's to run.\n */\n protected announcePluginInstall(): void {\n this.log(STATUS_MESSAGES.INSTALLING_PLUGINS);\n }\n\n /**\n * The closing half: what was installed, what was not, and the refusal to continue\n * past a failure.\n *\n * The hard-error is part of the report rather than each caller's own postscript\n * because it is the same rule everywhere — plugin install intent is inviolable, so\n * a run that could not honor it must stop BEFORE any config records a marketplace\n * `origin` for a skill with no plugin registration.\n */\n protected reportPluginInstalls(result: PluginInstallResult): void {\n for (const item of result.installed) {\n this.log(` Installed ${item.ref}`);\n }\n for (const item of result.failed) {\n this.warn(`Failed to install plugin ${item.id}: ${item.error}`);\n }\n if (result.failed.length > 0) {\n this.error(pluginInstallFailureError(result.failed.length), { exit: EXIT_CODES.ERROR });\n }\n this.log(`${pluginsInstalled(result.installed.length)}\\n`);\n }\n\n /**\n * Renders what a gated write's fan-out did to the OTHER registered projects: one line for each\n * it left alone because its config.ts cannot be loaded, then the recompile it performed.\n *\n * `uninstall` alone calls {@link reportPropagatedRecompile} directly, since it words the projects\n * whose config it could not prune in its own terms.\n */\n protected reportFanOut(report: GateReport): void {\n for (const projectPath of report.propagated.unreadable) {\n this.warn(registeredProjectConfigUnreadable(projectPath));\n }\n this.reportPropagatedRecompile(report);\n }\n\n /**\n * One line for each registered project a fan-out left alone because nothing of this\n * installation is there to rewrite: nothing is installed at its path any more, or it is another\n * provider's installation. `compile` and `uninstall` print it — neither project's config can\n * hold what either run changed.\n */\n protected reportProjectsOutOfReach(propagated: GateReport[\"propagated\"]): void {\n for (const projectPath of propagated.gone) {\n this.warn(registeredProjectGone(projectPath));\n }\n for (const projectPath of propagated.notOurs) {\n this.warn(registeredProjectOnAnotherProvider(projectPath));\n }\n }\n\n /**\n * Renders the recompile a gated write already performed on every OTHER registered\n * project this run's global change was propagated into.\n *\n * Shared by all four commands that fan out — the count and its wording are one\n * statement about one operation, and four copies of it had already drifted into two\n * spellings of the same sentence.\n */\n protected reportPropagatedRecompile(report: GateReport): void {\n if (report.propagated.updated.length === 0) return;\n\n const { rewrittenCount, unchangedCount, failedCount, warnings } = report.recompile;\n for (const warning of warnings) {\n this.warn(warning);\n }\n this.log(propagatedRecompileSummary(rewrittenCount, unchangedCount, failedCount));\n }\n\n /**\n * Names every selected skill this save left in no sub-agent's stack, and — where the\n * scope rule is why — every sub-agent it was kept away from.\n *\n * Shared by `init` and `edit` for the reason {@link reportValidationErrors} is: both\n * build the stack from the same rules over the same selection, so a skill that reaches\n * nothing through one reaches nothing through the other. The rule being reported is\n * CORRECT and nothing here changes it — a project-scoped skill installs, is written to\n * `config.ts`, and is loaded by nobody, which every other surface reports as a clean\n * install.\n *\n * `compile` says the same thing about the same shape one layer over, for a config\n * hand-edited into it — see `Compile.warnScopeDroppedStackPairs`.\n */\n protected reportUnassignedSkills(config: ProjectConfig, selected: readonly SkillConfig[]): void {\n for (const { skillId, blockedBy } of findUnassignedSkills(config, selected)) {\n this.warn(skillAssignedToNoAgent(skillId));\n if (blockedBy.length > 0) {\n this.warn(scopeBlockedStackAssignment(blockedBy, skillId));\n }\n }\n }\n\n /**\n * Refuses to run when a config file exists but cannot be loaded.\n *\n * Both configs this run would read are checked, because both are read on the way through: a\n * project's own `config.ts` and the global one every project write inlines. Checking up\n * front is the whole point — an unreadable GLOBAL config otherwise surfaced only at the\n * config write, after the wizard had copied skills and installed plugins, as a warning that\n * the write never happened.\n *\n * Every command that reads an installation's config calls it before anything else reads one:\n * the writes (`init`, `edit`, `compile`, `update`, `share`, `eject`) and the two that only\n * report (`search`, `list`). `doctor` reports the same file instead, and `uninstall` is the way\n * out of it, so neither does.\n *\n * A MISSING config is not a corrupt one and passes here untouched: it is the legitimate\n * state `init` exists for, and the state `edit` reports as \"no installation\".\n */\n protected async ensureConfigReadable(projectDir: string): Promise<void> {\n const failures = await findConfigLoadFailures(projectDir);\n if (failures.length > 0) {\n this.error(installationConfigsUnreadable(failures), { exit: EXIT_CODES.ERROR });\n }\n }\n\n /**\n * Refuses to run when a saved skill entry names a local skill that IS installed and whose\n * metadata.yaml describes no skill.\n *\n * One layer below {@link ensureConfigReadable} and for the same reason: the config parses,\n * and a file it points at does not. Both wizards resolve their saved roster against the\n * loaded catalogue, and an id nothing can be loaded for reaches no screen — so without this\n * the entry is dropped and reported as a skill the marketplace no longer carries, which is a\n * removal the user never asked for and a sentence blaming the wrong thing.\n *\n * Only entries the catalogue does not carry are looked at, so a healthy install pays a\n * filesystem read for nothing. An entry whose files are simply GONE is not refused — there\n * is no file to repair, so it is removed with a reason that says so\n * (`unresolvedSkillRemovalReasons`).\n *\n * Runs before the wizard mounts, which is the whole point: past that, a refusal costs the\n * user the session they had already spent, and everything this protects has been rewritten.\n */\n protected async ensureSavedSkillsReadable(\n savedSkills: readonly SkillConfig[],\n matrix: MergedSkillsMatrix,\n projectDir: string,\n ): Promise<void> {\n const unresolved = savedSkills\n .filter((saved) => !saved.excluded && !matrix.skills[saved.id])\n .map((saved) => saved.id);\n if (unresolved.length === 0) return;\n\n const unusable = await findUnusableSavedSkillMetadata(unresolved, savedSkills, projectDir);\n if (unusable.length === 0) return;\n\n // The detail is LOGGED and only the refusal is raised — oclif hard-wraps error text at the\n // terminal width, and a path broken across two lines is one nobody can copy. Same split\n // `compile` makes over the same verdict.\n for (const entry of unusable) {\n this.log(skillMetadataUnusableDetail(entry));\n }\n this.error(savedSkillMetadataUnusableError(unusable), { exit: EXIT_CODES.ERROR });\n }\n\n /**\n * Refuses a shared configuration carrying project-scoped content at the home directory.\n *\n * The home directory IS the global scope, and a global installation holds only global-scoped\n * content. Both scopes read one config file there, and on Claude one skills directory and one\n * agents directory as well — so a project-scoped entry lands in the global config wearing a\n * label that contradicts the file it is in, and on Claude `toClaudePluginScope` maps that\n * declared scope onward, registering the skill against `$HOME` as a project. Nothing\n * below this point reads the scope again, so whatever the boundary lets through becomes the\n * truth.\n *\n * Shared by `init --from` and `edit --from` for the reason {@link reportValidationErrors} is\n * shared: it is a fact about the payload and the directory, identical whichever command asked,\n * and an invariant enforced on one producer and not the other is enforced nowhere. It matters\n * more on the destructive one — `edit --from` reaches the same contradiction through the other\n * door and can remove global entries on the way.\n *\n * The interactive producer has always answered this for itself — `isHomeDirectory(projectDir)`\n * reaches the wizard session as `isGlobalRoot` and the scope toggles are inert under it — so\n * this puts both `--from` paths on the rule the wizard already follows.\n *\n * It takes the DECODED selection, so it must run after the decode and can run no earlier: an\n * all-global configuration is exactly what a global installation is for, and only the decode\n * says which entries survived this catalogue and what scope each rests at. Every caller runs it\n * before it reports a skip and before it writes anything, so a run about to be refused neither\n * narrates nor mutates.\n */\n protected refuseProjectScopedContentAtHome(result: WizardResultV2, projectDir: string): void {\n if (!isHomeDirectory(projectDir)) return;\n\n const { skillIds, agentNames } = projectScopedContent(result);\n if (skillIds.length === 0 && agentNames.length === 0) return;\n\n this.error(sharedConfigProjectScopeAtHome(skillIds, agentNames), { exit: EXIT_CODES.ERROR });\n }\n\n /**\n * The refusals a `--from` producer can decide only once it holds what it would install — the\n * selection and the skills the configuration carries — asked before it lists any of it or asks\n * whether to install it.\n *\n * A run that lists, asks, and is told yes has promised that a yes installs what was listed (the\n * u01 ruling: \"On yes, it installs what is listed\"), so a refusal still to come after the\n * question would ask a person to confirm an install that was never going to happen. Every other\n * `--from` refusal is already decided above the lists — a carried skill asked for as a plugin or\n * under a catalogue's id, project content at the home directory, an installation already here —\n * and these four are the ones that need the decoded selection to be asked of:\n *\n * - **A placement the host does not offer.** Read off the selection and the host the run\n * installs through, nothing else, so nothing makes it wait for the yes.\n * - **A stack the marketplace does not ship.** The stack supplies only the configuration's\n * description, yet the install refuses an id it cannot resolve — after the plugins are\n * installed and the skills copied. So it is asked here, through the lookup the install makes,\n * of the marketplace the install reads.\n * - **A carried skill over a directory no shared configuration put there** — the user's own\n * skill at the id the configuration minted for it. Judged on the same set the producer writes,\n * so the skills already installed globally, which it does not write, are not asked about.\n * - **A stack the config writer would refuse** — two skills in a category that holds one, as a\n * hand-written row or the kept skills an apply puts back can make. Asked through the writer's\n * own rule, because `edit --from` writes the config after its removals have landed.\n *\n * Shared by `init --from` and `edit --from` for the reason {@link refuseProjectScopedContentAtHome}\n * is: an invariant enforced on one producer and not the other is enforced nowhere.\n */\n protected async refuseSharedConfigBeforeAsking(\n selection: WizardResultV2,\n carried: ExternalSkillInstall[],\n root: string,\n sourceResult: SourceLoadResult,\n ): Promise<void> {\n this.refuseUnofferablePlacementsBeforeWriting(selection.skills, root);\n try {\n await refuseUnofferedStack(selection.selectedStackId, sourceResult);\n await refuseUncarriedDestinations(carried);\n refuseUnwritableStack(selection.assignedStack, sourceResult.matrix);\n } catch (error) {\n this.handleError(error);\n }\n }\n\n /**\n * Refuses a SELECTION asking for a mode/scope cell this host does not offer, before the run has\n * touched anything.\n *\n * **`bindsItsOfferedPlacements` is not a pre-flight and cannot be made into one.** It refuses\n * at `installPlugin`, which `installPluginSkills` calls once per skill inside a loop that\n * collects per-skill failures — so a payload whose first plugin row is offerable and whose\n * second is not installed a real plugin into the user's Codex registry and only then stopped,\n * on a message ending \"Nothing has been changed.\" Nothing removed it afterwards: no `config.ts`\n * was written, so `uninstall` had no row naming it and `doctor` had no configuration to check\n * it against — an orphan in the host's own registry that no command in this CLI can see. The\n * single-row case cannot show it, because with one unofferable row the loop's first iteration\n * IS the refusal. `edit --from` had no pre-flight at all until it came here, and met exactly\n * that per-plugin guard after its own yes.\n *\n * It reads the whole selection — ejected rows included — because the roster is about CELLS\n * rather than about plugins: a host that stopped offering `eject+project` would owe the same\n * refusal, and a guard that only looked at plugin rows would go on writing files for it.\n *\n * The same function the read path calls (`refuseUnofferedPlacements`, off the same host\n * roster), so `init`'s sentence and `compile`'s are one sentence rather than two that agree\n * today. The per-call guard stays where it is: it is the backstop for a caller that did not\n * come through here, and for the one host this release ships every cell is offered, so a\n * backstop that never fires is what a deleted one would look like.\n */\n protected refuseUnofferablePlacementsBeforeWriting(\n skills: readonly SkillConfig[],\n root: string,\n ): void {\n try {\n refuseUnofferedPlacements(skills, hostAt(root));\n } catch (error) {\n this.error(getErrorMessage(error), { exit: EXIT_CODES.ERROR });\n }\n }\n\n /** Whether this run owes an account — the one thing a command may ask about the list. */\n protected get hasIncompleteWork(): boolean {\n return this.incompleteWork.length > 0;\n }\n\n /**\n * Warns about work this run attempted and did not complete, and records it for the ending.\n *\n * Both halves, always. The warning stays at the point of failure because that is where it is\n * explicable and where the surrounding output says what was being attempted; the record is\n * what decides the exit code, and a failure the user is told about while the process reports\n * success is exactly the state this closes.\n *\n * What it must never do is abort. Every caller sits past the point where the mutation it is\n * reporting on has already happened, so stopping would relabel a state already committed to\n * disk rather than prevent it — and would abandon the steps after it that can still land.\n *\n * The `recovery` sentences live in `INCOMPLETE_WORK_RECOVERY` in `utils/messages.ts`. One\n * spelling per remedy is what matters; three spellings of \"run compile\" read as three\n * different instructions.\n */\n protected reportIncompleteWork(what: string, recovery: string): void {\n this.warn(what);\n this.recordIncompleteWork(what, recovery);\n }\n\n /**\n * The recording half alone, for a caller that has already said its piece: a recompile warns\n * once per failed sub-agent with the compiler's own reason, so the ending names the roster\n * those reasons belong to instead of repeating any of them.\n */\n protected recordIncompleteWork(what: string, recovery: string): void {\n this.incompleteWork.push({ what, recovery });\n }\n\n /**\n * The command's last word: what did not happen, what finishes it, and a non-zero exit.\n *\n * `this.exit` raises oclif's `ExitError`, which the framework carries to the process exit\n * code and prints nothing for — so the account printed here is the whole of the output, with\n * none of the `Error:` framing `this.error` would add to a command that in fact completed.\n *\n * A command that records must call this, or it files failures into a list nothing reads —\n * which is the original silence wearing the mechanism built to close it, and is what\n * `failure-reporting-classification.test.ts` holds every command in `src/cli/commands/` to.\n */\n protected exitIfWorkIncomplete(): void {\n if (!this.hasIncompleteWork) return;\n\n this.log(`\\n${chalk.hex(CLI_COLORS.WARNING)(completedWithFailures(this.incompleteWork))}\\n`);\n this.exit(EXIT_CODES.COMPLETED_WITH_FAILURES);\n }\n}\n","import type { PluginHost } from \"../../hosts/plugin-host.js\";\nimport { fetchMarketplace } from \"../../loading/index.js\";\nimport { warn } from \"../../../utils/logger.js\";\nimport { getErrorMessage } from \"../../../utils/errors.js\";\nimport type { SourceLoadResult } from \"../../loading/source-loader.js\";\n\nexport type MarketplaceResult = {\n /** The resolved marketplace name, or null if no marketplace is configured. */\n marketplace: string | null;\n /** Whether a new marketplace was registered (vs. updated or already existed). */\n registered: boolean;\n};\n\n/**\n * Ensures the marketplace is registered with the host this installation runs on.\n *\n * The host is a parameter rather than something resolved here: this is the one plugin operation\n * that is handed no directory at all — a marketplace is user-level state under one HOME, and its\n * verbs take a name and a source and nothing else — so there is no folder for it to read a\n * provider off.\n *\n * If the marketplace does not exist, registers it. If it exists, updates it.\n * Handles lazy marketplace name resolution when sourceResult.marketplace is undefined.\n *\n * Reports nothing on success — commands decide what to log based on the `registered`\n * flag — but never swallows a failure: `requireMarketplace` turns a null marketplace\n * into a hard error whose text cannot tell a transient fetch failure apart from a\n * source that genuinely ships no marketplace, so the cause is warned here or nowhere.\n */\nexport async function ensureMarketplace(\n sourceResult: SourceLoadResult,\n host: PluginHost,\n): Promise<MarketplaceResult> {\n const source = sourceResult.sourceConfig.source;\n\n if (!sourceResult.marketplace) {\n try {\n const marketplaceResult = await fetchMarketplace(source);\n sourceResult.marketplace = marketplaceResult.marketplace.name;\n } catch (error) {\n warn(`Could not resolve a marketplace from '${source}': ${getErrorMessage(error)}`);\n return { marketplace: null, registered: false };\n }\n }\n\n const marketplace = sourceResult.marketplace;\n const exists = await host.marketplaceExists(marketplace);\n\n if (!exists) {\n const marketplaceSource = source.replace(/^github:/, \"\");\n await host.addMarketplace(marketplaceSource);\n return { marketplace, registered: true };\n }\n\n try {\n await host.refreshMarketplace(marketplace);\n } catch {\n warn(\"Could not update marketplace — continuing with cached version\");\n }\n\n return { marketplace, registered: false };\n}\n","import { ensureMarketplace } from \"./ensure-marketplace.js\";\nimport type { PluginHost } from \"../../hosts/plugin-host.js\";\nimport type { SourceLoadResult } from \"../../loading/source-loader.js\";\n\nexport type MarketplaceRequirement =\n { ok: true; marketplace: string; registered: boolean } | { ok: false; error: string };\n\n/**\n * Resolves the marketplace required for plugin operations. Plugin install\n * intent is inviolable — callers must hard-error on `ok: false` rather than\n * silently falling back to eject or skipping, and must do so BEFORE any\n * filesystem mutation so a failure leaves no partial state on disk.\n */\nexport async function requireMarketplace(\n sourceResult: SourceLoadResult,\n purpose: string,\n host: PluginHost,\n): Promise<MarketplaceRequirement> {\n const mpResult = await ensureMarketplace(sourceResult, host);\n if (!mpResult.marketplace) {\n return {\n ok: false,\n error:\n `Cannot ${purpose}: marketplace could not be resolved from '${sourceResult.sourceConfig.source}'. ` +\n `Plugin install mode requires a marketplace — fix the marketplace or switch the affected skills to eject mode.`,\n };\n }\n return { ok: true, marketplace: mpResult.marketplace, registered: mpResult.registered };\n}\n"],"mappings":"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","names":[]}
@@ -1,34 +1,44 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  SEED_API_URL,
4
- SEED_USER_AGENT,
4
+ SEED_USER_AGENT
5
+ } from "./chunk-25MPBIK3.js";
6
+ import {
7
+ withoutExcludedAssignments
8
+ } from "./chunk-GE3WKJ6Q.js";
9
+ import {
5
10
  readCarriedSkills
6
- } from "./chunk-X4SSJZLY.js";
11
+ } from "./chunk-Y3VIRVVE.js";
7
12
  import {
8
13
  ERROR_MESSAGES,
9
14
  directoryExists,
10
15
  getErrorMessage,
16
+ getProjectConfigPath,
11
17
  isScopePairCompatible,
12
18
  loadProjectConfig,
19
+ loadProjectConfigFromDir,
13
20
  readForkedFromMetadata,
14
21
  resolveInstallPaths,
15
22
  truncateText
16
- } from "./chunk-XPDVAJDH.js";
23
+ } from "./chunk-A4KDXNOT.js";
17
24
  import {
18
25
  typedEntries,
19
26
  typedValues
20
- } from "./chunk-AVK2HEKB.js";
27
+ } from "./chunk-V5WXIM2F.js";
21
28
  import {
22
29
  CLI_INVOKE_COMMAND,
23
30
  DEFAULT_PUBLIC_SOURCE_NAME,
24
31
  EJECT_SOURCE,
25
32
  MATRIX_VERSION,
26
33
  SEED_VERSION,
34
+ activeAgentScopeMap,
35
+ activeSkillScopeMap,
27
36
  installableSeedPayloadSchema,
28
37
  seedModelSchema
29
- } from "./chunk-UITEKY2R.js";
38
+ } from "./chunk-ENGYJCTF.js";
30
39
 
31
40
  // src/cli/lib/seed/installation-payload.ts
41
+ import os from "os";
32
42
  import path from "path";
33
43
 
34
44
  // src/cli/lib/seed/config-to-seed.ts
@@ -60,17 +70,24 @@ function unshareableConfigError(unshareable) {
60
70
  "Sharing it anyway would mint an id that installs something else."
61
71
  ].join("\n");
62
72
  }
63
- function isRecordedMarketplace(config, skill) {
64
- return config.marketplace !== void 0 && skill.origin === config.marketplaceName;
73
+ function isRecordedMarketplace(record, skill) {
74
+ return record?.marketplace !== void 0 && skill.origin === record.marketplaceName;
65
75
  }
66
- function readMarketplace(config, skills) {
76
+ function readMarketplace(config, skills, inheritedFrom) {
67
77
  const served = skills.filter((skill) => needsMarketplaceNamed(skill.origin));
68
- if (served.length === 0) return { ref: void 0, unnameable: [] };
69
- const unaccounted = served.filter((skill) => !isRecordedMarketplace(config, skill));
78
+ const unaccounted = served.filter(
79
+ (skill) => !isRecordedMarketplace(config, skill) && !isRecordedMarketplace(inheritedFrom, skill)
80
+ );
70
81
  if (unaccounted.length > 0) {
71
82
  return { ref: void 0, unnameable: unaccounted.map(unnameableOriginMessage) };
72
83
  }
73
- return { ref: config.marketplace, unnameable: [] };
84
+ const servesItsOwn = served.some((skill) => isRecordedMarketplace(config, skill));
85
+ return { ref: servesItsOwn ? config.marketplace : void 0, unnameable: [] };
86
+ }
87
+ function skillsItsMarketplaceLeavesBehind(config, payload) {
88
+ const namedMarketplace = payload.marketplace === void 0 ? DEFAULT_PUBLIC_SOURCE_NAME : config.marketplaceName;
89
+ const isPluginFromElsewhere = (skill) => skill.origin !== EJECT_SOURCE && skill.origin !== namedMarketplace;
90
+ return config.skills.filter(isInstalled).filter(isPluginFromElsewhere).map((skill) => skill.id);
74
91
  }
75
92
  function unnameableModels(agents) {
76
93
  return agents.flatMap(
@@ -83,18 +100,16 @@ function readStack(stack, skillScopes, agentScopes) {
83
100
  for (const [agent, agentStack] of typedEntries(stack ?? {})) {
84
101
  const agentScope = agentScopes.get(agent);
85
102
  if (agentScope === void 0) continue;
86
- for (const categoryAssignments of typedValues(agentStack)) {
87
- for (const { id, preloaded } of categoryAssignments) {
88
- const skillScope = skillScopes.get(id);
89
- if (skillScope === void 0) continue;
90
- if (!isScopePairCompatible(skillScope, agentScope)) {
91
- unwritable.push(unwritablePairMessage(id, agent));
92
- continue;
93
- }
94
- const forSkill = assignments.get(id) ?? {};
95
- forSkill[agent] = seedLoadState(preloaded);
96
- assignments.set(id, forSkill);
103
+ for (const { id, preloaded } of typedValues(agentStack).flat()) {
104
+ const skillScope = skillScopes.get(id);
105
+ if (skillScope === void 0) continue;
106
+ if (!isScopePairCompatible(skillScope, agentScope)) {
107
+ unwritable.push(unwritablePairMessage(id, agent));
108
+ continue;
97
109
  }
110
+ const forSkill = assignments.get(id) ?? {};
111
+ forSkill[agent] = seedLoadState(preloaded);
112
+ assignments.set(id, forSkill);
98
113
  }
99
114
  }
100
115
  return { assignments, unwritable };
@@ -116,13 +131,13 @@ function toSeedAgent(agent) {
116
131
  ...agent.effort !== void 0 && { effort: agent.effort }
117
132
  };
118
133
  }
119
- function configToSeedPayload(config, carried) {
134
+ function configToSeedPayload(config, carried, inheritedFrom) {
120
135
  const skills = config.skills.filter(isInstalled);
121
136
  const agents = config.agents.filter(isInstalled);
122
137
  const skillScopes = new Map(skills.map((skill) => [skill.id, skill.scope]));
123
138
  const agentScopes = new Map(agents.map((agent) => [agent.name, agent.scope]));
124
139
  const { assignments, unwritable } = readStack(config.stack, skillScopes, agentScopes);
125
- const marketplace = readMarketplace(config, skills);
140
+ const marketplace = readMarketplace(config, skills, inheritedFrom);
126
141
  const unshareable = [
127
142
  ...marketplace.unnameable,
128
143
  ...unnameableModels(agents),
@@ -152,23 +167,51 @@ function configToSeedPayload(config, carried) {
152
167
  async function seedPayloadForInstallation(projectDir) {
153
168
  const installed = await readInstalledConfig(projectDir);
154
169
  if (!installed.ok) return installed;
155
- const mapped = mapOrRefuse(await readRoundTrip(installed.config, projectDir));
170
+ const roundTrip = await readRoundTrip(installed.config, projectDir);
171
+ const mapped = mapOrRefuse(roundTrip, installed.inheritedFrom);
156
172
  if (!mapped.ok) return mapped;
157
173
  const { payload } = mapped;
158
174
  const skills = Object.keys(payload.skills).length;
159
175
  const agents = Object.keys(payload.agents).length;
160
176
  if (skills === 0 && agents === 0) return { ok: false, error: ERROR_MESSAGES.NO_INSTALLATION };
161
- return { ok: true, payload, skills, agents };
177
+ const leftBehind = skillsItsMarketplaceLeavesBehind(roundTrip.config, payload);
178
+ return { ok: true, payload, skills, agents, leftBehind };
162
179
  }
163
180
  async function readInstalledConfig(projectDir) {
164
181
  try {
165
182
  const loaded = await loadProjectConfig(projectDir);
166
183
  if (!loaded) return { ok: false, error: ERROR_MESSAGES.NO_INSTALLATION };
167
- return { ok: true, config: loaded.config };
184
+ const inheritedFrom = await readInheritedConfig(loaded);
185
+ return { ok: true, config: withInheritedCuration(loaded.config, inheritedFrom), inheritedFrom };
168
186
  } catch (error) {
169
187
  return { ok: false, error: getErrorMessage(error) };
170
188
  }
171
189
  }
190
+ async function readInheritedConfig(loaded) {
191
+ if (isGlobalConfig(loaded)) return void 0;
192
+ const home = await loadProjectConfigFromDir(os.homedir(), loaded.provider);
193
+ return home?.config;
194
+ }
195
+ function isGlobalConfig(loaded) {
196
+ return loaded.configPath === getProjectConfigPath(os.homedir(), loaded.provider);
197
+ }
198
+ function withInheritedCuration(config, inheritedFrom) {
199
+ if (inheritedFrom?.stack === void 0) return config;
200
+ return { ...config, stack: { ...config.stack, ...inheritedRows(config, inheritedFrom.stack) } };
201
+ }
202
+ function inheritedRows(config, globalStack) {
203
+ const agents = inheritedAgents(config.agents);
204
+ const rows = Object.fromEntries(typedEntries(globalStack).filter(([agent]) => agents.has(agent)));
205
+ return withoutExcludedAssignments(rows, skillsNotInherited(config.skills));
206
+ }
207
+ function inheritedAgents(agents) {
208
+ const scopes = activeAgentScopeMap(agents);
209
+ return new Set(agents.map((agent) => agent.name).filter((name) => scopes.get(name) === "global"));
210
+ }
211
+ function skillsNotInherited(skills) {
212
+ const scopes = activeSkillScopeMap(skills);
213
+ return new Set(skills.map((skill) => skill.id).filter((id) => scopes.get(id) !== "global"));
214
+ }
172
215
  async function readRoundTrip(config, projectDir) {
173
216
  const owned = (await judgeSkills(config, projectDir)).filter((entry) => entry.owned);
174
217
  return {
@@ -196,9 +239,9 @@ async function judgeSkill(skill, projectDir) {
196
239
  if (provenance === null) return { skill, owned: false, carried: null };
197
240
  return { skill, owned: true, carried: { id: skill.id, skillDir, provenance } };
198
241
  }
199
- function mapOrRefuse({ config, content }) {
242
+ function mapOrRefuse({ config, content }, inheritedFrom) {
200
243
  try {
201
- return { ok: true, payload: configToSeedPayload(config, content) };
244
+ return { ok: true, payload: configToSeedPayload(config, content, inheritedFrom) };
202
245
  } catch (error) {
203
246
  return { ok: false, error: getErrorMessage(error) };
204
247
  }
@@ -306,4 +349,4 @@ export {
306
349
  skillsAuthoredHere,
307
350
  publishSeedConfig
308
351
  };
309
- //# sourceMappingURL=chunk-NTF4UXGK.js.map
352
+ //# sourceMappingURL=chunk-Y47EV74W.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/cli/lib/seed/installation-payload.ts","../src/cli/lib/seed/config-to-seed.ts","../src/cli/lib/seed/publish-seed.ts"],"sourcesContent":["import os from \"os\";\nimport path from \"path\";\n\nimport {\n configToSeedPayload,\n isInstalled,\n skillsItsMarketplaceLeavesBehind,\n} from \"./config-to-seed.js\";\nimport { readCarriedSkills } from \"./external-skills.js\";\nimport { EJECT_SOURCE } from \"../../consts.js\";\nimport { withoutExcludedAssignments } from \"../agents/agent-recompiler.js\";\nimport { loadProjectConfig, loadProjectConfigFromDir } from \"../configuration/project-config.js\";\nimport { activeAgentScopeMap, activeSkillScopeMap } from \"../configuration/scope-predicates.js\";\nimport { getProjectConfigPath, resolveInstallPaths } from \"../installation/install-base-dir.js\";\nimport { readForkedFromMetadata } from \"../skills/skill-metadata.js\";\nimport { getErrorMessage } from \"../../utils/errors.js\";\nimport { directoryExists } from \"../../utils/fs.js\";\nimport { ERROR_MESSAGES } from \"../../utils/messages.js\";\nimport { typedEntries } from \"../../utils/typed-object.js\";\n\nimport type { ContentReading, OwnedSkillDir } from \"./external-skills.js\";\nimport type { LoadedProjectConfig } from \"../configuration/project-config.js\";\nimport type { AgentScopeConfig, ProjectConfig, SkillConfig, SkillId } from \"../../types/index.js\";\nimport type { SeedPayload } from \"@workspace/matrix/seed\";\n\n/**\n * A payload ready to post, and what it will install — counted the way the sharer's own screens\n * count it, off the payload rather than off the config, so what a caller announces and what it\n * posts cannot disagree.\n *\n * `leftBehind` names the skills the payload carries that the one marketplace it names does not\n * serve: they travel, and an install anywhere else skips them. Empty for an installation read\n * from a single marketplace.\n */\nexport type InstallationPayload =\n | { ok: true; payload: SeedPayload; skills: number; agents: number; leftBehind: SkillId[] }\n | { ok: false; error: string };\n\n/**\n * The config to map, or the sentence explaining why there is none to map.\n *\n * `inheritedFrom` is the global configuration a project's own config inherits from, and absent\n * when the config read is the global one already.\n */\ntype InstalledConfig =\n | { ok: true; config: ProjectConfig; inheritedFrom: ProjectConfig | undefined }\n | { ok: false; error: string };\n\n/** The mapped payload, or every line naming something the contract cannot carry. */\ntype MappedPayload = { ok: true; payload: SeedPayload } | { ok: false; error: string };\n\n/** The installation as the round trip sees it: what it owns, and what it has to carry with it. */\ntype RoundTrip = { config: ProjectConfig; content: ContentReading };\n\n/**\n * What the round trip makes of one installed entry: whether it travels at all, and whether its\n * bytes travel with it.\n */\ntype SkillJudgement = { skill: SkillConfig; owned: boolean; carried: OwnedSkillDir | null };\n\n/**\n * Read, map, refuse — everything that can fail locally, failing before anybody spends a write.\n *\n * Shared by the two commands that mint an id for what is installed here: `share`, which reports\n * the id, and `edit --ui`, which opens it. They are one operation with two endings, and this is\n * the half that has to be identical — two spellings of \"the installation in this directory\"\n * would mint two different ids for one project, and only one of them would be true.\n *\n * Every failure is a message rather than a throw, because nothing has been written by the time\n * it runs: the caller's only job is to explain, and both callers explain the same way.\n */\nexport async function seedPayloadForInstallation(projectDir: string): Promise<InstallationPayload> {\n const installed = await readInstalledConfig(projectDir);\n if (!installed.ok) return installed;\n\n const roundTrip = await readRoundTrip(installed.config, projectDir);\n const mapped = mapOrRefuse(roundTrip, installed.inheritedFrom);\n if (!mapped.ok) return mapped;\n\n const { payload } = mapped;\n const skills = Object.keys(payload.skills).length;\n const agents = Object.keys(payload.agents).length;\n\n // The same guard `init --from` applies on arrival, applied here before the write instead of\n // there after it. A sub-agent is installable on its own — it has front-matter, a prompt and a\n // compiled file without owning a single skill — so only a configuration with neither skills\n // nor sub-agents is nothing to carry.\n if (skills === 0 && agents === 0) return { ok: false, error: ERROR_MESSAGES.NO_INSTALLATION };\n\n const leftBehind = skillsItsMarketplaceLeavesBehind(roundTrip.config, payload);\n return { ok: true, payload, skills, agents, leftBehind };\n}\n\n/**\n * The installation this directory has: its own configuration, or the global one it inherits.\n *\n * That is the config every other command reads here, and its skills and sub-agents are those of\n * BOTH scopes with each entry's own scope on it — which is exactly what the wire keys by. Its\n * `stack` is not: see {@link withInheritedCuration}, which is what makes a payload minted from a\n * project describe the whole of what is installed for it rather than half of it.\n *\n * A config file that exists but cannot be loaded is a fault, not an absence, so its own message\n * is reported rather than read as \"not installed\" — HOME's included, because minting without\n * the rows it holds would mint the thinner configuration this module refuses to.\n */\nasync function readInstalledConfig(projectDir: string): Promise<InstalledConfig> {\n try {\n const loaded = await loadProjectConfig(projectDir);\n if (!loaded) return { ok: false, error: ERROR_MESSAGES.NO_INSTALLATION };\n const inheritedFrom = await readInheritedConfig(loaded);\n return { ok: true, config: withInheritedCuration(loaded.config, inheritedFrom), inheritedFrom };\n } catch (error) {\n return { ok: false, error: getErrorMessage(error) };\n }\n}\n\n/**\n * The global configuration a project's own config inherits from — the SAME provider's, since each\n * provider inherits only within itself. None when the config read is the global one already.\n */\nasync function readInheritedConfig(\n loaded: LoadedProjectConfig,\n): Promise<ProjectConfig | undefined> {\n if (isGlobalConfig(loaded)) return undefined;\n\n const home = await loadProjectConfigFromDir(os.homedir(), loaded.provider);\n return home?.config;\n}\n\n/** Whether the config read is the global one: at `$HOME`, or in a directory without its own. */\nfunction isGlobalConfig(loaded: LoadedProjectConfig): boolean {\n return loaded.configPath === getProjectConfigPath(os.homedir(), loaded.provider);\n}\n\n/**\n * The project's configuration with the rows of the sub-agents it inherits, read from the file that\n * compiles them.\n *\n * A project's file inlines the global skills and sub-agents but keeps rows for its own sub-agents\n * only: a global sub-agent is compiled from the global config, so its row is written there alone\n * (`partitionInlinedConfigEntries` in `@workspace/compile`). Read by itself, the project file hands\n * every inherited sub-agent to the mapping with no row, and the id it mints installs them bare.\n *\n * The global config's row for an inherited sub-agent wins over one the project file holds, which\n * only a hand edit puts there: the global config is the one that compiles that sub-agent.\n */\nfunction withInheritedCuration(\n config: ProjectConfig,\n inheritedFrom: ProjectConfig | undefined,\n): ProjectConfig {\n if (inheritedFrom?.stack === undefined) return config;\n\n return { ...config, stack: { ...config.stack, ...inheritedRows(config, inheritedFrom.stack) } };\n}\n\n/**\n * The global config's rows for the sub-agents this project inherits, each narrowed to the skills\n * it inherits too — read through the scopes the mapping itself reads, so no row taken here can\n * land on a sub-agent or skill the payload carries at project scope.\n *\n * A sub-agent or skill the project masks with a half of its own is the project's here, and the\n * global row naming it describes an install this project does not use: on the project's own\n * sub-agent it would hand over another agent's load, and on a project skill it would ask a global\n * sub-agent for a pair the wire cannot carry, refusing a share that never named it.\n */\nfunction inheritedRows(\n config: ProjectConfig,\n globalStack: NonNullable<ProjectConfig[\"stack\"]>,\n): NonNullable<ProjectConfig[\"stack\"]> {\n const agents = inheritedAgents(config.agents);\n const rows = Object.fromEntries(typedEntries(globalStack).filter(([agent]) => agents.has(agent)));\n return withoutExcludedAssignments(rows, skillsNotInherited(config.skills));\n}\n\n/** The sub-agents this project takes from the global config: those resting at global scope here. */\nfunction inheritedAgents(agents: AgentScopeConfig[]): Set<string> {\n const scopes = activeAgentScopeMap(agents);\n return new Set(agents.map((agent) => agent.name).filter((name) => scopes.get(name) === \"global\"));\n}\n\n/**\n * The skills this project names but does not take from the global config: its own, and the global\n * installs it masks.\n */\nfunction skillsNotInherited(skills: SkillConfig[]): Set<SkillId> {\n const scopes = activeSkillScopeMap(skills);\n return new Set(skills.map((skill) => skill.id).filter((id) => scopes.get(id) !== \"global\"));\n}\n\n/**\n * The installation minus what the round trip does not own, plus the content it has to take along.\n *\n * `forkedFrom` decides ownership, and the round trip leaves what it does not own alone. The CLI\n * stamps that key into every skill directory it writes — an ejected catalogue skill, and a skill\n * a payload carried inline — while a skill the user wrote by hand into `.claude/skills/` carries\n * none. So absence of the key is not the whole answer and provenance is: what the CLI put there\n * says so on disk, and what a person put there says nothing because nothing forked it.\n *\n * A user-authored skill is therefore neither carried nor refused — it is simply outside the\n * round trip, and nothing about leaving it home is lossy because it was never in scope. Dropping\n * it here rather than in a command is what keeps `share` and `edit --ui`, which mint an id from\n * the same directory, from disagreeing about a single project.\n *\n * The stack rows naming a dropped skill go with it: `configToSeedPayload` keys assignments by\n * the skills it carries, so a row whose skill is gone is gone too.\n *\n * One walk answers both questions, because they are asked of the same file: whether the CLI put\n * this directory here, and — for the one kind of skill no catalogue can resolve — where its bytes\n * came from, so they can travel a second time.\n */\nasync function readRoundTrip(config: ProjectConfig, projectDir: string): Promise<RoundTrip> {\n const owned = (await judgeSkills(config, projectDir)).filter((entry) => entry.owned);\n\n return {\n config: { ...config, skills: owned.map((entry) => entry.skill) },\n content: await readCarriedSkills(owned.flatMap((entry) => entry.carried ?? [])),\n };\n}\n\n/** Every installed entry, judged. One walk of the disk, whichever half of the trip is asking. */\nfunction judgeSkills(config: ProjectConfig, projectDir: string): Promise<SkillJudgement[]> {\n return Promise.all(config.skills.map((skill) => judgeSkill(skill, projectDir)));\n}\n\n/**\n * The installed skills the round trip does NOT own — the user's own work, sitting in\n * `.claude/skills/` with no `forkedFrom` to say the CLI put it there.\n *\n * The producer already drops these on the way out, so no payload minted here ever named one.\n * This is the same judgement read by the other half: `edit --from` applies a payload\n * destructively, and a payload that made no statement about a skill cannot be read as an\n * instruction to delete it. Both halves ask {@link judgeSkill}, so \"outside the round trip\" has\n * one definition and cannot come to mean two things on one machine.\n */\nexport async function skillsAuthoredHere(\n config: ProjectConfig,\n projectDir: string,\n): Promise<Set<SkillId>> {\n const judged = await judgeSkills(config, projectDir);\n return new Set(judged.filter((entry) => !entry.owned).map((entry) => entry.skill.id));\n}\n\n/** The entry travels and no directory is read for it: a row naming an id is the whole of it. */\nfunction travelsAsAnId(skill: SkillConfig): SkillJudgement {\n return { skill, owned: true, carried: null };\n}\n\n/**\n * How one installed entry answers to the round trip — asked of the disk, offline, exactly as\n * `uninstall` asks it before removing anything.\n *\n * Only a directory that EXISTS and carries no provenance is somebody's own work, and that is the\n * one thing this excludes; each guard below says why the case above it never gets that far.\n */\nasync function judgeSkill(skill: SkillConfig, projectDir: string): Promise<SkillJudgement> {\n // A marketplace skill has no local directory to hold provenance and needs none: the marketplace\n // is what installs it again.\n if (skill.origin !== EJECT_SOURCE) return travelsAsAnId(skill);\n // A tombstone is a statement about something that is NOT installed here, so there are no bytes\n // of it to carry — and a refusal raised over them would refuse a share for a skill it is not\n // sharing.\n if (!isInstalled(skill)) return travelsAsAnId(skill);\n\n const skillsDir = resolveInstallPaths(projectDir, skill.scope).skillsDir;\n const skillDir = path.join(skillsDir, skill.id);\n // A configuration recording an install that is not there is evidence of nothing rather than\n // evidence of authorship, so it travels as the configuration records it.\n if (!(await directoryExists(skillDir))) return travelsAsAnId(skill);\n\n const provenance = await readForkedFromMetadata(skillDir);\n if (provenance === null) return { skill, owned: false, carried: null };\n\n return { skill, owned: true, carried: { id: skill.id, skillDir, provenance } };\n}\n\n/**\n * The mapping, with its refusals turned into this module's own currency.\n *\n * `configToSeedPayload` throws, and what it throws is a list: every line names something this\n * installation has that a shared configuration cannot say. That is a message for the user, not a\n * fault to propagate — the alternative is worse than a failed command, because a payload quietly\n * missing what it could not say still mints an id, and that id installs a configuration nobody\n * chose.\n */\nfunction mapOrRefuse(\n { config, content }: RoundTrip,\n inheritedFrom: ProjectConfig | undefined,\n): MappedPayload {\n try {\n return { ok: true, payload: configToSeedPayload(config, content, inheritedFrom) };\n } catch (error) {\n return { ok: false, error: getErrorMessage(error) };\n }\n}\n","import { MATRIX_VERSION } from \"@workspace/matrix\";\nimport {\n SEED_VERSION,\n installableSeedPayloadSchema,\n seedModelSchema,\n} from \"@workspace/matrix/seed\";\n\nimport { DEFAULT_PUBLIC_SOURCE_NAME, EJECT_SOURCE } from \"../../consts.js\";\nimport { isScopePairCompatible } from \"../configuration/config-generator.js\";\nimport { typedEntries, typedValues } from \"../../utils/typed-object.js\";\n\nimport type { ContentReading } from \"./external-skills.js\";\nimport type {\n AgentScopeConfig,\n ProjectConfig,\n SkillConfig,\n SkillScope,\n} from \"../../types/config.js\";\nimport type { ModelName } from \"../../types/matrix.js\";\nimport type { SkillId } from \"../../types/skills.js\";\nimport type {\n SeedAgent,\n SeedLoadState,\n SeedModel,\n SeedPayload,\n SeedSkill,\n} from \"@workspace/matrix/seed\";\n\n/** Sub-agent name -> load state for one skill: the shape the wire keys by skill. */\ntype SeedAssignments = Record<string, SeedLoadState>;\n\n/** What one walk of `config.stack` yields: the wire's assignments, and the rows that cannot be one. */\ntype StackReading = {\n assignments: Map<SkillId, SeedAssignments>;\n /** Pairs the config model has nowhere to write, worded for the refusal. */\n unwritable: string[];\n};\n\n/**\n * An installed entry. An excluded one is a tombstone — a statement about something that is NOT\n * installed here — and presence is selection on the wire, so it has nothing to say. Nothing is\n * lost by leaving it home either: `init --from` installs into a clean setup, where there is no\n * global install for a tombstone to mask.\n *\n * Exported because the reader that gathers what an installation CARRIES has to agree with the\n * mapper about what it installs: content read for an entry this payload will not name is content\n * paid for by nobody, and a refusal raised over it would refuse a share for a skill it is not\n * sharing.\n */\nexport function isInstalled(entry: { excluded?: boolean }): boolean {\n return !entry.excluded;\n}\n\n/**\n * Whether a skill from this origin obliges the payload to name a marketplace.\n *\n * Two do not. An ejected copy travels with the project, and the default public catalogue is what\n * an absent ref already means — so neither puts a ref on the wire, and two identical selections\n * cannot mint two different ids over one.\n */\nfunction needsMarketplaceNamed(origin: string): boolean {\n return origin !== EJECT_SOURCE && origin !== DEFAULT_PUBLIC_SOURCE_NAME;\n}\n\n/**\n * Asked of the contract's own enum rather than spelled out here, so widening `MODEL_NAMES`\n * without widening the wire cannot slip past as a silently dropped pin.\n */\nfunction isSeedModel(model: ModelName): model is SeedModel {\n return seedModelSchema.safeParse(model).success;\n}\n\n/** The wire spells as an enum what a stack entry spells as a boolean, and an absent flag is lazy. */\nfunction seedLoadState(preloaded: boolean | undefined): SeedLoadState {\n return preloaded === true ? \"preloaded\" : \"lazy\";\n}\n\nfunction unnameableOriginMessage(skill: SkillConfig): string {\n return `${skill.id} comes from the marketplace '${skill.origin}', and this installation does not record where that marketplace is fetched from`;\n}\n\nfunction unnameableModelMessage(agent: AgentScopeConfig[\"name\"], model: ModelName): string {\n return `${agent} pins model '${model}', which this contract has no word for — leaving it out would say \"keep the sub-agent's own metadata\", which is a different instruction`;\n}\n\nfunction unwritablePairMessage(skillId: SkillId, agent: string): string {\n return `${skillId} -> ${agent}: a project-scoped skill never reaches a sub-agent that rests at global scope`;\n}\n\n/**\n * Names everything the contract cannot carry at once, not one thing at a time: a sharer who fixes\n * one only to be refused for the next learns nothing the first message could not have told them.\n *\n * The refusal exists because the alternative is worse than a failed command. A payload quietly\n * missing what it could not say still mints an id, and that id installs a configuration nobody\n * chose — with nothing on either side saying so.\n */\nfunction unshareableConfigError(unshareable: string[]): string {\n return [\n \"This installation cannot be shared as it stands — a shared configuration has no way to carry:\",\n ...unshareable.map((line) => ` ${line}`),\n \"Sharing it anyway would mint an id that installs something else.\",\n ].join(\"\\n\");\n}\n\n/** The ref a payload has to carry, and the skills no ref this config holds can account for. */\ntype MarketplaceReading = {\n ref: string | undefined;\n unnameable: string[];\n};\n\n/** Where a configuration fetches its marketplace from, and the name that joins it to skills. */\ntype MarketplaceRecord = Pick<ProjectConfig, \"marketplace\" | \"marketplaceName\">;\n\n/**\n * Whether `record` is the marketplace `skill` came from, and says where it is fetched from. No\n * record, as for a configuration that inherits from none, records nothing.\n *\n * A skill's `origin` is a marketplace's NAME, `marketplace` is the ref it was fetched from, and\n * `marketplaceName` is what joins them — the name the install read out of that repository's own\n * manifest. Without both halves agreeing, the ref would send the receiver to a repository that\n * never served this skill, which is the same silent swap under a different spelling.\n */\nfunction isRecordedMarketplace(record: MarketplaceRecord | undefined, skill: SkillConfig): boolean {\n return record?.marketplace !== undefined && skill.origin === record.marketplaceName;\n}\n\n/**\n * Which marketplace the payload names, decided by the skills that oblige it to name one.\n *\n * A payload names ONE marketplace, and it is this configuration's own whenever a skill shared here\n * comes from it. A project under a global installation from another marketplace carries that\n * one's skills too: they travel, the receiver loading this ref alone leaves them behind, and\n * {@link skillsItsMarketplaceLeavesBehind} names them for the sharer. Only a skill whose\n * marketplace neither configuration records is refused — no payload could ever name where it is.\n */\nfunction readMarketplace(\n config: ProjectConfig,\n skills: SkillConfig[],\n inheritedFrom: MarketplaceRecord | undefined,\n): MarketplaceReading {\n const served = skills.filter((skill) => needsMarketplaceNamed(skill.origin));\n const unaccounted = served.filter(\n (skill) =>\n !isRecordedMarketplace(config, skill) && !isRecordedMarketplace(inheritedFrom, skill),\n );\n if (unaccounted.length > 0) {\n return { ref: undefined, unnameable: unaccounted.map(unnameableOriginMessage) };\n }\n\n const servesItsOwn = served.some((skill) => isRecordedMarketplace(config, skill));\n return { ref: servesItsOwn ? config.marketplace : undefined, unnameable: [] };\n}\n\n/**\n * The plugin skills `payload` carries that the marketplace it names does not serve.\n *\n * An install reads the one marketplace a payload names — the public catalogue when it names none —\n * so a plugin from any other is skipped wherever the id is installed. That is a stopgap rather\n * than a refusal: the id still installs everything else, and the sharer is told which skills it\n * leaves behind. An ejected copy is not a plugin and is not asked about here.\n */\nexport function skillsItsMarketplaceLeavesBehind(\n config: ProjectConfig,\n payload: SeedPayload,\n): SkillId[] {\n const namedMarketplace =\n payload.marketplace === undefined ? DEFAULT_PUBLIC_SOURCE_NAME : config.marketplaceName;\n const isPluginFromElsewhere = (skill: SkillConfig): boolean =>\n skill.origin !== EJECT_SOURCE && skill.origin !== namedMarketplace;\n\n return config.skills\n .filter(isInstalled)\n .filter(isPluginFromElsewhere)\n .map((skill) => skill.id);\n}\n\nfunction unnameableModels(agents: AgentScopeConfig[]): string[] {\n return agents.flatMap((agent) =>\n agent.model !== undefined && !isSeedModel(agent.model)\n ? [unnameableModelMessage(agent.name, agent.model)]\n : [],\n );\n}\n\n/**\n * Turns `config.stack` inside out: it is keyed by sub-agent and this contract is keyed by skill.\n *\n * Rows naming a sub-agent or a skill this configuration does not install are dropped rather than\n * refused, because they are already no part of what is installed — `compile` warns about exactly\n * those and leaves them out of the agents it writes, so carrying them would share more than this\n * project has.\n *\n * A row the config model cannot write is the opposite case and is collected for the refusal: the\n * decoder turns the same pair away on the way back in, so minting it would produce an id that\n * cannot be installed.\n */\nfunction readStack(\n stack: ProjectConfig[\"stack\"],\n skillScopes: Map<SkillId, SkillScope>,\n agentScopes: Map<string, SkillScope>,\n): StackReading {\n const assignments = new Map<SkillId, SeedAssignments>();\n const unwritable: string[] = [];\n\n for (const [agent, agentStack] of typedEntries(stack ?? {})) {\n const agentScope = agentScopes.get(agent);\n if (agentScope === undefined) continue;\n\n for (const { id, preloaded } of typedValues(agentStack).flat()) {\n const skillScope = skillScopes.get(id);\n if (skillScope === undefined) continue;\n\n if (!isScopePairCompatible(skillScope, agentScope)) {\n unwritable.push(unwritablePairMessage(id, agent));\n continue;\n }\n\n const forSkill = assignments.get(id) ?? {};\n forSkill[agent] = seedLoadState(preloaded);\n assignments.set(id, forSkill);\n }\n }\n\n return { assignments, unwritable };\n}\n\nfunction toSeedSkill(skill: SkillConfig, assignments: SeedAssignments | undefined): SeedSkill {\n return {\n // \"eject\" is the project's own copy; anything else is a plugin the marketplace serves, and\n // which marketplace that is has already had to be one the envelope's ref accounts for.\n install: skill.origin === EJECT_SOURCE ? \"eject\" : \"plugin\",\n scope: skill.scope,\n assignments: assignments ?? {},\n };\n}\n\n/**\n * A sub-agent's own row, and it always says `on`.\n *\n * The web app pins `on` only where a person did, because there an agent switched on by its rows is\n * already implied by them. An installed config is not an inference — every sub-agent it names was\n * chosen and has a compiled file on disk — so saying so outright is what carries the one that owns\n * no skill, which is the only thing the agents map can do that assignments cannot.\n */\nfunction toSeedAgent(agent: AgentScopeConfig): SeedAgent {\n return {\n on: true,\n scope: agent.scope,\n ...(agent.model !== undefined && isSeedModel(agent.model) && { model: agent.model }),\n ...(agent.effort !== undefined && { effort: agent.effort }),\n };\n}\n\n/**\n * Turns the installation this directory records into the payload the config store holds, so the\n * CLI can mint an id rather than only consume one.\n *\n * The inverse of `seedToWizardResult` in `seed-to-wizard.ts`, and held to it: a\n * payload minted here and decoded there has to describe the same install. That is why the scope\n * of every skill and sub-agent travels per entry rather than being implied, why the whole stack\n * is carried as per-`(skill, sub-agent)` assignments, and why nothing here leans on a wire default\n * the decoder would have to guess back.\n *\n * What it will not do is share a thinner configuration than the one installed. Anything the\n * contract cannot state is refused by name — see {@link unshareableConfigError} — because the\n * failure mode of the alternative is an id that silently installs something else.\n *\n * `stackId` is always null. A saved config records a stack's expansion and never the id it came\n * from, and the assignments above carry that expansion in full; naming an id this module invented\n * would make the receiver overlay a stack's own preload flags over the curation being shared.\n *\n * `description` is what a resolvable id would have supplied that the assignments do not, so it is\n * carried directly instead. That is the whole of the trade: the sentence travels, the roster the id\n * would have dragged behind it does not.\n *\n * `marketplace` is the one field carried for the payload rather than for an entry, because the\n * receiver loads one catalogue before it reads a single skill row — see {@link readMarketplace}.\n *\n * `carried` arrives as an argument because it is read off disk and this mapping touches none:\n * every id above is resolved by the receiver against a catalogue it already has, and the entries\n * in `carried` are the ones that answer to no catalogue in either direction. Stated rather than\n * defaulted, because a producer that forgot the content is exactly the defect this closed.\n *\n * `inheritedFrom` is the global configuration a project's own inherits from, absent when `config`\n * is the global one. It is read for one thing: the marketplace the inherited skills came from,\n * which this configuration does not record but the global one does.\n */\nexport function configToSeedPayload(\n config: ProjectConfig,\n carried: ContentReading,\n inheritedFrom?: MarketplaceRecord,\n): SeedPayload {\n const skills = config.skills.filter(isInstalled);\n const agents = config.agents.filter(isInstalled);\n const skillScopes = new Map(skills.map((skill) => [skill.id, skill.scope]));\n const agentScopes = new Map<string, SkillScope>(agents.map((agent) => [agent.name, agent.scope]));\n\n const { assignments, unwritable } = readStack(config.stack, skillScopes, agentScopes);\n const marketplace = readMarketplace(config, skills, inheritedFrom);\n\n const unshareable = [\n ...marketplace.unnameable,\n ...unnameableModels(agents),\n ...unwritable,\n ...carried.uncarryable,\n ];\n if (unshareable.length > 0) throw new Error(unshareableConfigError(unshareable));\n\n // Parsed rather than merely assembled, exactly as the web app's encoder is: it makes \"the JSON\n // the store will hold\" literal, and it is the one gate that catches a field whose values have\n // drifted out of the wire's enums since this module last named them.\n //\n // The INSTALLABLE half of the contract, which is the schema the store's POST route declares —\n // the lenient one exists for READING links already out in the world, and this module only ever\n // mints. It refuses nothing the refusal above permits, and that is the point: it is the belt\n // over those braces, so the day this module's own rule and the wire's disagree, the mint fails\n // loudly here instead of minting an id that cannot be installed.\n return installableSeedPayloadSchema.parse({\n v: SEED_VERSION,\n matrixVersion: MATRIX_VERSION,\n stackId: null,\n // Absent rather than empty, for the reason the marketplace ref is: an id is the hash of its\n // body, so a key meaning what its absence already means would remint every ordinary payload.\n ...(config.description !== undefined && { description: config.description }),\n ...(marketplace.ref !== undefined && { marketplace: marketplace.ref }),\n skills: Object.fromEntries(\n skills.map((skill) => [skill.id, toSeedSkill(skill, assignments.get(skill.id))]),\n ),\n // Absent rather than empty, for the reason the marketplace ref is: an id is the hash of its\n // body, so a key meaning what its absence already means would remint every ordinary payload.\n ...(Object.keys(carried.external).length > 0 && { external: carried.external }),\n agents: Object.fromEntries(agents.map((agent) => [agent.name, toSeedAgent(agent)])),\n });\n}\n","import { STATUS_CODES } from \"node:http\";\n\nimport { z } from \"zod\";\n\nimport { SEED_API_URL, SEED_USER_AGENT } from \"./fetch-seed.js\";\nimport { CLI_INVOKE_COMMAND } from \"../../consts.js\";\nimport { truncateText } from \"../../utils/string.js\";\n\nimport type { SeedPayload } from \"@workspace/matrix/seed\";\n\n/**\n * The store answers a stored configuration with its content-addressed id and nothing else.\n * Revalidated rather than read off the response type, because that type describes the worker this\n * CLI was built against and what answers is whatever is deployed.\n */\nconst mintedSchema = z.object({ id: z.string().min(1) });\n\n/**\n * The envelope a refused POST arrives in.\n *\n * `apps/server` registers no `defaultHook` and its own hook narrows only the seed-version case,\n * so every other refused body falls through to `@hono/zod-validator`, which answers\n * `c.json(result, 400)` — the whole `safeParse` result. A `ZodError` has no own enumerable fields\n * beyond `name` and `message`, so `{ success: false, error: { name, message } }` is what crosses\n * the wire. Only that string is read here; everything else is shape to match against.\n */\nconst refusalSchema = z.object({ error: z.object({ message: z.string() }) });\n\n/**\n * What that string really is, which is the part worth knowing: Zod renders its ISSUES into\n * `message` as a JSON document, so the field named `message` is not something to show a person.\n * The sentences the store's own schema wrote are one level further in, and reading them back out\n * is the whole difference between a bare `HTTP 400` and a refusal that names what is wrong.\n */\nconst refusedIssuesSchema = z\n .array(\n z.object({\n path: z.array(z.union([z.string(), z.number()])),\n message: z.string().min(1),\n }),\n )\n .min(1);\n\n/**\n * How much of the store's account of a refusal to quote back.\n *\n * The refusal it really writes is one sentence naming a skill and a sub-agent — around 150\n * characters — so this holds that whole, and a second beside it. Past that a body has stopped\n * being an explanation, and a store replaced by a proxy, a captive portal or something worse must\n * not get to paint the terminal. The same reasoning as `EXCERPT` in `read-piped-payload.ts`, at\n * the length this quote needs: that one bounds unreadable bytes shown so a user recognises them,\n * where this one bounds prose the user has to be able to finish reading.\n *\n * ONE budget for both shapes this route answers in, rather than one apiece, because a budget is a\n * measurement of a ROUTE and both are `POST /configs`. The plain-text refusals it writes are far\n * shorter than a list of schema issues — the longest is `Could not store this config` — so the\n * number sized on the longer shape holds the shorter one with room to spare. `fetch-seed.ts` sets\n * 120 for its own route and neither number travels between them; see the 2026-09-01 finding on\n * quoting a refusal's body.\n */\nconst EXPLANATION_BUDGET = 300;\n\n/** The content type the store's own sentences arrive as — the only one worth reading as prose. */\nconst QUOTABLE_TYPE = \"text/plain\";\n\n/** The status the store spends on a payload naming a version of the contract it does not serve. */\nconst CONTRACT_MISMATCH = 409;\n\n/**\n * What a 409 means from a terminal, said in the CLI's own words rather than the store's.\n *\n * This is the one refusal whose entire purpose is naming a remedy, and the store's body names one\n * a terminal cannot carry out: `refuseAnotherSeedVersion` in `apps/server/src/index.ts` answers\n * `Reload the page: ...`, written for the caller that refusal was designed around — a browser tab\n * minting from a bundle older than the last deploy, for which one reload really is the whole fix.\n * There is no page here. Quoting it would be worse than the bare status it replaced, because the\n * bare status at least does not send the reader somewhere that does not exist.\n *\n * The fact underneath is the same one, and from a terminal it is actionable: `SEED_VERSION` is a\n * `z.literal` imported from `@workspace/matrix/seed` and bundled into this binary, so the version\n * written here travels INSIDE the CLI. Nothing about the configuration, the directory it was read\n * from or the pipe it arrived on can change it, and a newer CLI is the only thing that can.\n *\n * It cannot be the payload's fault by either door: `read-piped-payload.ts` validates a piped\n * configuration against `installableSeedPayloadSchema` before this runs, and `config-to-seed.ts`\n * writes `SEED_VERSION` into one it builds — so a `v` this CLI does not itself name never reaches\n * the wire, and a 409 can only be the two ends disagreeing.\n *\n * It names no sub-command, which is deliberate twice over. `publishSeedConfig` is called by both\n * `share` and `edit --ui`, so there is no one command to re-run; and an invocation written after\n * `@latest` is invisible to `handed-out-invocations.ts`, whose reader matches\n * `${CLI_INVOKE_COMMAND}` followed by a SPACE — so naming one here would hand out a command the\n * gate that runs every handed-out command could not see.\n */\nconst OUT_OF_DATE_AGAINST_STORE =\n `This CLI is out of date against the configuration store: it writes a version of the sharing ` +\n `contract the store does not serve, and that version travels inside the CLI rather than with ` +\n `the configuration. Re-run this command through '${CLI_INVOKE_COMMAND}@latest'.`;\n\nexport type PublishSeedResult = { ok: true; id: string } | { ok: false; error: string };\n\n/**\n * Stores a configuration and returns the id it was given.\n *\n * The outbound half of the boundary `fetchSeedConfig` in `fetch-seed.ts` owns the inbound half\n * of, and it keeps the same posture: every failure is a message rather than a throw.\n * Nothing local has been written by the time this runs, so there is nothing to roll back and the\n * caller's only job is to explain.\n *\n * The id is the payload's own hash, so re-sharing an unchanged configuration returns the id it\n * had — the store spends no write, and a caller can share as often as it likes.\n */\nexport async function publishSeedConfig(payload: SeedPayload): Promise<PublishSeedResult> {\n const url = `${SEED_API_URL}/configs`;\n\n let response: Response;\n try {\n response = await fetch(url, {\n method: \"POST\",\n headers: {\n accept: \"application/json\",\n \"content-type\": \"application/json\",\n // The same signal the fetch half sends: it is the only thing that tells the store a\n // configuration came from the CLI rather than from a browser.\n \"user-agent\": SEED_USER_AGENT,\n },\n body: JSON.stringify(payload),\n });\n } catch {\n return { ok: false, error: `Could not reach ${SEED_API_URL} — check your connection.` };\n }\n\n if (!response.ok) return { ok: false, error: await refusalMessage(response) };\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 minted = mintedSchema.safeParse(body);\n if (!minted.success) {\n // Reporting success here would print an id nobody can install and tell the user to use it.\n return { ok: false, error: \"The configuration store did not return an id for this share.\" };\n }\n\n return { ok: true, id: minted.data.id };\n}\n\n/**\n * A refusal, carrying the store's own account of it wherever there is one to have.\n *\n * The status is never given up, because it is the only thing that separates a bad payload (400)\n * from a stale contract (409), a body over the cap (413), a rate limit (429) and a store that\n * refused the write (503). What it cannot do is say WHY a payload was bad, and the store already\n * knows: a refused POST answers with the issues its own schema raised, in plain English, naming\n * the skill and the sub-agent. Discarding that cost a real user a debugging session for a fault\n * the store had already described.\n *\n * Read for every status rather than for 400 alone — except the one status whose body is answering\n * somebody else. Which statuses carry which shape is the deployed worker's business, so both\n * shapes are tried against every body, and one that is neither degrades to the status anyway.\n */\nasync function refusalMessage(response: Response): Promise<string> {\n const refused = `Sharing this configuration failed (HTTP ${response.status}).`;\n\n // Branched on the status rather than on the body, because the status is the whole of the fact:\n // what a 409 says is that the two ends name different contract versions, and no body the store\n // could send makes that any more actionable from a terminal than the sentence above does.\n if (response.status === CONTRACT_MISMATCH) return `${refused} ${OUT_OF_DATE_AGAINST_STORE}`;\n\n const explanation = explanationOf(response, await refusalBody(response));\n\n return explanation === undefined ? refused : `${refused} The store said: ${explanation}`;\n}\n\n/**\n * Whatever the store sent, as text and unjudged.\n *\n * Deliberately NOT gated on the content type the way the function of this name in `fetch-seed.ts`\n * is, and the difference is the routes rather than a disagreement: that one answers every refusal\n * with `c.text`, where this one answers in two shapes under two types — the validator's envelope\n * as `application/json`, the worker's own sentences as `text/plain`. A gate here would throw one\n * of them away. It belongs on the prose arm alone, which is where {@link arrivedAsText} is.\n *\n * Nothing below this line is worth failing over: the message being assembled is already a\n * failure, and a body that cannot be read is one more thing the status will have to cover on its\n * own. Draining the stream can throw in its own right — a connection dropped mid-body — which is\n * why this is a `try` around the read.\n */\nasync function refusalBody(response: Response): Promise<string | undefined> {\n try {\n return await response.text();\n } catch {\n return undefined;\n }\n}\n\n/** `JSON.parse` as a value rather than a throw, since a body that is not JSON is expected here. */\nfunction jsonOf(text: string): unknown {\n try {\n return JSON.parse(text);\n } catch {\n return undefined;\n }\n}\n\n/**\n * The store's account of a refusal, in whichever of the two shapes this route answers in.\n *\n * The envelope is read first because it is the more specific of the two, and the order costs\n * nothing either way: an envelope arrives as JSON and could never satisfy the prose arm's\n * content-type gate, and prose has no shape for `refusalSchema` to match.\n *\n * The budget is spent here rather than inside either arm, so that whatever leaves this module is\n * bounded once, by one number belonging to one route.\n *\n * The body travels beside the response it came from rather than being taken off it, because by\n * the time this runs the stream has been drained and a second read would answer nothing.\n */\nfunction explanationOf(response: Response, body: string | undefined): string | undefined {\n if (body === undefined) return undefined;\n\n const said = schemaIssuesIn(body) ?? quotableProseIn(response, body);\n\n return said === undefined ? undefined : truncateText(said, EXPLANATION_BUDGET);\n}\n\n/** The sentences the store's own schema wrote, read back out of the validator's envelope. */\nfunction schemaIssuesIn(body: string): string | undefined {\n const refusal = refusalSchema.safeParse(jsonOf(body));\n if (!refusal.success) return undefined;\n\n const issues = refusedIssuesSchema.safeParse(jsonOf(refusal.data.error.message));\n if (!issues.success) return undefined;\n\n return issues.data.map(sentenceOf).join(\"; \");\n}\n\n/**\n * The store's own words, where the wire says the store wrote them and they say something.\n *\n * The three refusals this route writes with `c.text` — 413, 429 and 503 — reach a terminal by no\n * other arm, and before this they reached it by none at all. Two of the three are then discarded\n * again by {@link restatesItsOwnStatus}, which is the whole shape of the rule: what earns a quote\n * is not a body, it is a body that adds something to the status printed beside it.\n */\nfunction quotableProseIn(response: Response, body: string): string | undefined {\n if (!arrivedAsText(response)) return undefined;\n\n const said = body.trim();\n if (said === \"\") return undefined;\n if (restatesItsOwnStatus(said, response.status)) return undefined;\n\n return said;\n}\n\n/**\n * Whether what arrived is the store speaking, as far as the wire says it is.\n *\n * `c.text(...)` is how this route writes every refusal that is not the validator's, so `text/plain`\n * is the shape the store's own words take. What arrives as anything else did not come from it: a\n * proxy, a WAF, a captive portal or a gateway answering in its place — and their answer is markup\n * rather than prose, which quoted into a terminal is a screenful of tags that explains nothing and\n * buries the status that does.\n *\n * A sentence has no shape to validate, so the wire's own statement of what it sent is the only\n * discriminator prose has — where the envelope beside it has `refusalSchema`, a shape a foreign\n * body fails to be. It is not proof, since a hostile answer may claim any type it likes, which is\n * what {@link EXPLANATION_BUDGET} is for and why what survives both is attributed to the store\n * rather than spoken in the CLI's own voice.\n */\nfunction arrivedAsText(response: Response): boolean {\n return (response.headers.get(\"content-type\") ?? \"\").startsWith(QUOTABLE_TYPE);\n}\n\n/**\n * Whether the body says only what the status line printed beside it has already said.\n *\n * `node:http`'s `STATUS_CODES` is the registry of reason phrases a status line carries, so holding\n * a body against it is a rule about the whole class rather than a list of the statuses it happens\n * to catch today. It catches two: `Too many requests` is 429's `Too Many Requests` re-cased and\n * `Payload too large` is 413's, so neither is named here and a fourth refusal written the same way\n * is suppressed the day it ships. `Could not store this config` is not `Service Unavailable`, which\n * is why the one refusal on this route that names a cause is the one that survives.\n *\n * Compared case-insensitively, and against the trimmed body, because the worker writes sentence\n * case where the registry writes title case and that is not a difference in meaning.\n */\nfunction restatesItsOwnStatus(said: string, status: number): boolean {\n const reason = STATUS_CODES[status];\n\n return reason !== undefined && said.toLowerCase() === reason.toLowerCase();\n}\n\n/** One issue as it arrives, read off the schema above so the two cannot drift apart. */\ntype RefusedIssue = z.infer<typeof refusedIssuesSchema>[number];\n\n/**\n * One issue, path first — the same rendering `formatZodIssue` in `lib/schema-validator.ts` gives\n * a local one, and deliberately the same sentence a user sees from `share --stdin`.\n *\n * It cannot call that function: this issue was read off a wire and is a plain object, where\n * `formatZodIssue` takes a `z.ZodIssue`, a discriminated union nothing arriving over HTTP can be\n * narrowed to without a cast. The path is what the sentence itself cannot carry — the store's\n * message names the sub-agent and the path names the skill.\n */\nfunction sentenceOf(issue: RefusedIssue): string {\n const path = issue.path.join(\".\");\n return path === \"\" ? issue.message : `${path}: ${issue.message}`;\n}\n"],"mappings":"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","names":["path"]}