agents-inc 0.160.0 → 0.161.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 (135) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/README.md +1 -1
  3. package/dist/{chunk-PEHYVSJG.js → chunk-264XDRU7.js} +2 -2
  4. package/dist/{chunk-LJ6V54NR.js → chunk-2MPXMJ2O.js} +7 -7
  5. package/dist/{chunk-GWPKIXBM.js → chunk-3H42U56X.js} +2 -2
  6. package/dist/{chunk-CWQLRKWB.js → chunk-3M75HVIM.js} +3 -3
  7. package/dist/{chunk-YKRPWZ3G.js → chunk-3TM4FHTG.js} +2 -2
  8. package/dist/{chunk-C5P7RUDR.js → chunk-5DWDT6GM.js} +115 -96
  9. package/dist/chunk-5DWDT6GM.js.map +1 -0
  10. package/dist/{chunk-4APXK7ZY.js → chunk-5MML3K36.js} +2 -2
  11. package/dist/{chunk-J7Q5VYR7.js → chunk-6PVWDTEM.js} +12 -12
  12. package/dist/{chunk-LX7UXZBN.js → chunk-A2NA377T.js} +6 -6
  13. package/dist/{chunk-IWUFZ6NR.js → chunk-ADDYIMWN.js} +3 -3
  14. package/dist/{chunk-OUG6TCQ4.js → chunk-AMZO4YJK.js} +10786 -18653
  15. package/dist/chunk-AMZO4YJK.js.map +1 -0
  16. package/dist/{chunk-7JQPIMKD.js → chunk-AO6DXJUK.js} +3 -3
  17. package/dist/{chunk-CICB4AKA.js → chunk-B3YSTZZC.js} +3 -3
  18. package/dist/{chunk-XDNGMXOZ.js → chunk-B7YTQVAF.js} +4 -4
  19. package/dist/{chunk-XX657S4U.js → chunk-BLGETWYI.js} +6 -11
  20. package/dist/{chunk-XX657S4U.js.map → chunk-BLGETWYI.js.map} +1 -1
  21. package/dist/{chunk-ITEJARWI.js → chunk-BRHU6J3C.js} +3 -3
  22. package/dist/{chunk-AU5FS3QK.js → chunk-DGXW2ZFY.js} +3 -3
  23. package/dist/{chunk-K6MQV6SK.js → chunk-DHRW3MDM.js} +3 -3
  24. package/dist/{chunk-OJIQOVWB.js → chunk-DTCUZL7S.js} +2 -2
  25. package/dist/{chunk-Q2HB5SWU.js → chunk-EEFTUZHZ.js} +5 -5
  26. package/dist/{chunk-6CP3CLDE.js → chunk-EERGAAGE.js} +4 -4
  27. package/dist/{chunk-EPBUWEW4.js → chunk-EQSMVZGS.js} +10 -10
  28. package/dist/{chunk-5K33RJ7Z.js → chunk-EY7Z34Y4.js} +15 -15
  29. package/dist/{chunk-IJ7GWQUR.js → chunk-F6LS2BQD.js} +11 -11
  30. package/dist/{chunk-SITF5EZM.js → chunk-HB3YIAFD.js} +2 -2
  31. package/dist/{chunk-XSULY25W.js → chunk-LZPRLHUE.js} +9 -9
  32. package/dist/{chunk-RJ3JYZJ7.js → chunk-MED6GNV3.js} +288 -203
  33. package/dist/chunk-MED6GNV3.js.map +1 -0
  34. package/dist/chunk-N6CILY5A.js +35 -0
  35. package/dist/chunk-N6CILY5A.js.map +1 -0
  36. package/dist/{chunk-VI4X5DN5.js → chunk-ODUACQLV.js} +6 -6
  37. package/dist/{chunk-JQDN7KAZ.js → chunk-QKMT6OOP.js} +2 -2
  38. package/dist/{chunk-PWPKZNCV.js → chunk-SX57ZIGM.js} +4 -4
  39. package/dist/{chunk-PIUCYRLP.js → chunk-T4RVCFWN.js} +3 -3
  40. package/dist/{chunk-4VVKVOOP.js → chunk-UMYEY6BA.js} +2 -2
  41. package/dist/{chunk-X5PLVOJS.js → chunk-W2RXRWDB.js} +2 -2
  42. package/dist/{chunk-DEWI5HDF.js → chunk-WVCF7KFV.js} +5 -5
  43. package/dist/chunk-XA4SWA2Z.js +591 -0
  44. package/dist/chunk-XA4SWA2Z.js.map +1 -0
  45. package/dist/{chunk-SLB2SFTX.js → chunk-YOVUXONB.js} +9 -19
  46. package/dist/chunk-YOVUXONB.js.map +1 -0
  47. package/dist/chunk-YSQ76LWG.js +8734 -0
  48. package/dist/chunk-YSQ76LWG.js.map +1 -0
  49. package/dist/{chunk-OJR3ASZI.js → chunk-ZQZHDYHQ.js} +7 -7
  50. package/dist/commands/build/marketplace.js +7 -7
  51. package/dist/commands/build/plugins.js +7 -7
  52. package/dist/commands/compile.js +13 -13
  53. package/dist/commands/doctor.js +12 -12
  54. package/dist/commands/edit.js +44 -44
  55. package/dist/commands/eject.js +10 -10
  56. package/dist/commands/init.js +36 -36
  57. package/dist/commands/list.js +8 -8
  58. package/dist/commands/new/marketplace.js +7 -7
  59. package/dist/commands/search.js +10 -10
  60. package/dist/commands/share.js +10 -9
  61. package/dist/commands/share.js.map +1 -1
  62. package/dist/commands/uninstall.js +11 -11
  63. package/dist/commands/update.js +6 -6
  64. package/dist/components/common/removal-plan-confirm.js +2 -2
  65. package/dist/components/common/select-list.js +2 -2
  66. package/dist/components/wizard/category-grid.js +4 -4
  67. package/dist/components/wizard/checkbox-grid.js +4 -4
  68. package/dist/components/wizard/domain-selection.js +9 -9
  69. package/dist/components/wizard/run-wizard-session.js +26 -26
  70. package/dist/components/wizard/scroll-affordance.js +2 -2
  71. package/dist/components/wizard/skill-agent-summary.js +5 -5
  72. package/dist/components/wizard/source-grid.js +5 -5
  73. package/dist/components/wizard/stack-selection.js +7 -7
  74. package/dist/components/wizard/step-agents.js +8 -8
  75. package/dist/components/wizard/step-build.js +7 -7
  76. package/dist/components/wizard/step-confirm.js +9 -9
  77. package/dist/components/wizard/step-sources.js +8 -8
  78. package/dist/components/wizard/step-stack.js +8 -8
  79. package/dist/components/wizard/summary-panel.js +8 -8
  80. package/dist/components/wizard/toast.js +2 -2
  81. package/dist/components/wizard/wizard-layout.js +12 -12
  82. package/dist/components/wizard/wizard-tabs.js +2 -2
  83. package/dist/components/wizard/wizard.js +25 -25
  84. package/dist/hooks/init.js +36 -36
  85. package/dist/load-agent-defs-LDSND43G.js +13 -0
  86. package/dist/recompile-project-agents-GQLODH24.js +17 -0
  87. package/dist/{source-loader-CDYH2NIM.js → source-loader-TSF5VS6V.js} +4 -4
  88. package/dist/stores/wizard-store.js +4 -4
  89. package/package.json +9 -4
  90. package/dist/chunk-5KB4I5J7.js +0 -262
  91. package/dist/chunk-5KB4I5J7.js.map +0 -1
  92. package/dist/chunk-C5P7RUDR.js.map +0 -1
  93. package/dist/chunk-KCN5N3PB.js +0 -169
  94. package/dist/chunk-KCN5N3PB.js.map +0 -1
  95. package/dist/chunk-OUG6TCQ4.js.map +0 -1
  96. package/dist/chunk-RJ3JYZJ7.js.map +0 -1
  97. package/dist/chunk-SLB2SFTX.js.map +0 -1
  98. package/dist/chunk-VH6P7UGF.js +0 -254
  99. package/dist/chunk-VH6P7UGF.js.map +0 -1
  100. package/dist/load-agent-defs-KWHG7P7G.js +0 -13
  101. package/dist/recompile-project-agents-5FTDDHX7.js +0 -17
  102. /package/dist/{chunk-PEHYVSJG.js.map → chunk-264XDRU7.js.map} +0 -0
  103. /package/dist/{chunk-LJ6V54NR.js.map → chunk-2MPXMJ2O.js.map} +0 -0
  104. /package/dist/{chunk-GWPKIXBM.js.map → chunk-3H42U56X.js.map} +0 -0
  105. /package/dist/{chunk-CWQLRKWB.js.map → chunk-3M75HVIM.js.map} +0 -0
  106. /package/dist/{chunk-YKRPWZ3G.js.map → chunk-3TM4FHTG.js.map} +0 -0
  107. /package/dist/{chunk-4APXK7ZY.js.map → chunk-5MML3K36.js.map} +0 -0
  108. /package/dist/{chunk-J7Q5VYR7.js.map → chunk-6PVWDTEM.js.map} +0 -0
  109. /package/dist/{chunk-LX7UXZBN.js.map → chunk-A2NA377T.js.map} +0 -0
  110. /package/dist/{chunk-IWUFZ6NR.js.map → chunk-ADDYIMWN.js.map} +0 -0
  111. /package/dist/{chunk-7JQPIMKD.js.map → chunk-AO6DXJUK.js.map} +0 -0
  112. /package/dist/{chunk-CICB4AKA.js.map → chunk-B3YSTZZC.js.map} +0 -0
  113. /package/dist/{chunk-XDNGMXOZ.js.map → chunk-B7YTQVAF.js.map} +0 -0
  114. /package/dist/{chunk-ITEJARWI.js.map → chunk-BRHU6J3C.js.map} +0 -0
  115. /package/dist/{chunk-AU5FS3QK.js.map → chunk-DGXW2ZFY.js.map} +0 -0
  116. /package/dist/{chunk-K6MQV6SK.js.map → chunk-DHRW3MDM.js.map} +0 -0
  117. /package/dist/{chunk-OJIQOVWB.js.map → chunk-DTCUZL7S.js.map} +0 -0
  118. /package/dist/{chunk-Q2HB5SWU.js.map → chunk-EEFTUZHZ.js.map} +0 -0
  119. /package/dist/{chunk-6CP3CLDE.js.map → chunk-EERGAAGE.js.map} +0 -0
  120. /package/dist/{chunk-EPBUWEW4.js.map → chunk-EQSMVZGS.js.map} +0 -0
  121. /package/dist/{chunk-5K33RJ7Z.js.map → chunk-EY7Z34Y4.js.map} +0 -0
  122. /package/dist/{chunk-IJ7GWQUR.js.map → chunk-F6LS2BQD.js.map} +0 -0
  123. /package/dist/{chunk-SITF5EZM.js.map → chunk-HB3YIAFD.js.map} +0 -0
  124. /package/dist/{chunk-XSULY25W.js.map → chunk-LZPRLHUE.js.map} +0 -0
  125. /package/dist/{chunk-VI4X5DN5.js.map → chunk-ODUACQLV.js.map} +0 -0
  126. /package/dist/{chunk-JQDN7KAZ.js.map → chunk-QKMT6OOP.js.map} +0 -0
  127. /package/dist/{chunk-PWPKZNCV.js.map → chunk-SX57ZIGM.js.map} +0 -0
  128. /package/dist/{chunk-PIUCYRLP.js.map → chunk-T4RVCFWN.js.map} +0 -0
  129. /package/dist/{chunk-4VVKVOOP.js.map → chunk-UMYEY6BA.js.map} +0 -0
  130. /package/dist/{chunk-X5PLVOJS.js.map → chunk-W2RXRWDB.js.map} +0 -0
  131. /package/dist/{chunk-DEWI5HDF.js.map → chunk-WVCF7KFV.js.map} +0 -0
  132. /package/dist/{chunk-OJR3ASZI.js.map → chunk-ZQZHDYHQ.js.map} +0 -0
  133. /package/dist/{load-agent-defs-KWHG7P7G.js.map → load-agent-defs-LDSND43G.js.map} +0 -0
  134. /package/dist/{recompile-project-agents-5FTDDHX7.js.map → recompile-project-agents-GQLODH24.js.map} +0 -0
  135. /package/dist/{source-loader-CDYH2NIM.js.map → source-loader-TSF5VS6V.js.map} +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/cli/lib/seed/external-skills.ts","../../../node_modules/hono/dist/utils/cookie.js","../../../node_modules/hono/dist/client/utils.js","../../../node_modules/hono/dist/client/client.js","../../api/src/client.ts","../src/cli/lib/seed/fetch-seed.ts"],"sourcesContent":["import path from \"path\";\n\nimport { seedExternalSkillSchema } from \"@workspace/matrix/seed\";\n\nimport { GITHUB_SOURCE, LOCAL_SKILLS_PATH, STANDARD_FILES } from \"../../consts.js\";\nimport { resolveInstallPaths } from \"../installation/install-base-dir.js\";\nimport { readSkillMetadata } from \"../loading/loader.js\";\nimport { getCategoryDomain } from \"../matrix/matrix-provider.js\";\nimport { claimSlug } from \"../matrix/skill-resolution.js\";\nimport { validateSkillPath } from \"../skills/skill-copier.js\";\nimport {\n injectForkedFromMetadata,\n readLocalSkillMetadata,\n writeMetadataYaml,\n} from \"../skills/skill-metadata.js\";\nimport { computeFileHash } from \"../versioning.js\";\nimport { glob, readFile, writeFile } from \"../../utils/fs.js\";\nimport { typedEntries } from \"../../utils/typed-object.js\";\n\nimport type { SkillScope } from \"../../types/config.js\";\nimport type { Domain, MergedSkillsMatrix, ResolvedSkill } from \"../../types/matrix.js\";\nimport type { CategoryPath, SkillId, SkillSlug } from \"../../types/skills.js\";\nimport type { ForkedFromMetadata, LocalSkillMetadata } from \"../skills/skill-metadata.js\";\nimport type {\n SeedExternalSkill,\n SeedPayload,\n SeedSkill,\n SeedSkillTree,\n} from \"@workspace/matrix/seed\";\n\n/**\n * One skill the payload carries rather than names, seated and ready to be written.\n *\n * `skillDir` and `domain` are resolved once, where the checks that make them safe already are:\n * the directory has to be the one the catalogue entry points at, because that is what tells the\n * copy step this skill is already where it belongs, and the domain is what the category guard has\n * just proved this catalogue declares.\n */\nexport type ExternalSkillInstall = {\n id: SkillId;\n scope: SkillScope;\n skill: SeedExternalSkill;\n domain: Domain;\n skillDir: string;\n};\n\n/** One external entry with the skill row that selected it — what the payload says about it. */\ntype SelectedExternal = { id: SkillId; skill: SeedExternalSkill; entry: SeedSkill };\n\n/**\n * Names every carried skill a payload asks to install as a plugin, not just the first.\n *\n * There is nothing to install them FROM: the payload is the source, so no marketplace serves\n * these ids. Coercing them to eject would install something the payload did not ask for, under a\n * mode the sharer's own screen still shows as plugin — so the ids are named and the run stops.\n */\nfunction pluginInstallError(ids: SkillId[]): string {\n return [\n \"This configuration cannot be installed: these skills travel inside it, so no marketplace \" +\n \"serves them and they cannot be installed as plugins:\",\n ...ids.map((id) => ` ${id}`),\n \"Re-share it with each skill above set to eject, which is the only way a carried skill installs.\",\n ].join(\"\\n\");\n}\n\n/**\n * The external entries this selection actually names.\n *\n * Presence in `skills` is selection and `external` is only where the bytes are, so content nobody\n * picked installs nothing — seating it would put a skill in the catalogue no part of the\n * configuration asked for.\n */\nfunction selectedExternals(payload: SeedPayload): SelectedExternal[] {\n return typedEntries<SkillId, SeedExternalSkill>(payload.external ?? {}).flatMap(([id, skill]) => {\n const entry = payload.skills[id];\n return entry ? [{ id, skill, entry }] : [];\n });\n}\n\nfunction askedForAsPlugin(externals: SelectedExternal[]): SkillId[] {\n return externals.filter(({ entry }) => entry.install !== \"eject\").map(({ id }) => id);\n}\n\n/**\n * Boundary cast: a carried skill's id is minted at intake and belongs to no generated union,\n * which is exactly what makes it external. It is its own slug too — a skill outside every\n * catalogue has no shorter name anything else would recognise, and the sending side says the same.\n */\nfunction externalSlug(id: SkillId): SkillSlug {\n return id as SkillSlug;\n}\n\n/** The repository's owner as a handle, which is all the authorship a carried skill records. */\nfunction skillAuthor(repo: string): string {\n const [owner = repo] = repo.split(\"/\");\n return `@${owner}`;\n}\n\n/** The repository ref a carried skill's provenance records, in the form every other ref wears. */\nfunction repoRef(repo: string): string {\n return `${GITHUB_SOURCE.GITHUB_PREFIX}${repo}`;\n}\n\n/** Where a carried skill's directory goes: under the skills directory of the scope it names. */\nfunction externalSkillDir(id: SkillId, scope: SkillScope, projectDir: string): string {\n return path.join(resolveInstallPaths(projectDir, scope).skillsDir, id);\n}\n\n/**\n * The catalogue entry a carried skill becomes on arrival.\n *\n * It declares no relationships and is named by none, which is honest: nothing outside the\n * catalogue can say what this skill conflicts with, and nothing inside it knows the skill exists.\n */\nfunction externalCatalogueEntry(install: ExternalSkillInstall): ResolvedSkill {\n return {\n id: install.id,\n slug: externalSlug(install.id),\n displayName: install.skill.displayName,\n description: install.skill.description,\n // Boundary cast held by the guard above it: the category was confirmed against the catalogue\n // the payload names, and this one has just been shown to declare it too.\n category: install.skill.categoryId as CategoryPath,\n author: skillAuthor(install.skill.repo),\n path: `${LOCAL_SKILLS_PATH}/${install.id}/`,\n conflictsWith: [],\n requires: [],\n alternatives: [],\n discourages: [],\n // Local and custom for the same reason: the bytes are on this machine and nowhere else, and\n // the skill was authored outside the vocabulary this catalogue ships.\n local: true,\n custom: true,\n localPath: install.skillDir,\n };\n}\n\n/**\n * Seats one carried skill in the catalogue, or leaves it unseated.\n *\n * A skill is PLACED in the taxonomy and never extends it, so a category this catalogue has no\n * definition for belongs to no domain, renders in no tab and reaches no sub-agent. Left unseated,\n * the id falls to the decode's own skip, which reports it by name.\n */\nfunction seatExternalSkill(\n { id, skill, entry }: SelectedExternal,\n matrix: MergedSkillsMatrix,\n projectDir: string,\n): ExternalSkillInstall[] {\n const domain = getCategoryDomain(skill.categoryId);\n if (domain === undefined) return [];\n\n const install: ExternalSkillInstall = {\n id,\n skill,\n domain,\n scope: entry.scope,\n skillDir: externalSkillDir(id, entry.scope, projectDir),\n };\n\n matrix.skills[id] = externalCatalogueEntry(install);\n // Completes the map over the matrix: 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 * @throws {Error} If any carried skill asks to be installed as a plugin — see\n * {@link pluginInstallError}.\n */\nexport function registerExternalSkills(\n payload: SeedPayload,\n matrix: MergedSkillsMatrix,\n projectDir: string,\n): ExternalSkillInstall[] {\n const externals = selectedExternals(payload);\n const asPlugin = askedForAsPlugin(externals);\n\n if (asPlugin.length > 0) throw new Error(pluginInstallError(asPlugin));\n\n return externals.flatMap((external) => seatExternalSkill(external, matrix, projectDir));\n}\n\n/**\n * Writes each carried skill's directory where its own entry said, and registers it on disk.\n *\n * Three things have to be true afterwards, and each is a separate act: the files are there, the\n * skill answers to the id the configuration recorded, and a metadata.yaml describes it well\n * enough for the next `edit`, `compile` or `list` to find it again. The seat above lasts one run;\n * this is what makes the install survive.\n */\nexport async function writeExternalSkills(installs: ExternalSkillInstall[]): Promise<void> {\n for (const install of installs) {\n await writeSkillTree(install);\n await writeSkillManifest(install);\n await registerSkillOnDisk(install);\n }\n}\n\n/**\n * The directory as the payload holds it, keys and all.\n *\n * The keys came off the wire, so a payload may ask for any path it likes — including one that\n * climbs out of the skill's own directory. They answer to the same guard a marketplace's own\n * paths do.\n */\nasync function writeSkillTree(install: ExternalSkillInstall): Promise<void> {\n for (const [relativePath, contents] of Object.entries(install.skill.files)) {\n const filePath = path.join(install.skillDir, relativePath);\n validateSkillPath(filePath, install.skillDir, relativePath);\n await writeFile(filePath, contents);\n }\n}\n\n/** The frontmatter block at the head of a SKILL.md, and the `name` field inside it. */\nconst FRONTMATTER_BLOCK = /^---\\r?\\n([\\s\\S]*?)\\r?\\n---/;\nconst NAME_FIELD = /^name:.*$/m;\n\n/**\n * Names the skill by the id it installs under.\n *\n * Every loader reads a skill's id off this one field, and a compiled sub-agent references the id\n * the configuration recorded — the one minted at intake, which is also this directory's name. The\n * repository the skill came from knew about neither, so left as it was written the two never\n * meet: the sub-agent names a skill Claude Code knows as something else, and the next load\n * registers an id no configuration carries.\n *\n * Only the name. Everything else in the block is the author's and travels untouched.\n */\nfunction withInstalledName(manifest: string, install: ExternalSkillInstall): string {\n const named = `name: ${install.id}`;\n const block = FRONTMATTER_BLOCK.exec(manifest);\n\n // A manifest with no frontmatter at all describes no skill to Claude Code either. The payload\n // carries both fields one needs, so it is given one rather than installed unreadable.\n if (!block) {\n return `---\\n${named}\\ndescription: ${install.skill.description}\\n---\\n\\n${manifest}`;\n }\n\n const [whole, fields = \"\"] = block;\n const renamed = NAME_FIELD.test(fields)\n ? fields.replace(NAME_FIELD, named)\n : `${named}\\n${fields}`;\n\n // The block is anchored at the head of the file, so what follows it is the rest verbatim.\n return `---\\n${renamed}\\n---${manifest.slice(whole.length)}`;\n}\n\nasync function writeSkillManifest(install: ExternalSkillInstall): Promise<void> {\n const manifestPath = path.join(install.skillDir, STANDARD_FILES.SKILL_MD);\n await writeFile(manifestPath, withInstalledName(await readFile(manifestPath), install));\n}\n\n/**\n * What the payload confirmed, over what the repository shipped, over what neither says.\n *\n * The order is the whole of it. The taxonomy is the placement the user chose against the\n * catalogue this configuration names, and the repository's own idea of where its skill belongs\n * answers to a taxonomy nobody here shares — so that is written over the file. Everything else\n * the repository wrote is kept, because its author knows more about their skill than a default\n * does.\n *\n * The defaults underneath exist because `doctor` validates every installed metadata.yaml, and a\n * file this command writes that that command reports as an error is the CLI disagreeing with\n * itself — in a file the user cannot fix, since the skill is somebody else's repository. Neither\n * is invented: the authorship is the repository's owner, and the usage line is the same words the\n * stack loader already writes for every skill reference it has nothing more specific for.\n */\nfunction externalSkillMetadata(\n install: ExternalSkillInstall,\n shipped: LocalSkillMetadata | null,\n): LocalSkillMetadata {\n return {\n author: skillAuthor(install.skill.repo),\n usageGuidance: `Use when working with ${install.skill.displayName}`,\n ...shipped,\n displayName: install.skill.displayName,\n slug: install.id,\n category: install.skill.categoryId,\n domain: install.domain,\n cliDescription: install.skill.description,\n custom: true,\n };\n}\n\n/**\n * Registers the skill on disk, where the next command will look for it.\n *\n * `forkedFrom` is stamped through the one writer that stamps it, because it is the package's\n * single answer to \"did the CLI put this directory here?\" — `uninstall` reads it to decide what it\n * may delete, and the producer reads it to decide what the round trip owns. A carried skill IS the\n * round trip's; a skill the user wrote by hand is not, and carries nothing.\n *\n * The repository AND the directory inside it, because this is the only record of where these bytes\n * came from. Sharing this installation has to rebuild the entry the payload carried, and a\n * repository alone cannot say which of its directories travelled — see {@link readCarriedSkills}.\n */\nasync function registerSkillOnDisk(install: ExternalSkillInstall): Promise<void> {\n const metadataPath = path.join(install.skillDir, STANDARD_FILES.METADATA_YAML);\n const shipped = await readLocalSkillMetadata(install.skillDir);\n\n await writeMetadataYaml(metadataPath, externalSkillMetadata(install, shipped));\n await injectForkedFromMetadata(\n install.skillDir,\n install.id,\n await computeFileHash(path.join(install.skillDir, STANDARD_FILES.SKILL_MD)),\n { source: repoRef(install.skill.repo), path: install.skill.path },\n );\n}\n\n/**\n * One installed skill directory the round trip owns, and what its install recorded about it.\n *\n * Read by the caller rather than here: whether a directory is the CLI's copy or the user's own\n * work is a question about ownership, which `installation-payload.ts` already asks of every entry\n * before anything else. This module answers only the next one — whether the bytes have to travel.\n */\nexport type OwnedSkillDir = { id: string; skillDir: string; provenance: ForkedFromMetadata };\n\n/**\n * What one installation carries rather than names.\n *\n * The same shape the mapper's other readings wear: what can travel, and the lines naming what\n * cannot. Both halves matter — a payload quietly missing content it could not read still mints an\n * id, and that id installs a configuration nobody chose.\n */\nexport type ContentReading = {\n /** Skill id -> the entry a receiver seats it from. Keyed exactly as the wire keys `external`. */\n external: Record<string, SeedExternalSkill>;\n /** One line per skill whose content this installation cannot carry, for the refusal. */\n uncarryable: string[];\n};\n\n/** What one owned directory turns out to carry: content, a reason it cannot, or nothing. */\ntype CarriedRead =\n | { carries: \"content\"; id: string; skill: SeedExternalSkill }\n | { carries: \"nothing\" }\n | { carries: \"unshareable\"; line: string };\n\nfunction unnameableRepoMessage(id: string): string {\n return `${id} travels inside a shared configuration, and this installation does not record the repository its content came from`;\n}\n\nfunction uncarryableContentMessage(id: string, reason: string): string {\n return `${id} travels inside a shared configuration, and ${reason}`;\n}\n\n/**\n * The inverse of {@link repoRef}: the repository a ref names, or nothing when it names none this\n * contract can state.\n *\n * Provenance is written as a ref because that is the form every other source in a configuration\n * wears; the wire wants GitHub's own `owner/name`. Any other ref is a repository this contract has\n * no word for, which is a refusal rather than something to guess at.\n */\nfunction repoFromRef(ref: string | undefined): string | undefined {\n if (ref === undefined || !ref.startsWith(GITHUB_SOURCE.GITHUB_PREFIX)) return undefined;\n return ref.slice(GITHUB_SOURCE.GITHUB_PREFIX.length);\n}\n\n/** Every file under the skill, keyed by its path relative to it — dotfiles and nesting included. */\nasync function readSkillTree(skillDir: string): Promise<SeedSkillTree> {\n const files = await glob(\"**/*\", skillDir, { dot: true });\n const entries = await Promise.all(\n files.map(async (file) => [file, await readFile(path.join(skillDir, file))] as const),\n );\n return Object.fromEntries(entries);\n}\n\n/**\n * Rebuilds the entry a carried skill arrived as, from the directory the install wrote.\n *\n * The bytes as they stand rather than as they arrived: the manifest was renamed to the id this\n * install recorded, and a user may have edited the skill since. Both are what is installed here,\n * and what is installed here is what a share carries.\n *\n * Validated against the contract's own schema rather than by rules restated here — that is what\n * makes the weight limit, the manifest requirement and every field's shape one definition rather\n * than two that can drift.\n */\nasync function readCarriedSkill({ id, skillDir, provenance }: OwnedSkillDir): Promise<CarriedRead> {\n // The directory is what marks a skill as one no catalogue can resolve. Without it there is a\n // catalogue behind this id, so the receiver installs it from there and the bytes stay home.\n if (provenance.path === undefined) return { carries: \"nothing\" };\n\n const repo = repoFromRef(provenance.source);\n if (repo === undefined) return { carries: \"unshareable\", line: unnameableRepoMessage(id) };\n\n const described = await readSkillMetadata(path.join(skillDir, STANDARD_FILES.METADATA_YAML));\n if (!described.usable) {\n return { carries: \"unshareable\", line: uncarryableContentMessage(id, described.reason) };\n }\n\n const parsed = seedExternalSkillSchema.safeParse({\n displayName: described.metadata.displayName,\n description: described.metadata.cliDescription,\n categoryId: described.metadata.category,\n repo,\n path: provenance.path,\n files: await readSkillTree(skillDir),\n });\n if (!parsed.success) {\n const reason = parsed.error.issues.map((issue) => issue.message).join(\"; \");\n return { carries: \"unshareable\", line: uncarryableContentMessage(id, reason) };\n }\n\n return { carries: \"content\", id, skill: parsed.data };\n}\n\n/**\n * What a set of owned skill directories carries, and what it cannot.\n *\n * The mirror of {@link registerExternalSkills}: that seats an entry a payload carried and writes\n * its bytes, this reads those bytes back into the entry a payload carries. Every other id in a\n * configuration is resolved by the receiver against a catalogue it already has, so its content has\n * nothing to add; an added skill answers to no catalogue in either direction, and a share that\n * named it without carrying it would mint an id that installs a configuration missing it.\n */\nexport async function readCarriedSkills(owned: OwnedSkillDir[]): Promise<ContentReading> {\n const reads = await Promise.all(owned.map(readCarriedSkill));\n\n return {\n external: Object.fromEntries(\n reads.flatMap((read) => (read.carries === \"content\" ? [[read.id, read.skill]] : [])),\n ),\n uncarryable: reads.flatMap((read) => (read.carries === \"unshareable\" ? [read.line] : [])),\n };\n}\n","// src/utils/cookie.ts\nimport { decodeURIComponent_, tryDecode } from \"./url.js\";\nvar algorithm = { name: \"HMAC\", hash: \"SHA-256\" };\nvar getCryptoKey = async (secret) => {\n const secretBuf = typeof secret === \"string\" ? new TextEncoder().encode(secret) : secret;\n return await crypto.subtle.importKey(\"raw\", secretBuf, algorithm, false, [\"sign\", \"verify\"]);\n};\nvar makeSignature = async (value, secret) => {\n const key = await getCryptoKey(secret);\n const signature = await crypto.subtle.sign(algorithm.name, key, new TextEncoder().encode(value));\n return btoa(String.fromCharCode(...new Uint8Array(signature)));\n};\nvar verifySignature = async (base64Signature, value, secret) => {\n try {\n const signatureBinStr = atob(base64Signature);\n const signature = new Uint8Array(signatureBinStr.length);\n for (let i = 0, len = signatureBinStr.length; i < len; i++) {\n signature[i] = signatureBinStr.charCodeAt(i);\n }\n return await crypto.subtle.verify(algorithm, secret, signature, new TextEncoder().encode(value));\n } catch {\n return false;\n }\n};\nvar validCookieNameRegEx = /^[\\w!#$%&'*.^`|~+-]+$/;\nvar relaxedCookieNameRegEx = /^[!#-:<>-[\\]-~]+$/;\nvar validCookieValueRegEx = /^[ !#-:<-[\\]-~]*$/;\nvar trimCookieWhitespace = (value) => {\n let start = 0;\n let end = value.length;\n while (start < end) {\n const charCode = value.charCodeAt(start);\n if (charCode !== 32 && charCode !== 9) {\n break;\n }\n start++;\n }\n while (end > start) {\n const charCode = value.charCodeAt(end - 1);\n if (charCode !== 32 && charCode !== 9) {\n break;\n }\n end--;\n }\n return start === 0 && end === value.length ? value : value.slice(start, end);\n};\nvar parse = (cookie, name) => {\n if (name && cookie.indexOf(name) === -1) {\n return {};\n }\n const pairs = cookie.split(\";\");\n const parsedCookie = /* @__PURE__ */ Object.create(null);\n for (const pairStr of pairs) {\n const valueStartPos = pairStr.indexOf(\"=\");\n if (valueStartPos === -1) {\n continue;\n }\n const cookieName = trimCookieWhitespace(pairStr.substring(0, valueStartPos));\n if (name && name !== cookieName || !relaxedCookieNameRegEx.test(cookieName) || cookieName in parsedCookie) {\n continue;\n }\n let cookieValue = trimCookieWhitespace(pairStr.substring(valueStartPos + 1));\n if (cookieValue.startsWith('\"') && cookieValue.endsWith('\"')) {\n cookieValue = cookieValue.slice(1, -1);\n }\n if (validCookieValueRegEx.test(cookieValue)) {\n parsedCookie[cookieName] = cookieValue.indexOf(\"%\") !== -1 ? tryDecode(cookieValue, decodeURIComponent_) : cookieValue;\n if (name) {\n break;\n }\n }\n }\n return parsedCookie;\n};\nvar parseSigned = async (cookie, secret, name) => {\n const parsedCookie = /* @__PURE__ */ Object.create(null);\n const secretKey = await getCryptoKey(secret);\n for (const [key, value] of Object.entries(parse(cookie, name))) {\n const signatureStartPos = value.lastIndexOf(\".\");\n if (signatureStartPos < 1) {\n continue;\n }\n const signedValue = value.substring(0, signatureStartPos);\n const signature = value.substring(signatureStartPos + 1);\n if (signature.length !== 44 || !signature.endsWith(\"=\")) {\n continue;\n }\n const isVerified = await verifySignature(signature, signedValue, secretKey);\n parsedCookie[key] = isVerified ? signedValue : false;\n }\n return parsedCookie;\n};\nvar _serialize = (name, value, opt = {}) => {\n if (!validCookieNameRegEx.test(name)) {\n throw new Error(\"Invalid cookie name\");\n }\n let cookie = `${name}=${value}`;\n if (name.startsWith(\"__Secure-\") && !opt.secure) {\n throw new Error(\"__Secure- Cookie must have Secure attributes\");\n }\n if (name.startsWith(\"__Host-\")) {\n if (!opt.secure) {\n throw new Error(\"__Host- Cookie must have Secure attributes\");\n }\n if (opt.path !== \"/\") {\n throw new Error('__Host- Cookie must have Path attributes with \"/\"');\n }\n if (opt.domain) {\n throw new Error(\"__Host- Cookie must not have Domain attributes\");\n }\n }\n for (const key of [\"domain\", \"path\", \"sameSite\", \"priority\"]) {\n if (opt[key] && /[;\\r\\n]/.test(opt[key])) {\n throw new Error(`${key} must not contain \";\", \"\\\\r\", or \"\\\\n\"`);\n }\n }\n if (opt && typeof opt.maxAge === \"number\" && opt.maxAge >= 0) {\n if (opt.maxAge > 3456e4) {\n throw new Error(\n \"Cookies Max-Age SHOULD NOT be greater than 400 days (34560000 seconds) in duration.\"\n );\n }\n cookie += `; Max-Age=${opt.maxAge | 0}`;\n }\n if (opt.domain && opt.prefix !== \"host\") {\n cookie += `; Domain=${opt.domain}`;\n }\n if (opt.path) {\n cookie += `; Path=${opt.path}`;\n }\n if (opt.expires) {\n if (opt.expires.getTime() - Date.now() > 3456e7) {\n throw new Error(\n \"Cookies Expires SHOULD NOT be greater than 400 days (34560000 seconds) in the future.\"\n );\n }\n cookie += `; Expires=${opt.expires.toUTCString()}`;\n }\n if (opt.httpOnly) {\n cookie += \"; HttpOnly\";\n }\n if (opt.secure) {\n cookie += \"; Secure\";\n }\n if (opt.sameSite) {\n cookie += `; SameSite=${opt.sameSite.charAt(0).toUpperCase() + opt.sameSite.slice(1)}`;\n }\n if (opt.priority) {\n cookie += `; Priority=${opt.priority.charAt(0).toUpperCase() + opt.priority.slice(1)}`;\n }\n if (opt.partitioned) {\n if (!opt.secure) {\n throw new Error(\"Partitioned Cookie must have Secure attributes\");\n }\n cookie += \"; Partitioned\";\n }\n return cookie;\n};\nvar serialize = (name, value, opt) => {\n value = encodeURIComponent(value);\n return _serialize(name, value, opt);\n};\nvar serializeSigned = async (name, value, secret, opt = {}) => {\n const signature = await makeSignature(value, secret);\n value = `${value}.${signature}`;\n value = encodeURIComponent(value);\n return _serialize(name, value, opt);\n};\nexport {\n parse,\n parseSigned,\n serialize,\n serializeSigned\n};\n","// src/client/utils.ts\nimport { fetchRP, DetailedError } from \"./fetch-result-please.js\";\nvar mergePath = (base, path) => {\n base = base.replace(/\\/+$/, \"\");\n base = base + \"/\";\n path = path.replace(/^\\/+/, \"\");\n return base + path;\n};\nvar replaceUrlParam = (urlString, params) => {\n for (const [k, v] of Object.entries(params)) {\n const reg = new RegExp(\"/:\" + k + \"(?:{[^/]+})?\\\\??(?=/|$)\");\n urlString = urlString.replace(reg, v ? `/${v}` : \"\");\n }\n return urlString;\n};\nvar buildSearchParams = (query) => {\n const searchParams = new URLSearchParams();\n for (const [k, v] of Object.entries(query)) {\n if (v === void 0) {\n continue;\n }\n if (Array.isArray(v)) {\n for (const v2 of v) {\n searchParams.append(k, v2);\n }\n } else {\n searchParams.set(k, v);\n }\n }\n return searchParams;\n};\nvar replaceUrlProtocol = (urlString, protocol) => {\n switch (protocol) {\n case \"ws\":\n return urlString.replace(/^http/, \"ws\");\n case \"http\":\n return urlString.replace(/^ws/, \"http\");\n }\n};\nvar removeIndexString = (urlString) => {\n if (/^https?:\\/\\/[^\\/]+?\\/index(?=\\?|$)/.test(urlString)) {\n return urlString.replace(/\\/index(?=\\?|$)/, \"/\");\n }\n return urlString.replace(/\\/index(?=\\?|$)/, \"\");\n};\nfunction isObject(item) {\n return typeof item === \"object\" && item !== null && !Array.isArray(item);\n}\nfunction deepMerge(target, source) {\n if (!isObject(target) && !isObject(source)) {\n return source;\n }\n const merged = { ...target };\n for (const key in source) {\n const value = source[key];\n if (isObject(merged[key]) && isObject(value)) {\n merged[key] = deepMerge(merged[key], value);\n } else {\n merged[key] = value;\n }\n }\n return merged;\n}\nasync function parseResponse(fetchRes) {\n return fetchRP(fetchRes);\n}\nexport {\n DetailedError,\n buildSearchParams,\n deepMerge,\n mergePath,\n parseResponse,\n removeIndexString,\n replaceUrlParam,\n replaceUrlProtocol\n};\n","// src/client/client.ts\nimport { serialize } from \"../utils/cookie.js\";\nimport {\n buildSearchParams,\n deepMerge,\n mergePath,\n removeIndexString,\n replaceUrlParam,\n replaceUrlProtocol\n} from \"./utils.js\";\nvar createProxy = (callback, path) => {\n const proxy = new Proxy(() => {\n }, {\n get(_obj, key) {\n if (typeof key !== \"string\" || key === \"then\") {\n return void 0;\n }\n return createProxy(callback, [...path, key]);\n },\n apply(_1, _2, args) {\n return callback({\n path,\n args\n });\n }\n });\n return proxy;\n};\nvar ClientRequestImpl = class {\n url;\n method;\n buildSearchParams;\n queryParams = void 0;\n pathParams = {};\n rBody;\n cType = void 0;\n constructor(url, method, options) {\n this.url = url;\n this.method = method;\n this.buildSearchParams = options.buildSearchParams;\n }\n fetch = async (args, opt) => {\n if (args) {\n if (args.query) {\n this.queryParams = this.buildSearchParams(args.query);\n }\n if (args.form) {\n const form = new FormData();\n for (const [k, v] of Object.entries(args.form)) {\n if (v === void 0) {\n continue;\n }\n if (Array.isArray(v)) {\n for (const v2 of v) {\n form.append(k, v2);\n }\n } else {\n form.append(k, v);\n }\n }\n this.rBody = form;\n }\n if (args.json) {\n this.rBody = JSON.stringify(args.json);\n this.cType = \"application/json\";\n }\n if (args.param) {\n this.pathParams = args.param;\n }\n }\n let methodUpperCase = this.method.toUpperCase();\n const headerValues = {\n ...args?.header,\n ...typeof opt?.headers === \"function\" ? await opt.headers() : opt?.headers\n };\n if (args?.cookie) {\n const cookies = [];\n for (const [key, value] of Object.entries(args.cookie)) {\n cookies.push(serialize(key, value, { path: \"/\" }));\n }\n headerValues[\"Cookie\"] = cookies.join(\",\");\n }\n if (this.cType) {\n headerValues[\"Content-Type\"] = this.cType;\n }\n const headers = new Headers(headerValues ?? void 0);\n let url = this.url;\n url = removeIndexString(url);\n url = replaceUrlParam(url, this.pathParams);\n if (this.queryParams) {\n url = url + \"?\" + this.queryParams.toString();\n }\n methodUpperCase = this.method.toUpperCase();\n const setBody = !(methodUpperCase === \"GET\" || methodUpperCase === \"HEAD\");\n return (opt?.fetch || fetch)(url, {\n body: setBody ? this.rBody : void 0,\n method: methodUpperCase,\n headers,\n ...opt?.init\n });\n };\n};\nvar hc = (baseUrl, options) => createProxy(function proxyCallback(opts) {\n const buildSearchParamsOption = options?.buildSearchParams ?? buildSearchParams;\n const parts = [...opts.path];\n const lastParts = parts.slice(-3).reverse();\n if (lastParts[0] === \"toString\") {\n if (lastParts[1] === \"name\") {\n return lastParts[2] || \"\";\n }\n return proxyCallback.toString();\n }\n if (lastParts[0] === \"valueOf\") {\n if (lastParts[1] === \"name\") {\n return lastParts[2] || \"\";\n }\n return proxyCallback;\n }\n let method = \"\";\n if (/^\\$/.test(lastParts[0])) {\n const last = parts.pop();\n if (last) {\n method = last.replace(/^\\$/, \"\");\n }\n }\n const path = parts.join(\"/\");\n const url = mergePath(baseUrl, path);\n if (method === \"url\" || method === \"path\") {\n let result = url;\n if (opts.args[0]) {\n if (opts.args[0].param) {\n result = replaceUrlParam(url, opts.args[0].param);\n }\n if (opts.args[0].query) {\n result = result + \"?\" + buildSearchParamsOption(opts.args[0].query).toString();\n }\n }\n result = removeIndexString(result);\n if (method === \"url\") {\n return new URL(result);\n }\n return result.slice(baseUrl.replace(/\\/+$/, \"\").length).replace(/^\\/?/, \"/\");\n }\n if (method === \"ws\") {\n const webSocketUrl = replaceUrlProtocol(\n opts.args[0] && opts.args[0].param ? replaceUrlParam(url, opts.args[0].param) : url,\n \"ws\"\n );\n const targetUrl = new URL(webSocketUrl);\n const queryParams = opts.args[0]?.query;\n if (queryParams) {\n Object.entries(queryParams).forEach(([key, value]) => {\n if (Array.isArray(value)) {\n value.forEach((item) => targetUrl.searchParams.append(key, item));\n } else {\n targetUrl.searchParams.set(key, value);\n }\n });\n }\n const establishWebSocket = (...args) => {\n if (options?.webSocket !== void 0 && typeof options.webSocket === \"function\") {\n return options.webSocket(...args);\n }\n return new WebSocket(...args);\n };\n return establishWebSocket(targetUrl.toString());\n }\n const req = new ClientRequestImpl(url, method, {\n buildSearchParams: buildSearchParamsOption\n });\n if (method) {\n options ??= {};\n const reqOptions = { ...opts.args[1] };\n const baseHeaders = options.headers;\n const reqHeaders = reqOptions.headers;\n if (baseHeaders && reqHeaders) {\n reqOptions.headers = async () => ({\n ...typeof baseHeaders === \"function\" ? await baseHeaders() : baseHeaders,\n ...typeof reqHeaders === \"function\" ? await reqHeaders() : reqHeaders\n });\n }\n const args = deepMerge(options, reqOptions);\n return req.fetch(opts.args[0], args);\n }\n return req;\n}, []);\nexport {\n hc\n};\n","import { hc } from \"hono/client\"\n\nimport type { AppType } from \"server\"\n\n/**\n * The typed client both front doors reach the worker through.\n *\n * The editor and the CLI shared nothing before this package existed: the\n * editor configured `hc<AppType>` and the CLI hand-wrote a `fetch` at a URL it\n * built itself, so the two agreed about the worker's routes only by\n * coincidence. What they genuinely differ in is small and finite — where the\n * worker is, whether a session cookie rides along, and what identifies the\n * caller — so those are the parameters and everything else is shared.\n *\n * What this package deliberately does NOT own is either consumer's refusal\n * copy. The editor turns a failure into a union member a component renders;\n * the CLI turns one into a sentence a person reads in a terminal. Those are\n * different artefacts for different readers, and a shared \"message\" would be\n * wrong for both.\n *\n * `AppType` is a type and nothing else. `import type` erases before any\n * bundler sees it, so no worker code is reachable from the editor's bundle\n * (which fails its build on a first-paint budget) or from the CLI's.\n */\n\n/**\n * Whether the browser's session cookie rides along.\n *\n * Only the two values either consumer has a use for, rather than the full\n * `RequestCredentials`: `same-origin` is exactly the setting that breaks the\n * editor, because the cookie is set on `.agentsinc.sh` by a different origin\n * than the one the app is served from, and naming it here would make it\n * reachable by a typo.\n */\nexport type ApiCredentials = \"include\" | \"omit\"\n\n/**\n * What every request carries, however it is sent.\n *\n * `credentials` defaults to `\"include\"` and that direction is the point. The\n * session cookie is set by a different origin on the same registrable domain,\n * and without it sign-in appears to work and the very next request is\n * anonymous — with nothing logged on either side. A policy that has to be\n * opted INTO is one a new call site can forget silently; this one has to be\n * opted out of by name, which is a thing a reader can see.\n */\nexport type ApiRequestPolicy = {\n headers?: Record<string, string>\n credentials?: ApiCredentials\n}\n\nexport type ApiClientOptions = ApiRequestPolicy & {\n /** Where the worker is. No default: a wrong guess is a silent wrong API. */\n baseUrl: string\n /**\n * The seam tests reach through. hc calls\n * `(opt?.fetch || fetch)(url, { body, method, headers, ...opt?.init })`, so\n * injecting one is the only way to observe what this package produces without\n * a network — and the exact shape matters, because `init` is spread LAST.\n * That is why `headers` goes through hc's own option rather than through\n * `init`: in `init` it would replace the whole `Headers` object, including\n * the content type hc sets for a JSON body.\n */\n fetch?: typeof globalThis.fetch\n}\n\ntype ResolvedPolicy = {\n headers: Record<string, string>\n credentials: ApiCredentials\n}\n\n/**\n * The one place the defaults are applied, so the typed client and any\n * hand-written fetch cannot drift about what a request carries.\n */\nconst resolvePolicy = ({\n headers = {},\n credentials = \"include\",\n}: ApiRequestPolicy): ResolvedPolicy => ({ headers, credentials })\n\n/**\n * The policy as a `RequestInit`, for the paths `AppType` does not describe.\n *\n * Better Auth mounts its own surface under `/api/auth/*` with a single\n * handler rather than a described route, so there is nothing there for `hc` to\n * type — and a hand-written fetch at those paths is how the editor signs a\n * person in. This is what keeps that call on the same session policy as the\n * typed ones instead of on a second copy of it.\n *\n * Spread it LAST over a caller's own init: a caller may add a method, a body\n * or headers of its own, and may not drop the cookie.\n */\nexport const apiRequestInit = (policy: ApiRequestPolicy): RequestInit =>\n resolvePolicy(policy)\n\n/**\n * Builds the client for one consumer's base URL, headers and session policy.\n *\n * The two configured values go to different places in hc's options, and which\n * goes where is load-bearing. hc spreads `init` LAST over the request it\n * built, so anything named there replaces what hc put in that field — a\n * `headers` in `init` would replace the whole `Headers` object, including the\n * `Content-Type: application/json` hc sets for a `$post({ json })`. Headers go\n * through hc's own `headers` option, which is merged into that object instead,\n * and `init` names `credentials` and nothing else.\n */\nexport const createApiClient = ({\n baseUrl,\n fetch,\n ...policy\n}: ApiClientOptions) => {\n const { headers, credentials } = resolvePolicy(policy)\n\n return hc<AppType>(baseUrl, {\n headers,\n init: { credentials },\n // Spread rather than named. Under `exactOptionalPropertyTypes` hc's\n // optional `fetch` does not accept an explicit `undefined`, so writing\n // `fetch,` here is a TS2379 whenever a caller omits one.\n ...(fetch && { fetch }),\n })\n}\n\n/** The configured client, for consumers that pass one around. */\nexport type ApiClient = ReturnType<typeof createApiClient>\n","import { createApiClient } from \"@workspace/api\";\nimport { seedPayloadSchema, type SeedPayload } from \"@workspace/matrix/seed\";\n\n/** The config store behind agentsinc.sh. Overridable so tests never touch the network. */\nexport const SEED_API_URL = process.env.AGENTS_INC_API_URL ?? \"https://api.agentsinc.sh\";\n\n/**\n * Identifies this fetch as the CLI rather than a browser.\n *\n * `GET /configs/:id` is the only place either side can observe a config being *installed* rather\n * than merely built, and the worker can only separate that from someone opening a share link if\n * we say so. Without this the conversion signal does not exist.\n */\nexport const SEED_USER_AGENT = \"agents-inc-cli\";\n\n/**\n * The worker's routes, typed from the worker itself, configured for a terminal.\n *\n * `credentials: \"omit\"` is named rather than left to the shared default. The default is `include`\n * because the editor's session is a cookie the browser holds; a terminal holds no cookie jar at\n * all, so inheriting that default would claim a session that cannot exist.\n *\n * Built once at module scope, like `SEED_API_URL` above and for the same reason — the base URL is\n * read from the environment once at import, so there is nothing per-call for a client to pick up.\n */\nconst store = createApiClient({\n baseUrl: SEED_API_URL,\n headers: { accept: \"application/json\", \"user-agent\": SEED_USER_AGENT },\n credentials: \"omit\",\n});\n\nexport type FetchSeedResult = { ok: true; payload: SeedPayload } | { ok: false; error: string };\n\n/**\n * Fetches and validates a shared configuration.\n *\n * Every failure is a message rather than a throw: this runs before anything has been written, so\n * there is nothing to roll back and the caller's job is to explain rather than recover.\n */\nexport async function fetchSeedConfig(id: string): Promise<FetchSeedResult> {\n let response: Response;\n try {\n // Escaped here rather than by the client: hono's `replaceUrlParam` substitutes a path\n // parameter verbatim, so an id carrying a `/` or a `?` would silently address another route.\n response = await store.configs[\":id\"].$get({ param: { id: encodeURIComponent(id) } });\n } catch {\n return { ok: false, error: `Could not reach ${SEED_API_URL} — check your connection.` };\n }\n\n if (response.status === 404) {\n return { ok: false, error: `No configuration found for id '${id}'.` };\n }\n if (!response.ok) {\n return { ok: false, error: `Fetching configuration failed (HTTP ${response.status}).` };\n }\n\n let body: unknown;\n try {\n body = await response.json();\n } catch {\n return { ok: false, error: \"The configuration store returned something that is not JSON.\" };\n }\n\n const parsed = seedPayloadSchema.safeParse(body);\n if (!parsed.success) {\n // Names the remedy rather than a cause it cannot observe. The payload was validated by the\n // store on the way IN, so a stored payload that no longer parses means the contract moved\n // underneath it — and every way that happens lands in this one `safeParse`: an id minted\n // before a version bump, an id minted after one, and a body that is simply broken. The CLI\n // cannot tell them apart, and the one thing true of all three is that re-sharing fixes it,\n // because the store content-addresses an id and a fresh share mints one under this version.\n return {\n ok: false,\n error: `Configuration '${id}' is not in a format this version of the CLI can install. Shared ids are never migrated — re-share the configuration to mint a current one, or update the CLI if that id came from a newer version.`,\n };\n }\n\n return { ok: true, payload: parsed.data };\n}\n"],"mappings":"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","names":["path","path","fetch"]}
@@ -1,6 +1,5 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
- DOMAIN_ORDER,
4
3
  deriveInstallMode,
5
4
  disableBuffering,
6
5
  drainBuffer,
@@ -8,12 +7,9 @@ import {
8
7
  getAvailableSkills,
9
8
  getCellState,
10
9
  getUnmetRequiredBy,
11
- isActiveAt,
12
- isGlobalTombstone,
13
10
  isLocalOnlySkill,
14
- isProjectOwned,
15
11
  warn
16
- } from "./chunk-OUG6TCQ4.js";
12
+ } from "./chunk-YSQ76LWG.js";
17
13
  import {
18
14
  getCategoryDomain,
19
15
  getSkillById,
@@ -22,7 +18,7 @@ import {
22
18
  typedFromEntries,
23
19
  typedKeys,
24
20
  typedValues
25
- } from "./chunk-XX657S4U.js";
21
+ } from "./chunk-BLGETWYI.js";
26
22
  import {
27
23
  CLI_INVOKE_COMMAND,
28
24
  DEFAULT_PUBLIC_SOURCE_NAME,
@@ -30,8 +26,12 @@ import {
30
26
  EJECT_SOURCE,
31
27
  FALLBACK_DOMAIN,
32
28
  INSTALL_MODES,
33
- SKILL_CATEGORIES_PATH
34
- } from "./chunk-5KB4I5J7.js";
29
+ SKILL_CATEGORIES_PATH,
30
+ isActiveAt,
31
+ isGlobalTombstone,
32
+ isProjectOwned,
33
+ orderDomains
34
+ } from "./chunk-AMZO4YJK.js";
35
35
 
36
36
  // src/cli/stores/wizard-store.ts
37
37
  import { create } from "zustand";
@@ -188,15 +188,6 @@ function buildCategoriesForDomain(domain, allSelections, installedSkillIds, skil
188
188
  return categoryRows.filter((row) => row.options.length > 0);
189
189
  }
190
190
 
191
- // src/cli/lib/wizard/domain-order.ts
192
- function orderDomains(domains) {
193
- const builtInSet = new Set(DOMAIN_ORDER);
194
- return [
195
- ...domains.filter((d) => !builtInSet.has(d)).sort(),
196
- ...DOMAIN_ORDER.filter((d) => domains.includes(d))
197
- ];
198
- }
199
-
200
191
  // src/cli/lib/wizard/agent-roster.ts
201
192
  var BUILT_IN_AGENT_GROUPS = [
202
193
  {
@@ -1158,7 +1149,6 @@ export {
1158
1149
  formatScopeTag,
1159
1150
  deriveScopeBadges,
1160
1151
  buildCategoriesForDomain,
1161
- orderDomains,
1162
1152
  BUILT_IN_AGENT_GROUPS,
1163
1153
  BUILT_IN_AGENT_IDS,
1164
1154
  DOMAIN_AGENTS,
@@ -1169,4 +1159,4 @@ export {
1169
1159
  showWarningsAsToast,
1170
1160
  hydrateWizardStore
1171
1161
  };
1172
- //# sourceMappingURL=chunk-SLB2SFTX.js.map
1162
+ //# sourceMappingURL=chunk-YOVUXONB.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/cli/stores/wizard-store.ts","../src/cli/lib/wizard/build-step-logic.ts","../src/cli/lib/wizard/scope-diff.ts","../src/cli/lib/wizard/agent-roster.ts"],"sourcesContent":["import { create } from \"zustand\";\nimport {\n CLI_INVOKE_COMMAND,\n DEFAULT_PUBLIC_SOURCE_NAME,\n DEFAULT_SCRATCH_DOMAINS,\n EJECT_SOURCE,\n FALLBACK_DOMAIN,\n INSTALL_MODES,\n SKILL_CATEGORIES_PATH,\n} from \"../consts.js\";\nimport type { InstallMode } from \"../lib/installation/index.js\";\nimport { deriveInstallMode as sharedDeriveInstallMode } from \"../lib/installation/installation.js\";\nimport type { AgentScopeConfig, SkillConfig, SkillScope } from \"../types/config.js\";\nimport {\n isActiveAt,\n isGlobalTombstone,\n isProjectOwned,\n} from \"../lib/configuration/scope-predicates.js\";\nimport { isLocalOnlySkill } from \"../lib/loading/multi-source-loader.js\";\nimport { matrix, getSkillById, getCategoryDomain } from \"../lib/matrix/matrix-provider.js\";\nimport {\n agentSlotKey,\n buildCategoriesForDomain,\n firstFocusableAgent,\n orderDomains,\n skillSlotKey,\n} from \"../lib/wizard/index.js\";\nimport type {\n AgentName,\n Domain,\n DomainSelections,\n SkillId,\n Category,\n CategorySelections,\n ResolvedSkill,\n} from \"../types/index.js\";\nimport type { SourceOption, SourceRow } from \"../components/wizard/source-grid.js\";\nimport { disableBuffering, drainBuffer, enableBuffering, warn } from \"../utils/logger.js\";\nimport { typedEntries, typedFromEntries, typedKeys, typedValues } from \"../utils/typed-object.js\";\n\n/** The whole of what a skill no marketplace carries can be installed as. */\nconst LOCAL_ONLY_INSTALL_MODES = [\"eject\"] as const satisfies readonly Exclude<\n InstallMode,\n \"mixed\"\n>[];\n\n/** Toast strings surfaced by scope/selection guards (E2E asserts these verbatim). */\nconst TOAST_MESSAGES = {\n GLOBAL_SKILLS_LOCKED: \"Global skills cannot be changed from project scope\",\n ALREADY_EJECTED_AT_GLOBAL: \"Already exists as ejected skill at global scope\",\n GLOBAL_AGENTS_LOCKED: \"Global agents cannot be changed from project scope\",\n} as const;\n\n/**\n * What a population run past the mount could not place, in one line.\n *\n * Short by necessity rather than by preference: `Toast` in `components/wizard/toast.tsx` paints\n * its message on one row plus padding, absolutely positioned at the foot of a frame already\n * sized to the terminal,\n * so a toast as wide as the warning it stands for would wrap and break the frame it is drawn\n * in. Nothing is discarded by keeping it short — `unresolvableSkillIds` still carries every id,\n * which is what `edit` names each one from afterwards.\n *\n * It states the outcome rather than the cause, because two causes arrive here: a skill the\n * loaded source does not carry, and one whose category no domain claims. Both end the same way,\n * which is the sentence both warnings already close on — the wizard has no screen to put the\n * skill on, so it is left out of this session's selection.\n */\nfunction skillsLeftOutToast(count: number): string {\n return count === 1\n ? \"1 skill was left out — this source cannot place it\"\n : `${count} skills were left out — this source cannot place them`;\n}\n\n/** First defined source among candidates, else the default public source. */\nfunction resolveEffectiveSource(...candidates: Array<string | undefined>): string {\n return candidates.find((source) => source !== undefined) ?? DEFAULT_PUBLIC_SOURCE_NAME;\n}\n\n/** Name of a skill's primary available source, if any. */\nfunction primarySourceName(skill: ResolvedSkill | undefined): string | undefined {\n return skill?.availableSources?.find((s) => s.primary)?.name;\n}\n\n/** The one marketplace a skill can be plugin-installed from, when one carries it. */\nfunction marketplaceSourceName(skill: ResolvedSkill | undefined): string | undefined {\n return skill?.availableSources?.find((source) => source.type !== \"local\")?.name;\n}\n\n/**\n * The origin a skill takes when nothing saved names one: the marketplace that carries\n * it, or the project's own copy when none does. A marketplace origin on a skill no\n * marketplace has names an install that cannot happen, which is what made a\n * locally-written skill default to a plugin it could never be.\n */\nfunction defaultOriginFor(skill: ResolvedSkill | undefined): string {\n if (isLocalOnlySkill(skill)) return EJECT_SOURCE;\n\n return primarySourceName(skill) ?? DEFAULT_PUBLIC_SOURCE_NAME;\n}\n\nfunction createDefaultSkillConfig(id: SkillId): SkillConfig {\n return { id, scope: \"global\", origin: defaultOriginFor(matrix.skills[id]) };\n}\n\n/** True when configs hold an active (non-excluded) project-scope entry for the id. */\nfunction hasProjectActive(configs: SkillConfig[], id: SkillId): boolean {\n return configs.some((sc) => sc.id === id && isActiveAt(sc, \"project\"));\n}\n\n/** The active (non-excluded) global-scope entry for the id, when configs hold one. */\nfunction findGlobalActive(configs: SkillConfig[], id: SkillId): SkillConfig | undefined {\n return configs.find((sc) => sc.id === id && isActiveAt(sc, \"global\"));\n}\n\n/** True when configs hold an active (non-excluded) global-scope entry for the id. */\nfunction hasGlobalActive(configs: SkillConfig[], id: SkillId): boolean {\n return findGlobalActive(configs, id) !== undefined;\n}\n\n/** True when configs hold an excluded global-scope tombstone for the id. */\nfunction hasGlobalTombstone(configs: SkillConfig[], id: SkillId): boolean {\n return configs.some((sc) => sc.id === id && isGlobalTombstone(sc));\n}\n\n/**\n * A dual-scope pair — an active project entry plus a global tombstone for\n * the same skill. The shape the `[P][G]` row renders from; removal collapses it to a single\n * inherited-global entry, re-selection rebuilds it.\n */\nfunction isDualScopePair(configs: SkillConfig[], id: SkillId): boolean {\n return hasProjectActive(configs, id) && hasGlobalTombstone(configs, id);\n}\n\n/**\n * True when a SELECTED skill must not be deselected at project scope.\n *\n * The lock protects GLOBAL-OWNED halves and nothing else. Two arms: an active global entry in\n * the hydration snapshot (genuinely global-only — the long-standing read-only behaviour); and a\n * snapshot tombstone paired with a LIVE plain active global entry (the stale state a persisted\n * `[P][G]` reaches after an in-session collapse, whose deselect would silently tombstone the\n * still-real global install).\n *\n * A persisted `[P][G]` pair matches neither: its live global half is a tombstone, and its project\n * half is the project's own install to drop — `applySkillRemoval` collapses the pair to the\n * inherited global entry, so removing it never touches the global install it masks. A skill\n * freshly added this session (absent from the snapshot) is likewise nobody's install yet and\n * stays freely deselectable.\n */\nfunction isGloballyLockedSkill(\n installed: SkillConfig[],\n liveConfigs: SkillConfig[],\n id: SkillId,\n): boolean {\n return (\n hasGlobalActive(installed, id) ||\n (hasGlobalTombstone(installed, id) && hasGlobalActive(liveConfigs, id))\n );\n}\n\n/**\n * True when an exclusive-category radio swap must not drop this skill at project scope.\n *\n * The deselect lock, plus one case it deliberately allows on its own row: a live `[P][G]` pair.\n * Dropping a pair's project half leaves the global install it masks ACTIVE, so a swap that did it\n * implicitly would seat the new pick beside a still-active sibling in a category that permits one.\n * Removing the pair stays the project's to do — with the selection key on its own row, where\n * nothing takes the freed slot.\n */\nfunction blocksExclusiveSwap(\n installed: SkillConfig[],\n liveConfigs: SkillConfig[],\n id: SkillId,\n): boolean {\n return isGloballyLockedSkill(installed, liveConfigs, id) || isDualScopePair(liveConfigs, id);\n}\n\n/**\n * True when re-scoping this project-eject entry to global would overwrite an ejected global\n * install that the live config does not already override with a tombstone.\n */\nfunction wouldOverwriteGlobalEject(\n config: SkillConfig,\n liveConfigs: SkillConfig[],\n installedSkillConfigs: SkillConfig[] | null,\n): boolean {\n if (config.scope !== \"project\" || config.origin !== EJECT_SOURCE) return false;\n const globalEjectInstalled = installedSkillConfigs?.some(\n (sc) =>\n sc.id === config.id && sc.scope === \"global\" && sc.origin === EJECT_SOURCE && !sc.excluded,\n );\n if (!globalEjectInstalled) return false;\n return !liveConfigs.some((sc) => sc.id === config.id && sc.excluded);\n}\n\n/**\n * True when the slot a Sources-step call targets is a global install this session INHERITED —\n * an active global entry the hydration snapshot already carried.\n *\n * Keyed on the `(id, scope)` SLOT, never on the id: an id legitimately occupies slots at both\n * scopes at once, and the project half of a `[P][G]` pair is the project's own install to\n * configure. An id-keyed test would freeze the half the Sources grid deliberately leaves\n * editable.\n *\n * Read off the SNAPSHOT, never off the live entry's scope: a skill this session added at global\n * scope — and every skill in a first `init`, where the snapshot is `null` — is nobody's install\n * yet, so nothing is inherited and every row is the session's own.\n */\nfunction isInheritedGlobalSlot(\n installed: SkillConfig[] | null,\n id: SkillId,\n scope: SkillScope | undefined,\n): boolean {\n if (installed === null) return false;\n return scope === \"global\" && hasGlobalActive(installed, id);\n}\n\n/**\n * Rewrites the origin of the ACTIVE entry at (id, scope), leaving every other entry untouched —\n * in particular a dual-scope skill's excluded global tombstone, which keeps describing the\n * masked global install.\n */\nfunction withActiveEntryOrigin(\n configs: SkillConfig[],\n id: SkillId,\n scope: SkillScope | undefined,\n origin: string,\n): SkillConfig[] {\n return configs.map((sc) =>\n sc.id === id && !sc.excluded && sc.scope === scope ? { ...sc, origin } : sc,\n );\n}\n\n/**\n * Removes deselected skills, honouring what the project is allowed to remove.\n *\n * An entry the project OWNS — project-scoped, or the project's own global tombstone — is\n * dropped. An entry the project merely INHERITS (an active global-scope entry the hydration\n * snapshot already carried) is immutable from project scope and survives BYTE-IDENTICAL: a\n * project edit neither uninstalls a global install nor mints a tombstone for it. A skill this\n * session added itself is absent from the snapshot, is nobody's install yet, and is dropped\n * like any other so an accidental add stays undoable.\n *\n * `installedSkillConfigs` is `null` when editing FROM global scope, where the config being\n * edited IS the global one: nothing is inherited, so every removal is a genuine uninstall.\n *\n * Dual-scope entries (an active project entry paired with a global tombstone) collapse to a\n * single inherited-global entry so the `[G]` badge keeps rendering after the project half is\n * dropped.\n */\nfunction applySkillRemoval(\n configs: SkillConfig[],\n removedIds: Iterable<SkillId>,\n installedSkillConfigs: SkillConfig[] | null,\n): SkillConfig[] {\n // Annotated because `instanceof Set` narrows an `Iterable<SkillId>` to `Set<any>`,\n // which then spreads out as `any[]` below.\n const removed: ReadonlySet<SkillId> =\n removedIds instanceof Set ? removedIds : new Set(removedIds);\n const installedIds = new Set((installedSkillConfigs ?? []).map((s) => s.id));\n\n /**\n * A removed entry the project may not drop: a global install that existed before this session\n * and that the project does not own. Dual-scope pairs are excluded — both their halves go, and\n * the surviving global install is re-surfaced as a single inherited entry below.\n */\n const survivesRemoval = (entry: SkillConfig): boolean =>\n !isDualScopePair(configs, entry.id) && !isProjectOwned(entry) && installedIds.has(entry.id);\n\n const retained = configs.filter((sc) => !removed.has(sc.id) || survivesRemoval(sc));\n const resurfacedInheritedGlobals = [...removed]\n .filter((id) => isDualScopePair(configs, id))\n .map((id) => ({\n id,\n scope: \"global\" as const,\n origin:\n configs.find((sc) => sc.id === id && sc.scope === \"global\")?.origin ??\n DEFAULT_PUBLIC_SOURCE_NAME,\n }));\n\n return [...retained, ...resurfacedInheritedGlobals];\n}\n\n/** All skill IDs across a domain's category selections, in category order. */\nfunction flattenCategorySelections(selections: CategorySelections): SkillId[] {\n return typedValues(selections).flat();\n}\n\n/** Collects all skill IDs from a domain's category selections. */\nfunction collectSkillIdsFromSelections(selections: CategorySelections): Set<SkillId> {\n return new Set(flattenCategorySelections(selections));\n}\n\n/** Reconciles skill configs after selection changes: drops project-owned removals, leaves inherited global installs untouched, restores excluded on re-select, adds new defaults. */\nfunction reconcileSkillConfigs(\n configs: SkillConfig[],\n added: SkillId[],\n removed: SkillId[],\n installedSkillConfigs: SkillConfig[] | null,\n isEditingFromGlobalScope: boolean,\n): SkillConfig[] {\n // Editing from global scope has no project overlay, so a removal is a genuine uninstall.\n // Pass null so applySkillRemoval DROPS the skill rather than retaining it as an inherited\n // global install the project may not touch.\n const effectiveInstalled = isEditingFromGlobalScope ? null : installedSkillConfigs;\n let result = applySkillRemoval(configs, removed, effectiveInstalled);\n\n for (const id of added) {\n // Dual-scope restore: re-selecting a skill that is globally installed (recorded as a\n // tombstone in the project snapshot) with no current project entry re-creates BOTH a\n // fresh project entry and a global tombstone — mirroring toggleSkillScope's G->P path\n // so the row renders `[P][G]` again on a second spacebar.\n if (\n !isEditingFromGlobalScope &&\n hasGlobalTombstone(installedSkillConfigs ?? [], id) &&\n !hasProjectActive(result, id)\n ) {\n const globalEntry =\n (installedSkillConfigs ?? []).find((sc) => sc.id === id && sc.scope === \"global\") ??\n result.find((sc) => sc.id === id && sc.scope === \"global\");\n const origin = globalEntry?.origin ?? DEFAULT_PUBLIC_SOURCE_NAME;\n result = [\n ...result.filter((sc) => sc.id !== id),\n { id, scope: \"project\", origin },\n { id, scope: \"global\", excluded: true, origin },\n ];\n continue;\n }\n\n const existingExcluded = result.find((sc) => sc.id === id && sc.excluded);\n if (existingExcluded) {\n // Un-excluding drops the tombstone flag rather than setting it to `undefined`:\n // an absent `excluded` is what \"not excluded\" means everywhere else in the config.\n result = result.map((sc) => {\n if (sc.id !== id || !sc.excluded) return sc;\n const { excluded: _excluded, ...active } = sc;\n return active;\n });\n } else if (!result.some((sc) => sc.id === id)) {\n // Re-selecting a skill that the hydration snapshot still holds is a RESTORE, not a fresh\n // add: it must come back with its persisted scope and source rather than the wizard\n // defaults (a project-scoped eject skill would otherwise round-trip to global+marketplace\n // and trigger a bogus scope/source migration). buildSkillConfigForId degrades to exactly\n // createDefaultSkillConfig's output when the snapshot has no entry, so genuinely-new\n // selections are unaffected.\n result = [...result, buildSkillConfigForId(id, installedSkillConfigs)];\n }\n }\n\n return result;\n}\n\n/** True when configs hold an active (non-excluded) project-scope entry for the agent. */\nfunction agentHasProjectActive(configs: AgentScopeConfig[], name: AgentName): boolean {\n return configs.some((ac) => ac.name === name && isActiveAt(ac, \"project\"));\n}\n\n/** True when configs hold an active (non-excluded) global-scope entry for the agent. */\nfunction agentHasGlobalActive(configs: AgentScopeConfig[], name: AgentName): boolean {\n return configs.some((ac) => ac.name === name && isActiveAt(ac, \"global\"));\n}\n\n/** True when configs hold an excluded global-scope tombstone for the agent. */\nfunction agentHasGlobalTombstone(configs: AgentScopeConfig[], name: AgentName): boolean {\n return configs.some((ac) => ac.name === name && isGlobalTombstone(ac));\n}\n\n/** Agent side of isDualScopePair: active project entry + global tombstone for the same agent. */\nfunction isDualScopeAgentPair(configs: AgentScopeConfig[], name: AgentName): boolean {\n return agentHasProjectActive(configs, name) && agentHasGlobalTombstone(configs, name);\n}\n\n/**\n * Excluded tombstone entries. Preserved across reconcile/preselect merges so a dual-scope\n * pair's tombstone half survives and the pair can be restored later.\n */\nfunction collectTombstones<T extends { excluded?: boolean }>(configs: T[]): T[] {\n return configs.filter((entry) => entry.excluded);\n}\n\n/** The `(name, scope)` slots a rebuilt agent roster occupies. */\nfunction filledAgentSlots(configs: AgentScopeConfig[]): ReadonlySet<string> {\n return new Set(configs.map((ac) => agentSlotKey(ac.name, ac.scope)));\n}\n\n/**\n * Saved tombstones that still mask something once preselection has rebuilt the\n * active entries.\n *\n * A tombstone says \"the install at this scope is silenced\", which is only\n * meaningful while the active entry it silences sits at the OTHER scope — that\n * pair is the whole of the dual-scope indicator. A tombstone left at a slot the\n * rebuild has just filled with an active entry silences nothing, and the config\n * merge keys an active and an excluded entry apart, so both would be written.\n */\nfunction agentTombstonesOutsideRebuild(\n saved: AgentScopeConfig[],\n rebuilt: AgentScopeConfig[],\n): AgentScopeConfig[] {\n const filled = filledAgentSlots(rebuilt);\n return collectTombstones(saved).filter((ac) => !filled.has(agentSlotKey(ac.name, ac.scope)));\n}\n\n/** The skill-side twin of {@link agentTombstonesOutsideRebuild}, keyed on `(id, scope)`. */\nfunction skillTombstonesOutsideRebuild(\n saved: SkillConfig[],\n rebuilt: SkillConfig[],\n): SkillConfig[] {\n const filled = new Set(rebuilt.map((sc) => skillSlotKey(sc.id, sc.scope)));\n return collectTombstones(saved).filter((sc) => !filled.has(skillSlotKey(sc.id, sc.scope)));\n}\n\n/**\n * Applies an agent toggle: deselect removes the agent's entries; select restores an excluded\n * entry or adds a new one.\n *\n * A deselect never masks a globally-installed agent. Every reachable deselect here is\n * one the project owns — an active global install and a live `[P][G]` pair are both refused\n * upstream in `toggleAgent`, and a global-scope edit owns everything it can see — so the only\n * correct outcome is a clean removal.\n *\n * A newly added agent is `scope: \"global\"` DELIBERATELY, and a project-scoped installation\n * therefore compiling it with an empty stack is the CORRECT outcome, not a defect (ruled\n * 2026-08-19, after a finding filed against this line was graded wrong and deleted). Global is\n * the default scope for an agent, and `isScopePairCompatible` in\n * `lib/configuration/config-generator.ts` is the reason the stack comes out empty: project\n * skills never reach global agents, so a global agent paired with project-scoped skills is\n * given none of them. Re-scoping the agent to match the skills would put a global-by-default\n * agent under the project's ownership on nothing but a toggle. Anyone reading this line as a\n * missing `scope` derivation is re-deriving a reading that has already been rejected.\n */\nfunction applyAgentToggle(\n configs: AgentScopeConfig[],\n agent: AgentName,\n isSelected: boolean,\n): AgentScopeConfig[] {\n if (isSelected) {\n return configs.filter((ac) => ac.name !== agent);\n }\n\n const existingExcluded = configs.find((ac) => ac.name === agent && ac.excluded);\n if (existingExcluded) {\n return configs.map((ac) => {\n if (ac.name !== agent || !ac.excluded) return ac;\n const { excluded: _excluded, ...active } = ac;\n return active;\n });\n }\n return [...configs, { name: agent, scope: \"global\" as const }];\n}\n\n/**\n * True when an existing agent entry must outlive a domain-roster rebuild, which merges rather than\n * replaces. Two kinds survive:\n *\n * - Every excluded tombstone whose slot the rebuild leaves free, so a dual-scope pair (active\n * entry plus a tombstone at the other scope) survives preselection — the agent-side mirror of\n * the dual-scope fix in `populateFromSkillIds`. Deliberately NOT filtered by roster\n * membership; the slot test is what keeps a tombstone from landing beside an active entry it\n * cannot be masking.\n * - Every entry the project does not own, so a globally-installed agent outside the selected\n * domains' roster is never silently uninstalled by a project edit.\n *\n * Entries the roster itself rebuilds are excluded — `buildAgentConfigForName` re-derives those.\n */\nfunction survivesRosterRebuild(\n agentConfig: AgentScopeConfig,\n roster: ReadonlySet<AgentName>,\n rebuiltSlots: ReadonlySet<string>,\n): boolean {\n if (agentConfig.excluded) {\n return !rebuiltSlots.has(agentSlotKey(agentConfig.name, agentConfig.scope));\n }\n return !isProjectOwned(agentConfig) && !roster.has(agentConfig.name);\n}\n\n/**\n * Restores the `[P][G]` pair when re-selecting an inherited-global agent row whose\n * global install is recorded as a tombstone in the project snapshot — mirrors\n * reconcileSkillConfigs' restore branch.\n */\nfunction restoreDualScopeAgent(\n selectedAgents: AgentName[],\n agentConfigs: AgentScopeConfig[],\n agent: AgentName,\n) {\n return {\n selectedAgents: [...selectedAgents, agent],\n agentConfigs: [\n ...agentConfigs.filter((ac) => ac.name !== agent),\n { name: agent, scope: \"project\" as const },\n { name: agent, scope: \"global\" as const, excluded: true },\n ],\n };\n}\n\n/**\n * Next selectedAgents after a toggle. A deselect drops the agent; re-enabling a tombstoned\n * agent is already listed; a fresh add appends.\n */\nfunction nextSelectedAgents(\n selectedAgents: AgentName[],\n agent: AgentName,\n flags: { isSelected: boolean; isInList: boolean },\n): AgentName[] {\n if (flags.isSelected) return selectedAgents.filter((a) => a !== agent);\n if (flags.isInList) return selectedAgents;\n return [...selectedAgents, agent];\n}\n\n/** Builds a SkillConfig for a resolved skill ID, preferring saved config values. */\nfunction buildSkillConfigForId(id: SkillId, savedConfigs?: SkillConfig[] | null): SkillConfig {\n // Prefer project-scoped entry over global when duplicates exist (defensive)\n const saved =\n savedConfigs?.find((sc) => sc.id === id && !sc.excluded && sc.scope === \"project\") ??\n savedConfigs?.find((sc) => sc.id === id && !sc.excluded);\n return {\n id,\n scope: saved?.scope ?? \"global\",\n origin: saved?.origin ?? defaultOriginFor(matrix.skills[id]),\n };\n}\n\n/**\n * Builds an active AgentScopeConfig for a name, preferring a saved project-scoped\n * active entry. Mirrors buildSkillConfigForId on the agent path so preselection can\n * separate active-entry construction from tombstone preservation.\n */\nfunction buildAgentConfigForName(\n name: AgentName,\n savedConfigs?: AgentScopeConfig[],\n): AgentScopeConfig {\n // Prefer project-scoped active entry over global when duplicates exist.\n const saved =\n savedConfigs?.find((ac) => ac.name === name && !ac.excluded && ac.scope === \"project\") ??\n savedConfigs?.find((ac) => ac.name === name && !ac.excluded);\n return {\n name,\n scope: saved?.scope ?? \"global\",\n // Model and effort are the user's deliberate choice, not something the roster re-derives —\n // they survive the rebuild on the same terms as scope.\n ...(saved?.model !== undefined && { model: saved.model }),\n ...(saved?.effort !== undefined && { effort: saved.effort }),\n };\n}\n\n/** Restores skill configs for a domain: clears excluded flags on restored skills, adds new defaults for unknown skills. */\nfunction restoreSkillConfigs(\n existingConfigs: SkillConfig[],\n restoredIds: SkillId[],\n): SkillConfig[] {\n const restoredSet = new Set(restoredIds);\n const existingIds = new Set(existingConfigs.map((sc) => sc.id));\n\n const updated = existingConfigs.map((sc) => {\n if (!restoredSet.has(sc.id) || !sc.excluded) return sc;\n const { excluded: _excluded, ...active } = sc;\n return active;\n });\n\n const newConfigs = restoredIds.filter((id) => !existingIds.has(id)).map(createDefaultSkillConfig);\n\n return [...updated, ...newConfigs];\n}\n\n/**\n * Built-in agent names grouped by domain prefix. Custom domains return no preselected agents.\n * The consolidated `pm` and `reviewer` are cross-domain by role, so every domain rosters both;\n * the preselection union dedupes when several selected domains bring them.\n *\n * Exported ahead of a second production caller for the reason CLAUDE.md's Code Style exception\n * names: this is an identity roster more than one surface has to agree on. It, the grid's\n * `BUILT_IN_AGENT_GROUPS` and the generated `AGENT_NAMES` are three hand-or-machine-written\n * lists of the same set, and `tsc` only ever reconciled them for REMOVALS — an agent added to\n * the catalogue and to neither roster shipped unreachable through the wizard, six at a time.\n * `lib/wizard/agent-roster.test.ts` is the surface that reconciles them now.\n */\nexport const DOMAIN_AGENTS: Partial<Record<Domain, AgentName[]>> = {\n web: [\"web-developer\", \"web-researcher\", \"web-tester\", \"pm\", \"reviewer\"],\n api: [\"api-developer\", \"api-researcher\", \"api-tester\", \"pm\", \"reviewer\"],\n cli: [\"cli-developer\", \"cli-tester\", \"cli-researcher\", \"pm\", \"reviewer\"],\n ai: [\"ai-developer\", \"ai-researcher\", \"ai-tester\", \"pm\", \"reviewer\"],\n};\n\n/**\n * What an id this catalogue does not carry means, and what changes it.\n *\n * The outcome first, because it is the part the user cannot see: the skill reaches no screen,\n * so it is absent from everything the session goes on to write. Then the one reading a user can\n * act on — a marketplace this installation has not refreshed since the entry was written.\n *\n * `edit` classifies the same event far better downstream: `removalReason` in\n * `lib/skills/unresolved-skill-entries.ts` tells a marketplace drop from a local install whose\n * files are gone, and names the directory it looked in. None of that is reachable from here —\n * that classification is asynchronous and reads the filesystem, while this is a synchronous\n * store function holding only the matrix — so this line offers a remedy rather than a guess at\n * a reason it cannot establish.\n */\nfunction absentFromSourceWarning(skillId: SkillId): string {\n return (\n `Installed skill '${skillId}' is not present in the loaded source — it may have been ` +\n `removed or renamed. It is left out of this session's selection. Run ` +\n `'${CLI_INVOKE_COMMAND} update' to refresh the marketplace if you expect it to still be ` +\n `carried there.`\n );\n}\n\n/**\n * The same for a skill the catalogue DOES carry and no domain claims.\n *\n * {@link getCategoryDomain} reads `categories[category]?.domain`, so an undeclared category and\n * one declared without a `domain` are one answer here — and the wizard is organised by domain,\n * which is why an unplaceable category costs the skill its screen. Both ways out are the\n * source's: declare the category properly, or take the version of the source that already does.\n */\nfunction unplaceableCategoryWarning(skillId: SkillId, category: string): string {\n return (\n `Installed skill '${skillId}' has unknown category '${category}' — skipping. No domain in ` +\n `this source claims that category, so the wizard has no screen to place the skill on. ` +\n `Declare it with a 'domain' in the source's '${SKILL_CATEGORIES_PATH}', or run ` +\n `'${CLI_INVOKE_COMMAND} update' to refresh the marketplace.`\n );\n}\n\nfunction resolveSkillForPopulation(\n skillId: SkillId,\n): { domain: Domain; subcat: Category; techId: SkillId } | null {\n const { skills } = matrix;\n const skill = skills[skillId];\n if (!skill?.category) {\n warn(absentFromSourceWarning(skillId));\n return null;\n }\n\n const domain = getCategoryDomain(skill.category);\n if (!domain) {\n warn(unplaceableCategoryWarning(skillId, skill.category));\n return null;\n }\n\n // Boundary cast: domain lookup confirmed category exists in matrix\n const subcat = skill.category as Category;\n return { domain, subcat, techId: skillId };\n}\n\n/** Adds a skill to selections[domain][category] if absent; true when newly added. */\nfunction addToDomainSelections(\n selections: DomainSelections,\n domain: Domain,\n category: Category,\n skillId: SkillId,\n): boolean {\n const categorySelections = (selections[domain] ??= {});\n const skillList = (categorySelections[category] ??= []);\n if (skillList.includes(skillId)) return false;\n skillList.push(skillId);\n return true;\n}\n\n/** The `SkillConfig.origin` value an install mode writes for this skill. */\nfunction sourceForInstallMode(skill: ResolvedSkill, mode: Exclude<InstallMode, \"mixed\">): string {\n if (mode === \"eject\") return EJECT_SOURCE;\n\n return marketplaceSourceName(skill) ?? DEFAULT_PUBLIC_SOURCE_NAME;\n}\n\n/**\n * The install mode a persisted `origin` value stands for. The per-skill half of\n * `deriveInstallMode`, which asks the same question of a whole selection: `eject` names the\n * project's own copy and every other value names the marketplace the plugin comes from.\n */\nfunction installModeOfSource(origin: string | undefined): Exclude<InstallMode, \"mixed\"> {\n return origin === EJECT_SOURCE ? \"eject\" : \"plugin\";\n}\n\n/**\n * The cells of one skill's install-mode control, with the current mode selected.\n *\n * A skill nothing but the copy on disk backs gets the local cell ALONE — the grid cannot\n * express a plugin install that no marketplace could serve, so the refusal downstream is\n * a guard against callers reaching past this surface rather than the user's first\n * encounter with it.\n */\nfunction buildInstallModeOptions(\n skill: ResolvedSkill | undefined,\n selectedMode: Exclude<InstallMode, \"mixed\">,\n): SourceOption[] {\n const modes = isLocalOnlySkill(skill) ? LOCAL_ONLY_INSTALL_MODES : INSTALL_MODES;\n return modes.map((mode) => ({ mode, selected: mode === selectedMode }));\n}\n\n/**\n * The snapshot slots this session has emptied — an `(id, scope)` the hydration snapshot\n * holds ACTIVE that no live config entry occupies any more. The emptying leaves nothing behind to\n * render from: a PROJECT skill is dropped outright (applySkillRemoval leaves no tombstone, unlike\n * the global case), and so is ANY skill deselected while editing from global scope, where\n * `reconcileSkillConfigs` passes `null` so `applySkillRemoval` drops rather than tombstones. In\n * both the snapshot is the only surviving record, so without this set the row would vanish and the\n * user would lose sight of what saving is about to remove. Deliberately ungated on edit context:\n * `computeScopeDiff`, which the confirm step classifies removals with, has no global-scope gate\n * either, so neither surface may have one.\n *\n * Keyed per `(id, scope)` SLOT, mirroring `computeScopeDiff`'s removal match — removal is a\n * property of the slot, not of the id. Collapsing a dual-scope `[P][G]` pair to `[G]` empties the\n * PROJECT slot while the global one survives, so the skill renders twice on BOTH surfaces (`-` at\n * Project, `•`/lock at Global) instead of the survivor masking the loss. A tombstone OCCUPIES its\n * slot, so re-activating a masked global install is never a removal. Selection is not consulted:\n * `skillConfigs` is the same input the confirm step diffs, which is what keeps the two agreeing.\n *\n * Snapshot TOMBSTONES are deliberately not removal candidates — narrower than `computeScopeDiff`,\n * whose removal filter counts them. A tombstone is a MASK over a global install, not an install of\n * its own: dropping it deletes nothing (the global copy survives), so a red pending-removal row for\n * one would announce a deletion that never happens. No store transition reaches that shape anyway —\n * every path that drops a tombstone fills the same slot with an active entry (`toggleSkillScope`\n * P→G, `applySkillRemoval`'s dual-scope collapse).\n */\nfunction collectRemovedInstalledEntries(\n installedSkillConfigs: SkillConfig[] | null,\n skillConfigs: SkillConfig[],\n): SkillConfig[] {\n if (!installedSkillConfigs) return [];\n const occupiedSlots = new Set(skillConfigs.map((sc) => skillSlotKey(sc.id, sc.scope)));\n return installedSkillConfigs.filter(\n (sc) =>\n !sc.excluded &&\n !occupiedSlots.has(skillSlotKey(sc.id, sc.scope)) &&\n // A skill the marketplace no longer carries has nothing to render — hydration already\n // skipped it into unresolvableSkillIds, and getSkillById would throw on it downstream.\n !!matrix.skills[sc.id],\n );\n}\n\n/**\n * Every `(id, scope)` slot the hydration snapshot occupies — the baseline a Sources row is\n * \"added\" against, and the direct counterpart of `computeScopeDiff`'s `prevSkillKeySet`. Tombstones\n * count as occupied, exactly as that set does, so re-reading a stored tombstone never flags\n * a spurious addition.\n *\n * A missing snapshot (a first `init`, nothing installed at either scope) collapses to the EMPTY set\n * rather than to a distinct \"no baseline\" state, because the two are the same answer: an empty\n * baseline occupies no slot, so every row is new — which is what `classifyDiffRow` already tells the\n * confirm step for a null baseline, and what an empty snapshot already told this surface.\n */\nfunction collectInstalledSkillSlots(\n installedSkillConfigs: SkillConfig[] | null,\n): ReadonlySet<string> {\n if (!installedSkillConfigs) return new Set();\n return new Set(installedSkillConfigs.map((sc) => skillSlotKey(sc.id, sc.scope)));\n}\n\n/**\n * The `{ added: true }` fragment for a row whose SLOT is new this session, `{}` otherwise —\n * spread into the row so the Sources tab flags it with the info panel's added-diff marker (`+`).\n * Keying on the id alone would miss a skill adopted at project scope while it stays installed\n * globally: the id is old, but the project slot is new — which is exactly how `classifyDiffRow`\n * classifies the same change on the confirm step. Never gated on `isEditingFromGlobalScope`: an\n * addition is an addition regardless of edit context.\n */\nfunction addedSlotFlag(\n installedSkillSlots: ReadonlySet<string>,\n id: SkillId,\n scope: SkillScope | undefined,\n): { added?: true } {\n return installedSkillSlots.has(skillSlotKey(id, scope)) ? {} : { added: true };\n}\n\n/** Copy of the options with the persisted source's mode selected — for rows pinned to it. */\nfunction withSelectedMode(options: SourceOption[], source: string | undefined): SourceOption[] {\n const mode = installModeOfSource(source);\n return options.map((option) => ({ ...option, selected: option.mode === mode }));\n}\n\n/**\n * The per-skill inputs every source row shares: the canonical id, the live config entry driving\n * scope/lock classification, and the source options with the effective source preselected. A\n * pending-removal row re-pins that selection to its persisted origin (`withSelectedMode`).\n */\nfunction resolveSkillRowInputs(\n id: SkillId,\n skillConfigs: SkillConfig[],\n): { skillId: SkillId; configEntry: SkillConfig | undefined; options: SourceOption[] } {\n const skill = getSkillById(id);\n const configEntry = skillConfigs.find((sc) => sc.id === skill.id);\n const selectedSource = resolveEffectiveSource(\n configEntry?.origin,\n skill.activeSource?.name,\n primarySourceName(skill),\n );\n return {\n skillId: skill.id,\n configEntry,\n options: buildInstallModeOptions(skill, installModeOfSource(selectedSource)),\n };\n}\n\ntype SourceRowContext = {\n configEntry: SkillConfig | undefined;\n installedSkillConfigs: SkillConfig[] | null;\n isEditingFromGlobalScope: boolean;\n /** `(id, scope)` slots the snapshot occupies — the baseline each row's `+` derives from. */\n installedSkillSlots: ReadonlySet<string>;\n};\n\n/**\n * The inert row for a snapshot slot this session emptied. Carries the PERSISTED scope and\n * source so the row stays visible and shows what saving removes. Deliberately NOT readOnly: that\n * renders a lock, which reads as \"installed globally\" rather than \"about to be removed\". Carries no\n * added flag either — the slot it renders comes FROM the snapshot, so it can never be new this\n * session.\n */\nfunction toPendingRemovalRow(\n skillId: SkillId,\n options: SourceOption[],\n removedInstalledEntry: SkillConfig,\n): SourceRow {\n return {\n skillId,\n options: withSelectedMode(options, removedInstalledEntry.origin),\n scope: removedInstalledEntry.scope,\n disabled: true,\n };\n}\n\n/**\n * True when an already-emitted row renders the snapshot entry's `(id, scope)` slot, which makes a\n * pending-removal row for it a duplicate rather than a loss.\n *\n * The one shape that reaches this: a global install adopted at project scope WITHOUT a tombstone\n * (`[G]` snapshot, `[P]` live — the historical no-tombstone dual-scope shape `computeScopeDiff`\n * calls an inherited global). Its global slot is unoccupied in the live config, yet the locked\n * global row already renders it FROM the snapshot, so the install is inherited, not removed.\n */\nfunction isSlotAlreadyRendered(rows: SourceRow[], removedInstalledEntry: SkillConfig): boolean {\n const slot = skillSlotKey(removedInstalledEntry.id, removedInstalledEntry.scope);\n return rows.some((row) => skillSlotKey(row.skillId, row.scope) === slot);\n}\n\n/**\n * The locked row for a global install this project may not change from here — the lock reads\n * \"installed globally, not yours to edit at project scope\". Its source is pinned to the installed\n * one, and its added flag derives from the GLOBAL slot, so an install the project merely inherits\n * stays a plain lock rather than reading as new.\n */\nfunction toLockedGlobalRow(\n skillId: SkillId,\n options: SourceOption[],\n installedSource: string | undefined,\n installedSkillSlots: ReadonlySet<string>,\n): SourceRow {\n return {\n skillId,\n options: withSelectedMode(options, installedSource),\n scope: \"global\" as const,\n readOnly: true,\n ...addedSlotFlag(installedSkillSlots, skillId, \"global\"),\n };\n}\n\n/**\n * Classifies one skill's LIVE config entry into its source-grid rows: a locked global row for\n * excluded-global entries, locked global + editable project rows for skills re-scoped\n * global→project this session, or a single row otherwise. Pending-removal rows are not derived\n * here — they belong to snapshot slots with no live entry left (see `toPendingRemovalRow`).\n */\nfunction classifySkillSourceRows(\n skillId: SkillId,\n options: SourceOption[],\n context: SourceRowContext,\n): SourceRow[] {\n const { configEntry, installedSkillConfigs, isEditingFromGlobalScope, installedSkillSlots } =\n context;\n const installedGlobalConfig = findGlobalActive(installedSkillConfigs ?? [], skillId);\n\n const isExcludedGlobal = configEntry?.excluded && configEntry.scope === \"global\";\n if (isExcludedGlobal && !isEditingFromGlobalScope) {\n return [\n toLockedGlobalRow(\n skillId,\n options,\n installedGlobalConfig?.origin ?? configEntry.origin,\n installedSkillSlots,\n ),\n ];\n }\n\n if (!isEditingFromGlobalScope && installedGlobalConfig && configEntry?.scope === \"project\") {\n // Skill toggled from global to project — emit locked global copy + editable project copy. Each\n // half derives its own added flag from its own slot, so the `+` lands on the newly occupied\n // PROJECT row while the still-installed global row stays a plain lock.\n return [\n toLockedGlobalRow(skillId, options, installedGlobalConfig.origin, installedSkillSlots),\n {\n skillId,\n options,\n scope: \"project\" as const,\n ...addedSlotFlag(installedSkillSlots, skillId, \"project\"),\n },\n ];\n }\n\n const readOnly = !isEditingFromGlobalScope && !!installedGlobalConfig;\n return [\n {\n skillId,\n options,\n ...(configEntry?.scope !== undefined && { scope: configEntry.scope }),\n ...(readOnly ? { readOnly: true as const } : {}),\n ...addedSlotFlag(installedSkillSlots, skillId, configEntry?.scope),\n },\n ];\n}\n\n/**\n * Visual grouping order in source-grid: global readOnly, global editable, then project. A\n * pending-removal (disabled) row is NOT a separate tier — it sorts by its own scope so it renders\n * inline with the other rows of that scope, matching the info panel, which shows removals in place\n * rather than in a dedicated section. Its trailing position within a scope section falls out of the\n * removal rows being appended after every live row, which the stable sort preserves.\n */\nfunction sourceRowSortTier(row: SourceRow): number {\n if (row.scope === \"global\" && row.readOnly) return 0;\n if (row.scope === \"global\") return 1;\n return 2;\n}\n\n/**\n * Wizard step identifiers for the multi-step init/edit flow.\n *\n * Progression: stack -> domains -> build -> sources -> agents -> confirm\n * The \"stack\" step shows all stacks + \"Start from scratch\" in a unified list.\n * The \"domains\" step shows domain selection (web, api, cli, mobile, shared).\n * Navigation is tracked via the `history` stack for goBack() support.\n */\nexport type WizardStep =\n | \"stack\" // Select stack or \"Start from scratch\"\n | \"domains\" // Select domains to configure\n | \"build\" // CategoryGrid for technology selection\n | \"sources\" // Choose skill sources (recommended vs custom)\n | \"agents\" // Select which agents to compile\n | \"confirm\"; // Final confirmation\n\n/** How the user builds their config: from a pre-built stack, or skill-by-skill. */\ntype WizardApproach = \"stack\" | \"scratch\";\n\n/** For the stack approach: use the stack's defaults, or customize its skills. */\ntype StackAction = \"defaults\" | \"customize\";\n\nexport const WIZARD_STEP_ORDER = [\n \"stack\",\n \"domains\",\n \"build\",\n \"sources\",\n \"agents\",\n \"confirm\",\n] as const satisfies readonly WizardStep[];\n\n/** Whether the loaded source offers any stack to choose between. */\nfunction offersStacks(): boolean {\n return matrix.suggestedStacks.length > 0;\n}\n\n/**\n * The steps this session's wizard actually runs, in order.\n *\n * `WIZARD_STEP_ORDER` is every step the wizard has; this is the ones it has\n * THIS time. The stack step exists only where there is a stack to choose, so a\n * source that ships none — the built-in catalogue standing in for the default\n * public marketplace alone — drops it: hydration opens past it (see\n * {@link FIRST_STEP_WITHOUT_STACKS}) and the tab bar is drawn without it. One\n * answer to \"does this run have a stack step\", so the tabs cannot advertise a\n * step the flow does not have.\n */\nexport function getActiveStepFlow(): WizardStep[] {\n if (offersStacks()) return [...WIZARD_STEP_ORDER];\n return WIZARD_STEP_ORDER.filter((step) => step !== \"stack\");\n}\n\n/** The flow's steps before the active one; none when the step is outside the flow. */\nfunction stepsBefore(flow: WizardStep[], step: WizardStep): WizardStep[] {\n const index = flow.indexOf(step);\n return index < 0 ? [] : flow.slice(0, index);\n}\n\n/**\n * Wizard store state and actions.\n *\n * The store uses a composition pattern: small, focused actions that each mutate\n * one or two state fields. Wizard step components compose these actions to build\n * up the full selection state incrementally (domains -> categories -> skills -> sources).\n *\n * State flow: stack/scratch selection -> domain selection -> per-domain skill\n * selection (build step) -> source customization -> agent selection -> confirmation.\n */\nexport type WizardState = {\n step: WizardStep;\n\n approach: WizardApproach | null;\n selectedStackId: string | null;\n stackAction: StackAction | null;\n\n selectedDomains: Domain[];\n\n currentDomainIndex: number;\n domainSelections: DomainSelections;\n /** Snapshot of stack-provided domain selections for restoration on domain re-toggle */\n _stackDomainSelections: DomainSelections | null;\n\n showLabels: boolean;\n\n skillConfigs: SkillConfig[];\n focusedSkillId: SkillId | null;\n\n /**\n * Skill ids from the saved config that could NOT be resolved against the currently-loaded\n * source matrix this session (`populateFromSkillIds` skipped them, warning per skill). The\n * wizard cannot represent them, so they are absent from its result and the merge removes them\n * like any other absent entry — this list is what lets `edit` name each one and say why it went\n * rather than dropping it in silence.\n */\n unresolvableSkillIds: SkillId[];\n\n showInfo: boolean;\n\n selectedAgents: AgentName[];\n agentConfigs: AgentScopeConfig[];\n focusedAgentId: AgentName | null;\n\n /** Snapshot of configs that were installed before the wizard opened, used for diff rendering */\n installedSkillConfigs: SkillConfig[] | null;\n installedAgentConfigs: AgentScopeConfig[] | null;\n\n /** True when running init (first-time setup), false when editing an existing installation */\n isInitMode: boolean;\n\n /** When true, scope toggling is disabled (editing from ~/.claude/ with no project to move items to) */\n isEditingFromGlobalScope: boolean;\n\n /** Temporary toast message shown in the wizard (auto-cleared after timeout) */\n toastMessage: string | null;\n\n /** Global skill configs to pre-select when a stack or scratch is chosen in init. Set by use-wizard-initialization. */\n globalPreselections: SkillConfig[] | null;\n\n /** Global agent preselections to restore after selectStack wipes selectedAgents/agentConfigs. Set by use-wizard-initialization. */\n globalAgentPreselections: { agents: AgentName[]; configs: AgentScopeConfig[] } | null;\n\n history: WizardStep[];\n\n /**\n * Navigate to a wizard step, pushing the current step onto history.\n * @param step - Target step to navigate to\n *\n * Side effects: sets `step`, appends previous step to `history`\n */\n setStep: (step: WizardStep) => void;\n /**\n * Set the wizard approach (stack-based or build-from-scratch).\n * @param approach - \"stack\" to use a pre-built template, \"scratch\" to select skills manually, null to reset\n *\n * Side effects: sets `approach`\n */\n setApproach: (approach: WizardApproach | null) => void;\n /**\n * Select a stack by ID, or null to deselect.\n * @param stackId - Stack identifier from suggestedStacks, or null to clear\n *\n * Side effects: sets `selectedStackId`\n */\n selectStack: (stackId: string | null) => void;\n /**\n * Set how to apply the selected stack.\n * @param action - \"defaults\" to use stack as-is, \"customize\" to enter the build step\n *\n * Side effects: sets `stackAction`\n */\n setStackAction: (action: StackAction) => void;\n /**\n * Prepare a build with no stack behind it — what \"Start from scratch\" means.\n *\n * Two surfaces arrive here and must agree on what it is: the stack step's\n * scratch row, and the hydration that opens the wizard past a stack step the\n * loaded source gave nothing to show on.\n *\n * Side effects: clears every stack-derived selection (via `selectStack(null)`),\n * sets `approach` to \"scratch\", restores `selectedAgents` / `agentConfigs` from\n * `globalAgentPreselections`, populates selections from `globalPreselections`,\n * and selects the scratch domains. Does NOT navigate — the caller owns the step.\n */\n startFromScratch: () => void;\n /**\n * Pre-populate domainSelections from a flat list of installed skill IDs.\n *\n * Used by `npx agents-inc edit` to restore wizard state from existing project config.\n * Looks up each skill's category and domain, warns for unresolvable skills.\n *\n * @param skillIds - Flat array of currently installed skill IDs\n * @param skills - Skill lookup providing category and displayName per skill ID\n * @param categories - Category definitions used to resolve category -> domain mapping\n *\n * Side effects: sets `domainSelections`, sets `selectedDomains` to domains found in the provided skill IDs\n */\n populateFromSkillIds: (skillIds: SkillId[], savedConfigs?: SkillConfig[]) => void;\n /**\n * Toggle a domain on or off in the selectedDomains list.\n * @param domain - Domain to toggle\n *\n * Side effects: adds or removes from `selectedDomains`\n */\n toggleDomain: (domain: Domain) => void;\n /**\n * Toggle a skill selection within a domain's category.\n *\n * When exclusive is true (radio behavior), selecting a new skill replaces any\n * existing selection in that category. When false (checkbox behavior),\n * the skill is added to or removed from the selection array.\n *\n * @param domain - Domain containing the category\n * @param category - Category within the domain\n * @param technology - Skill ID to toggle\n * @param exclusive - If true, only one skill can be selected per category (radio)\n *\n * Side effects: updates `domainSelections[domain][category]`\n */\n toggleTechnology: (\n domain: Domain,\n category: Category,\n technology: SkillId,\n exclusive: boolean,\n ) => void;\n /**\n * Advance to the next domain in the build step.\n * @returns true if advanced, false if already at the last domain\n *\n * Side effects: increments `currentDomainIndex`\n */\n nextDomain: () => boolean;\n /**\n * Go back to the previous domain in the build step.\n * @returns true if moved back, false if already at the first domain\n *\n * Side effects: decrements `currentDomainIndex`\n */\n prevDomain: () => boolean;\n /**\n * Set the current domain index directly.\n * @param index - Index to set (0-based, must be within selectedDomains range)\n *\n * Side effects: sets `currentDomainIndex` if index is valid, otherwise no-op\n */\n setCurrentDomainIndex: (index: number) => void;\n /** Toggle compatibility label visibility on skill tags in the build step grid. */\n toggleShowLabels: () => void;\n /**\n * Derive the install mode from skillConfigs source values.\n * If all skills use \"eject\" source, returns \"eject\". If all use non-eject, returns \"plugin\".\n * If mixed, returns \"mixed\". Returns \"eject\" when no skills are configured.\n */\n deriveInstallMode: () => InstallMode;\n /**\n * Toggle the scope of a specific skill between \"project\" and \"global\".\n * @param skillId - Skill to toggle scope for\n *\n * Side effects: updates `skillConfigs` entry for the skill\n */\n toggleSkillScope: (skillId: SkillId) => void;\n /**\n * Set the currently focused skill ID in the build step (for S hotkey).\n * @param id - Skill ID to focus, or null to clear\n *\n * Side effects: sets `focusedSkillId`\n */\n setFocusedSkillId: (id: SkillId | null) => void;\n /**\n * Seed `focusedSkillId` to the skill the build-step grid focuses first for the\n * active domain (row 0, col 0 of the filtered category rows). Runs synchronously\n * at build-step entry and on every domain change so the `s` scope hotkey — which\n * reads `focusedSkillId` — always resolves the visually-focused skill, with no\n * dependency on CategoryGrid's post-mount effect.\n *\n * Side effects: sets `focusedSkillId` (null when the active domain has no skills)\n */\n seedFocusedSkillForActiveDomain: () => void;\n /**\n * Set how a specific skill is installed: the project's own copy, or the marketplace plugin.\n * @param skillId - Skill to configure the install mode for\n * @param mode - `eject` for a local copy, `plugin` for the one marketplace\n * @param scope - Acting scope from the Sources row: only the active entry at this scope is\n * updated; a masked global tombstone for the same id keeps its source.\n *\n * Refuses a project-context call that targets a global slot the hydration snapshot already\n * owns ({@link isInheritedGlobalSlot}) — a project edit may not change how a global install is\n * installed, the same authority the Sources grid enforces by rendering that row inert.\n *\n * Side effects: updates the active `skillConfigs` entry for the skill at `scope`, writing the\n * `origin` value the mode resolves to. No-op with a warning on an empty skill id; silent no-op\n * on a refused global slot.\n */\n setInstallMode: (\n skillId: SkillId,\n mode: Exclude<InstallMode, \"mixed\">,\n scope: SkillScope | undefined,\n ) => void;\n /** Toggle the info overlay (selected skills and agents). */\n toggleInfo: () => void;\n /** Set a temporary toast message, or null to clear it. */\n setToastMessage: (message: string | null) => void;\n /**\n * Navigate to the previous wizard step using the history stack.\n * No-op when history is empty (e.g., edit flow starting at a mid-wizard step).\n *\n * Side effects: pops from `history`, sets `step` to the popped value\n */\n goBack: () => void;\n /**\n * Toggle an agent on or off in the selectedAgents list.\n * @param agent - Agent name to toggle\n *\n * Side effects: adds or removes from `selectedAgents`, syncs `agentConfigs`\n */\n toggleAgent: (agent: AgentName) => void;\n /**\n * Toggle the scope of a specific agent between \"project\" and \"global\".\n * @param agentName - Agent to toggle scope for\n *\n * Side effects: updates `agentConfigs` entry for the agent\n */\n toggleAgentScope: (agentName: AgentName) => void;\n /**\n * Set the currently focused agent ID in the agents step (for S hotkey).\n * @param id - Agent name to focus, or null to clear\n *\n * Side effects: sets `focusedAgentId`\n */\n setFocusedAgentId: (id: AgentName | null) => void;\n /**\n * Seed `focusedAgentId` to the row the agents grid focuses first, unless a\n * focused agent is already recorded — the grid restores that one instead.\n *\n * Runs on entry to the agents step so the value is written before any frame\n * renders or input is processed. The `s` scope toggle in `wizard.tsx` reads\n * `focusedAgentId` synchronously, and terminal input is not ordered against\n * render-phase effects: a post-mount seed can lose to a buffered keystroke.\n *\n * Side effects: sets `focusedAgentId`\n */\n seedFocusedAgent: () => void;\n /**\n * Preselect agents based on selected domains from the first wizard step.\n * Matches domains against DOMAIN_AGENTS mapping.\n * Optional agents (meta/pattern) are excluded.\n *\n * The from-scratch path only: with a stack chosen, its declared roster stands and\n * this is a no-op. Selecting a stack is the statement of which sub-agents an\n * installation gets, and the user edits that roster in the agents step.\n *\n * Side effects: replaces `selectedAgents` with computed preselection, unless a\n * stack is selected\n */\n preselectAgentsFromDomains: () => void;\n /**\n * Preselect agents for a chosen stack: merges the stack's agent keys with global\n * agent preselections, preserving dual-scope tombstones. Parallels\n * populateFromSkillIds on the skill path.\n *\n * This is the roster the install gets — nothing downstream re-derives it.\n *\n * Side effects: replaces `selectedAgents` and `agentConfigs` with the merged result\n */\n preselectAgentsFromStack: (stackAgents: AgentName[]) => void;\n /** Reset all wizard state to initial values. */\n reset: () => void;\n\n /**\n * Collect all selected skill IDs across all domains and categories.\n * @returns Flat array of every selected SkillId (may contain duplicates if shared across domains)\n */\n getAllSelectedTechnologies: () => SkillId[];\n /**\n * Group selected skill IDs by domain.\n * @returns Partial record mapping each domain with selections to its skill ID array\n */\n getSelectedTechnologiesPerDomain: () => Partial<Record<Domain, SkillId[]>>;\n /**\n * Get the domain currently visible in the build step.\n * @returns The domain at currentDomainIndex, or null if no domains are selected\n */\n getCurrentDomain: () => Domain | null;\n /**\n * Count total selected technologies across all domains.\n * @returns Number of selected skill IDs\n */\n getTechnologyCount: () => number;\n /**\n * Compute which wizard steps are completed and which are skipped.\n * Used by WizardTabs to render step progress indicators. Both lists are read\n * against {@link getActiveStepFlow} — a step this run never has cannot be one\n * it completed.\n * @returns Object with completedSteps and skippedSteps string arrays\n */\n getStepProgress: () => { completedSteps: WizardStep[]; skippedSteps: WizardStep[] };\n /** @returns true if there is a next domain after the current one */\n canGoToNextDomain: () => boolean;\n /** @returns true if there is a previous domain before the current one */\n canGoToPreviousDomain: () => boolean;\n\n /**\n * Build the source selection rows for the sources step UI.\n *\n * For each selected technology, resolves the canonical skill ID and marks which of the two\n * install modes its persisted `origin` stands for.\n *\n * @returns Array of row objects, one per selected technology, each containing:\n * - `skillId` - Canonical resolved skill ID\n * - `options` - The two install-mode cells, with the current one selected\n */\n buildSourceRows: () => SourceRow[];\n};\n\n/** State-only fields from WizardState (excludes actions/getters). Used to type createInitialState(). */\ntype WizardStateData = Pick<\n WizardState,\n | \"step\"\n | \"approach\"\n | \"selectedStackId\"\n | \"stackAction\"\n | \"selectedDomains\"\n | \"currentDomainIndex\"\n | \"domainSelections\"\n | \"_stackDomainSelections\"\n | \"showLabels\"\n | \"skillConfigs\"\n | \"focusedSkillId\"\n | \"unresolvableSkillIds\"\n | \"showInfo\"\n | \"selectedAgents\"\n | \"agentConfigs\"\n | \"focusedAgentId\"\n | \"installedSkillConfigs\"\n | \"installedAgentConfigs\"\n | \"isInitMode\"\n | \"isEditingFromGlobalScope\"\n | \"toastMessage\"\n | \"globalPreselections\"\n | \"globalAgentPreselections\"\n | \"history\"\n>;\n\nexport const createInitialState = (overrides?: Partial<WizardStateData>): WizardStateData => ({\n step: \"stack\",\n approach: null,\n selectedStackId: null,\n stackAction: null,\n selectedDomains: [],\n currentDomainIndex: 0,\n domainSelections: {},\n /** Snapshot of domainSelections from populateFromSkillIds, used to restore on domain re-toggle */\n _stackDomainSelections: null,\n showLabels: false,\n skillConfigs: [],\n focusedSkillId: null,\n unresolvableSkillIds: [],\n showInfo: false,\n selectedAgents: [],\n agentConfigs: [],\n focusedAgentId: null,\n installedSkillConfigs: null,\n installedAgentConfigs: null,\n isInitMode: false,\n isEditingFromGlobalScope: false,\n toastMessage: null,\n globalPreselections: null,\n globalAgentPreselections: null,\n history: [],\n ...overrides,\n});\n\n/**\n * Writes the focus each step opens on, synchronously, as the step is entered.\n *\n * Both grids highlight a row from their first frame, and both scope toggles read\n * the focused id out of this store the moment a key arrives. Terminal input is not\n * ordered against render-phase effects, so a focus seeded after mount can lose to\n * a keystroke that was already buffered — which is why entry seeds it instead.\n */\nfunction seedFocusForStep(\n step: WizardStep,\n actions: Pick<WizardState, \"seedFocusedSkillForActiveDomain\" | \"seedFocusedAgent\">,\n): void {\n if (step === \"build\") actions.seedFocusedSkillForActiveDomain();\n if (step === \"agents\") actions.seedFocusedAgent();\n}\n\nexport const useWizardStore = create<WizardState>((set, get) => ({\n ...createInitialState(),\n\n setStep: (step) => {\n set((state) => ({\n step,\n history: [...state.history, state.step],\n }));\n seedFocusForStep(step, get());\n },\n\n setApproach: (approach) => set({ approach }),\n\n selectStack: (stackId) =>\n set({\n selectedStackId: stackId,\n domainSelections: {},\n _stackDomainSelections: null,\n selectedDomains: [],\n skillConfigs: [],\n selectedAgents: [],\n agentConfigs: [],\n currentDomainIndex: 0,\n stackAction: null,\n }),\n\n setStackAction: (action) => set({ stackAction: action }),\n\n startFromScratch: () => {\n // selectStack(null) wipes the agent selections along with the stack's, so the\n // global ones are put back rather than left as collateral.\n get().selectStack(null);\n get().setApproach(\"scratch\");\n\n const { globalAgentPreselections, globalPreselections } = get();\n if (globalAgentPreselections) {\n set({\n selectedAgents: globalAgentPreselections.agents,\n agentConfigs: globalAgentPreselections.configs,\n });\n }\n if (globalPreselections?.length) {\n get().populateFromSkillIds(\n globalPreselections.map((skill) => skill.id),\n globalPreselections,\n );\n }\n\n // Additive: a scratch domain the preselections already brought stays on.\n for (const domain of DEFAULT_SCRATCH_DOMAINS) {\n if (!get().selectedDomains.includes(domain)) get().toggleDomain(domain);\n }\n },\n\n populateFromSkillIds: (skillIds, savedConfigs) =>\n set(() => {\n const domainSelections: DomainSelections = {};\n const resolvedSkillIds: SkillId[] = [];\n const unresolvableSkillIds: SkillId[] = [];\n\n for (const skillId of skillIds) {\n const resolved = resolveSkillForPopulation(skillId);\n if (!resolved) {\n unresolvableSkillIds.push(skillId);\n continue;\n }\n\n const { domain, subcat, techId } = resolved;\n if (addToDomainSelections(domainSelections, domain, subcat, techId)) {\n resolvedSkillIds.push(techId);\n }\n }\n\n const selectedDomains = orderDomains(typedKeys<Domain>(domainSelections));\n\n const skillConfigs: SkillConfig[] = resolvedSkillIds.map((id) =>\n buildSkillConfigForId(id, savedConfigs),\n );\n\n // Preserve excluded entries so they flow through to wizard result.\n // Allow an excluded tombstone to coexist with an active entry for the\n // same skill id at a different scope (render layer computes secondaryScope\n // from the pair) — and only at a different one.\n const excludedConfigs = skillTombstonesOutsideRebuild(savedConfigs ?? [], skillConfigs);\n\n return {\n domainSelections,\n _stackDomainSelections: structuredClone(domainSelections),\n selectedDomains,\n skillConfigs: [...skillConfigs, ...excludedConfigs],\n unresolvableSkillIds,\n };\n }),\n\n toggleDomain: (domain) =>\n set((state) => {\n const isSelected = state.selectedDomains.includes(domain);\n if (isSelected) {\n const { [domain]: _removed, ...remainingSelections } = state.domainSelections;\n const removedSkillIds = _removed\n ? collectSkillIdsFromSelections(_removed)\n : new Set<SkillId>();\n\n return {\n selectedDomains: state.selectedDomains.filter((d) => d !== domain),\n domainSelections: remainingSelections,\n // Global-scope edit: no overlay, so deselecting a domain uninstalls its skills cleanly\n // rather than tombstoning them in the global config.\n skillConfigs: applySkillRemoval(\n state.skillConfigs,\n removedSkillIds,\n state.isEditingFromGlobalScope ? null : state.installedSkillConfigs,\n ),\n };\n }\n\n // Restore stack selections for this domain if a stack snapshot exists\n const stackSelections = state._stackDomainSelections?.[domain];\n if (stackSelections) {\n const restoredSkillIds = [...collectSkillIdsFromSelections(stackSelections)];\n\n return {\n selectedDomains: orderDomains([...state.selectedDomains, domain]),\n domainSelections: {\n ...state.domainSelections,\n [domain]: structuredClone(stackSelections),\n },\n skillConfigs: restoreSkillConfigs(state.skillConfigs, restoredSkillIds),\n };\n }\n\n return {\n selectedDomains: orderDomains([...state.selectedDomains, domain]),\n };\n }),\n\n toggleTechnology: (domain, category, technology, exclusive) =>\n set((state) => {\n const installed = state.installedSkillConfigs ?? [];\n const currentSelections = state.domainSelections[domain]?.[category] || [];\n const isSelected = currentSelections.includes(technology);\n\n // Block a GLOBAL-OWNED entry from being changed at project scope. On a SELECT only the\n // active-global arm applies (an inherited-global row is read-only in both directions); the\n // stale-collapse arm is a deselect guard, kept behind isSelected so the re-select restore\n // path (reconcileSkillConfigs rebuilds `[P][G]`) still runs. The project half of a\n // persisted `[P][G]` pair is project-owned and passes both ways.\n const isGlobalLocked = isSelected\n ? isGloballyLockedSkill(installed, state.skillConfigs, technology)\n : hasGlobalActive(installed, technology);\n if (isGlobalLocked && !state.isEditingFromGlobalScope) {\n return { toastMessage: TOAST_MESSAGES.GLOBAL_SKILLS_LOCKED };\n }\n\n // In exclusive mode, selecting a new skill replaces the current one. Block if that would\n // implicitly drop a skill this scope may not drop THIS WAY: a radio swap must never\n // tombstone a global install, and never unmask one either.\n if (exclusive && !isSelected) {\n const wouldDropLockedSkill = currentSelections.some((selectedId) =>\n blocksExclusiveSwap(installed, state.skillConfigs, selectedId),\n );\n if (wouldDropLockedSkill && !state.isEditingFromGlobalScope) {\n return { toastMessage: TOAST_MESSAGES.GLOBAL_SKILLS_LOCKED };\n }\n }\n\n let newSelections: SkillId[];\n if (exclusive) {\n newSelections = isSelected ? [] : [technology];\n } else {\n newSelections = isSelected\n ? currentSelections.filter((t) => t !== technology)\n : [...currentSelections, technology];\n }\n\n const removed = currentSelections.filter((id) => !newSelections.includes(id));\n const added = newSelections.filter((id) => !currentSelections.includes(id));\n\n const skillConfigs = reconcileSkillConfigs(\n state.skillConfigs,\n added,\n removed,\n state.installedSkillConfigs,\n state.isEditingFromGlobalScope,\n );\n\n // A dual-scope deselect collapses to a single active inherited-global entry, so the\n // skill is still genuinely active. Keep it in the domain selection (mirroring what a\n // save-and-reopen re-derives via populateFromSkillIds) instead of dropping it purely\n // because it left the pre-removal selection array. A genuine full removal leaves no\n // active entry and still drops normally.\n const stillActiveAfterRemoval =\n isSelected &&\n !newSelections.includes(technology) &&\n (hasProjectActive(skillConfigs, technology) || hasGlobalActive(skillConfigs, technology));\n const resolvedSelections = stillActiveAfterRemoval\n ? [...newSelections, technology]\n : newSelections;\n\n return {\n skillConfigs,\n domainSelections: {\n ...state.domainSelections,\n [domain]: {\n ...state.domainSelections[domain],\n [category]: resolvedSelections,\n },\n },\n };\n }),\n\n nextDomain: () => {\n const state = get();\n if (state.currentDomainIndex < state.selectedDomains.length - 1) {\n set({\n currentDomainIndex: state.currentDomainIndex + 1,\n });\n get().seedFocusedSkillForActiveDomain();\n return true;\n }\n return false;\n },\n\n prevDomain: () => {\n const state = get();\n if (state.currentDomainIndex > 0) {\n set({\n currentDomainIndex: state.currentDomainIndex - 1,\n });\n get().seedFocusedSkillForActiveDomain();\n return true;\n }\n return false;\n },\n\n setCurrentDomainIndex: (index) => {\n const state = get();\n if (index >= 0 && index < state.selectedDomains.length) {\n set({ currentDomainIndex: index });\n get().seedFocusedSkillForActiveDomain();\n }\n },\n\n toggleShowLabels: () => set((state) => ({ showLabels: !state.showLabels })),\n\n deriveInstallMode: (): InstallMode => {\n const { skillConfigs } = get();\n return sharedDeriveInstallMode(skillConfigs);\n },\n\n toggleSkillScope: (skillId) =>\n set((state) => {\n // Unreachable in production and deliberately uncovered here. `toggleFocusedScope` in\n // components/wizard/wizard.tsx is the only caller of this action and of toggleAgentScope,\n // and it emits the refusal toast and returns before either is called — so a unit spec\n // aimed at this line pins a state the product cannot enter, and stays green if the\n // component guard is deleted. The refusal a user can reach is asserted through the `s`\n // key in e2e/interactive/edit-wizard-navigation.e2e.test.ts, beside the project-scope\n // toggle it must not swallow.\n if (state.isEditingFromGlobalScope) return state;\n\n const config = state.skillConfigs.find((sc) => sc.id === skillId && !sc.excluded);\n if (!config) return state;\n\n // Guard: block project eject → global when global eject already exists (would overwrite)\n if (wouldOverwriteGlobalEject(config, state.skillConfigs, state.installedSkillConfigs)) {\n return { toastMessage: TOAST_MESSAGES.ALREADY_EJECTED_AT_GLOBAL };\n }\n\n // A real global install exists when the snapshot carries EITHER an active global entry\n // or a global tombstone: a tombstone means the skill IS installed globally and this\n // project was overriding it. Both must re-create the tombstone on a G→P toggle, so an\n // in-session collapse→`s` restores a genuine `[P][G]` pair rather than a bare `[P]` that\n // loses the still-real global install. (Matches the agent-path derivation, which already\n // counts tombstones.)\n const wasInstalledGlobally =\n state.installedSkillConfigs?.some((sc) => sc.id === skillId && sc.scope === \"global\") ??\n false;\n const newScope = config.scope === \"project\" ? (\"global\" as const) : (\"project\" as const);\n\n const rescoped = state.skillConfigs.map((sc) =>\n sc.id === skillId && !sc.excluded ? { ...sc, scope: newScope } : sc,\n );\n\n if (newScope === \"project\") {\n // Moving global → project: add the excluded global tombstone if not already there.\n // Gated on wasInstalledGlobally so fresh init toggles don't create spurious tombstones.\n const needsTombstone =\n wasInstalledGlobally && !rescoped.some((sc) => sc.id === skillId && sc.excluded);\n return {\n skillConfigs: needsTombstone\n ? [\n ...rescoped,\n { id: skillId, scope: \"global\" as const, excluded: true, origin: config.origin },\n ]\n : rescoped,\n };\n }\n\n // Moving project → global: always drop any excluded global tombstone for this id.\n // An active entry at global scope supersedes any tombstone at the same scope — the\n // invariant \"no active + tombstone at the same (id, scope)\" must hold. Unconditional\n // removal (not gated on wasInstalledGlobally) heals the case where the prior\n // G→P produced a tombstone that installedSkillConfigs-derived wasInstalledGlobally\n // cannot see (because its `!sc.excluded` filter ignores the tombstone itself).\n return { skillConfigs: rescoped.filter((sc) => !(sc.id === skillId && sc.excluded)) };\n }),\n\n setFocusedSkillId: (id) => set({ focusedSkillId: id }),\n\n seedFocusedSkillForActiveDomain: () => {\n const state = get();\n // Mirror the build-step renderer's domain fallback (use-build-step-props.ts):\n // when no domain is selected the grid still renders FALLBACK_DOMAIN and\n // highlights a cell, so the seed must resolve that same domain — never null\n // while a cell is visibly focused — or the cold `s` toggle no-ops on a desync.\n const domain = state.getCurrentDomain() ?? FALLBACK_DOMAIN;\n const categories = buildCategoriesForDomain(\n domain,\n state.getAllSelectedTechnologies(),\n undefined,\n state.skillConfigs,\n );\n set({ focusedSkillId: categories[0]?.options[0]?.id ?? null });\n },\n\n setInstallMode: (skillId, mode, scope) =>\n set((state) => {\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- SkillId is a string union with no empty member, so the type rules this out; the guard is for a runtime caller handing over an empty id\n if (!skillId) {\n warn(\"Ignoring setInstallMode call with empty skillId\");\n return state;\n }\n // Block a GLOBAL-OWNED slot from being reconfigured at project scope — the authority the\n // Sources grid already enforces by rendering that row inert, held here so it does not rest\n // on the UI alone. Silent: the grid never offers the row, so a refused call is a caller\n // reaching past it.\n if (\n isInheritedGlobalSlot(state.installedSkillConfigs, skillId, scope) &&\n !state.isEditingFromGlobalScope\n ) {\n return state;\n }\n const origin = sourceForInstallMode(getSkillById(skillId), mode);\n return {\n skillConfigs: withActiveEntryOrigin(state.skillConfigs, skillId, scope, origin),\n };\n }),\n\n toggleInfo: () => set((state) => ({ showInfo: !state.showInfo })),\n\n setToastMessage: (message) => set({ toastMessage: message }),\n\n goBack: () => {\n const previousStep = get().history.at(-1);\n if (previousStep === undefined) return;\n set((state) => ({ step: previousStep, history: state.history.slice(0, -1) }));\n seedFocusForStep(previousStep, get());\n },\n\n toggleAgent: (agent) =>\n set((state) => {\n const installed = state.installedAgentConfigs ?? [];\n\n // A live dual-scope `[P][G]` row is locked to `s`: the selection key is inert on it and\n // emits the same global-locked toast an inherited-global row shows. Mirrors the skill-side\n // dual-scope arm in toggleTechnology — `s` alone collapses and restores the pair.\n const isDualScopePairRow =\n !state.isEditingFromGlobalScope && isDualScopeAgentPair(state.agentConfigs, agent);\n if (isDualScopePairRow) {\n return { toastMessage: TOAST_MESSAGES.GLOBAL_AGENTS_LOCKED };\n }\n\n const isInheritedGlobalReselect =\n !state.isEditingFromGlobalScope &&\n agentHasGlobalActive(state.agentConfigs, agent) &&\n !agentHasProjectActive(state.agentConfigs, agent) &&\n !state.selectedAgents.includes(agent) &&\n agentHasGlobalTombstone(installed, agent);\n if (isInheritedGlobalReselect) {\n return restoreDualScopeAgent(state.selectedAgents, state.agentConfigs, agent);\n }\n\n // Block a globally-installed agent from being changed at project scope. Mirrors the\n // skill-path guard in toggleTechnology: fire on an active global entry in the snapshot,\n // or on a snapshot tombstone paired with a LIVE plain active global entry (the stale\n // state a persisted `[P][G]` reaches after an in-session collapse). A freshly-added\n // global agent (absent from the snapshot) stays freely deselectable.\n const isActiveGlobal =\n agentHasGlobalActive(installed, agent) ||\n (agentHasGlobalTombstone(installed, agent) &&\n agentHasGlobalActive(state.agentConfigs, agent));\n if (isActiveGlobal && !state.isEditingFromGlobalScope) {\n return { toastMessage: TOAST_MESSAGES.GLOBAL_AGENTS_LOCKED };\n }\n\n const isInList = state.selectedAgents.includes(agent);\n const hasExcludedTombstone = state.agentConfigs.some(\n (ac) => ac.name === agent && ac.excluded,\n );\n // An agent is effectively selected only if it's in the list WITHOUT an excluded tombstone.\n // When it has an excluded tombstone, it's visually \"off\" and toggling means \"re-enable\".\n const isSelected = isInList && !hasExcludedTombstone;\n\n return {\n selectedAgents: nextSelectedAgents(state.selectedAgents, agent, { isSelected, isInList }),\n agentConfigs: applyAgentToggle(state.agentConfigs, agent, isSelected),\n };\n }),\n\n toggleAgentScope: (agentName) =>\n set((state) => {\n // Unreachable in production for the same reason as toggleSkillScope's — see it.\n if (state.isEditingFromGlobalScope) return state;\n\n const config = state.agentConfigs.find((ac) => ac.name === agentName && !ac.excluded);\n if (!config) return state;\n\n // Counts a global tombstone as \"installed globally\" (a tombstone means a real global\n // install this project overrides), so an in-session collapse→`s` restores a genuine\n // `[P][G]` pair.\n const wasInstalledGlobally =\n state.installedAgentConfigs?.some((ac) => ac.name === agentName && ac.scope === \"global\") ??\n false;\n const newScope = config.scope === \"project\" ? (\"global\" as const) : (\"project\" as const);\n\n const rescoped = state.agentConfigs.map((ac) =>\n ac.name === agentName && !ac.excluded ? { ...ac, scope: newScope } : ac,\n );\n\n if (newScope === \"project\") {\n // Moving global → project: add the excluded global tombstone if not already there.\n // Gated on wasInstalledGlobally so fresh init toggles don't create spurious tombstones.\n const needsTombstone =\n wasInstalledGlobally && !rescoped.some((ac) => ac.name === agentName && ac.excluded);\n return {\n agentConfigs: needsTombstone\n ? [...rescoped, { name: agentName, scope: \"global\" as const, excluded: true }]\n : rescoped,\n };\n }\n\n // Moving project → global: always drop any excluded global tombstone for this name.\n // Symmetric with toggleSkillScope — see its comment for the invariant.\n return { agentConfigs: rescoped.filter((ac) => !(ac.name === agentName && ac.excluded)) };\n }),\n\n setFocusedAgentId: (id) => set({ focusedAgentId: id }),\n\n seedFocusedAgent: () => {\n if (get().focusedAgentId !== null) return;\n set({ focusedAgentId: firstFocusableAgent() });\n },\n\n preselectAgentsFromDomains: () =>\n set((state) => {\n // A stack declares its own roster, and that declaration is the whole of what\n // choosing it means. Deriving one from the domains would run later in the step\n // order and overwrite it, so the from-scratch path stops here.\n if (state.selectedStackId) return state;\n\n // Deduped: several selected domains each roster the shared `reviewer`.\n const sorted = [\n ...new Set(state.selectedDomains.flatMap((domain) => DOMAIN_AGENTS[domain] ?? [])),\n ].sort();\n const roster = new Set(sorted);\n const merged = sorted.map((name) => buildAgentConfigForName(name, state.agentConfigs));\n const rebuiltSlots = filledAgentSlots(merged);\n const retained = state.agentConfigs.filter((ac) =>\n survivesRosterRebuild(ac, roster, rebuiltSlots),\n );\n return {\n selectedAgents: sorted,\n agentConfigs: [...merged, ...retained],\n };\n }),\n\n preselectAgentsFromStack: (stackAgents) =>\n set((state) => {\n const savedConfigs = state.globalAgentPreselections?.configs ?? [];\n const globalAgents = state.globalAgentPreselections?.agents ?? [];\n const mergedAgents = [...new Set([...stackAgents, ...globalAgents])].sort();\n const merged = mergedAgents.map((name) => buildAgentConfigForName(name, savedConfigs));\n // Preserve dual-scope tombstones, same invariant as preselectAgentsFromDomains.\n const excludedConfigs = agentTombstonesOutsideRebuild(savedConfigs, merged);\n return {\n selectedAgents: mergedAgents,\n agentConfigs: [...merged, ...excludedConfigs],\n };\n }),\n\n reset: () => set(createInitialState()),\n\n getAllSelectedTechnologies: () => {\n return typedValues(get().domainSelections).flatMap(flattenCategorySelections);\n },\n\n getSelectedTechnologiesPerDomain: () => {\n const entries = typedEntries(get().domainSelections)\n .map(([domain, domainSel]) => [domain, flattenCategorySelections(domainSel)] as const)\n .filter(([, techs]) => techs.length > 0);\n return typedFromEntries(entries);\n },\n\n getCurrentDomain: () => {\n const state = get();\n return state.selectedDomains[state.currentDomainIndex] || null;\n },\n\n getTechnologyCount: () => {\n return get().getAllSelectedTechnologies().length;\n },\n\n getStepProgress: () => {\n const state = get();\n const isStackDefaults =\n state.approach === \"stack\" && !!state.selectedStackId && state.stackAction === \"defaults\";\n const skippedSteps: WizardStep[] = isStackDefaults ? [\"build\", \"sources\", \"agents\"] : [];\n const precedingSteps = stepsBefore(getActiveStepFlow(), state.step);\n const completedSteps = precedingSteps.filter((step) => !skippedSteps.includes(step));\n return { completedSteps, skippedSteps };\n },\n\n canGoToNextDomain: () => {\n const state = get();\n return state.currentDomainIndex < state.selectedDomains.length - 1;\n },\n\n canGoToPreviousDomain: () => {\n const state = get();\n return state.currentDomainIndex > 0;\n },\n\n buildSourceRows: () => {\n const state = get();\n const selectedTechnologies = get().getAllSelectedTechnologies();\n const { skillConfigs } = state;\n\n // Include inherited global skills (in skillConfigs but not in domainSelections)\n const selectedSet = new Set(selectedTechnologies);\n const inheritedSkillIds = skillConfigs\n .filter((sc) => !sc.excluded && !selectedSet.has(sc.id))\n .map((sc) => sc.id);\n const allActiveIds = new Set([...inheritedSkillIds, ...selectedTechnologies]);\n const excludedGlobalIds = skillConfigs\n .filter((sc) => isGlobalTombstone(sc) && !allActiveIds.has(sc.id))\n .map((sc) => sc.id);\n // Every skill with a LIVE config entry or selection. Internally disjoint by construction, so no\n // skill contributes live rows twice.\n const liveSkillIds = [...inheritedSkillIds, ...selectedTechnologies, ...excludedGlobalIds];\n // The slot baseline additions are measured against. Each emitted row checks its OWN\n // `(id, scope)` slot, so a skill adopted at a second scope registers as added on the newly\n // occupied row alone — the same classification the confirm step's computeScopeDiff makes.\n const installedSkillSlots = collectInstalledSkillSlots(state.installedSkillConfigs);\n const resolveRowInputs = (id: SkillId) => resolveSkillRowInputs(id, skillConfigs);\n\n const liveRows: SourceRow[] = liveSkillIds.flatMap((id) => {\n const { skillId, configEntry, options } = resolveRowInputs(id);\n return classifySkillSourceRows(skillId, options, {\n configEntry,\n installedSkillConfigs: state.installedSkillConfigs,\n isEditingFromGlobalScope: state.isEditingFromGlobalScope,\n installedSkillSlots,\n });\n });\n\n // Slots the session emptied. A skill may appear in BOTH lists — a collapsed\n // dual-scope pair keeps its surviving global row and gains a project pending-removal row — so\n // rows are no longer disjoint per SKILL. They stay disjoint per `(id, scope)` SLOT: a snapshot\n // slot a live row already renders never gets a removal row on top of it.\n const pendingRemovalRows: SourceRow[] = collectRemovedInstalledEntries(\n state.installedSkillConfigs,\n skillConfigs,\n )\n .filter((entry) => !isSlotAlreadyRendered(liveRows, entry))\n .map((entry) => {\n const { skillId, options } = resolveRowInputs(entry.id);\n return toPendingRemovalRow(skillId, options, entry);\n });\n\n // Stable sort by scope tier: global readOnly, global editable, then project. Pending-removal\n // rows carry no dedicated tier — they sort by their own scope and, being appended last, trail\n // inline within that scope section. Matches source-grid grouping so navigation indices align\n // with render order.\n const rows = [...liveRows, ...pendingRemovalRows];\n rows.sort((a, b) => sourceRowSortTier(a) - sourceRowSortTier(b));\n\n return rows;\n },\n}));\n\n/**\n * Runs a change the user triggered from a painted frame, with anything it warned about shown as\n * a toast.\n *\n * `warn()` writes to stderr, and stderr under a mounted wizard is where a message goes to be\n * lost: the frame is sized to the terminal and starts at the top of an empty buffer, so the next\n * repaint pushes the line off the top of the screen. That is the same loss the startup band\n * exists to prevent before the mount, and the one `assertWizardScreenIsWhollyVisible` in\n * `e2e/pages/base-step.ts` fails the interactive suite on. The band is deliberately the wrong\n * home for it — a message raised mid-session is not a startup message — so it takes the\n * wizard's own transient channel instead.\n *\n * FOR CALL SITES PAST THE MOUNT ONLY, which is why the routing lives at the call site rather\n * than inside the actions themselves. {@link WizardState.populateFromSkillIds} and\n * {@link WizardState.startFromScratch} are each reached from hydration as well, where buffering is\n * already on and the band IS the right home; a window opened around either one there would reset\n * the buffer the load filled and close it again before hydration had finished speaking into it.\n */\nexport function showWarningsAsToast(change: () => void): void {\n enableBuffering();\n try {\n change();\n const warnings = drainBuffer();\n if (warnings.length > 0) {\n useWizardStore.getState().setToastMessage(skillsLeftOutToast(warnings.length));\n }\n } finally {\n disableBuffering();\n }\n}\n\nexport type HydrateOptions = {\n initialStep?: WizardStep;\n initialDomains?: Domain[];\n initialAgents?: AgentName[];\n installedSkillIds?: SkillId[];\n installedSkillConfigs?: SkillConfig[];\n installedAgentConfigs?: AgentScopeConfig[];\n isEditingFromGlobalScope?: boolean;\n};\n\n/**\n * Imperatively hydrates the wizard store before the first render.\n *\n * Must be called BEFORE render(<Wizard ... />) so React captures the correct\n * initial snapshot on the first frame. Running this inside a render-phase hook\n * causes a one-frame flash of the default \"stack\" step before the jump to the\n * intended step is committed to stdout.\n */\nexport function hydrateWizardStore(options: HydrateOptions): void {\n useWizardStore.setState(createInitialState());\n\n const { initialStep } = options;\n const isEditFlow = initialStep !== undefined;\n if (isEditFlow) {\n hydrateForEdit(initialStep, options);\n } else {\n hydrateForInit(options);\n }\n}\n\n/** Edit flow: populate from installed skills, then jump straight to the saved step. */\nfunction hydrateForEdit(initialStep: WizardStep, options: HydrateOptions): void {\n const {\n initialDomains,\n initialAgents,\n installedSkillIds,\n installedSkillConfigs,\n installedAgentConfigs,\n isEditingFromGlobalScope,\n } = options;\n\n if (installedSkillIds?.length) {\n useWizardStore.getState().populateFromSkillIds(installedSkillIds, installedSkillConfigs);\n }\n\n useWizardStore.setState({\n isInitMode: false,\n // Jump directly to initialStep with empty history. The user is starting\n // fresh at this step — no prior steps to navigate back through.\n step: initialStep,\n history: [],\n approach: \"scratch\",\n // Saved domains/agents from config override what populateFromSkillIds derived.\n ...(initialDomains?.length ? { selectedDomains: initialDomains, currentDomainIndex: 0 } : {}),\n ...(initialAgents?.length ? { selectedAgents: initialAgents } : {}),\n ...(initialAgents?.length && installedAgentConfigs?.length\n ? { agentConfigs: installedAgentConfigs }\n : {}),\n // Snapshot installed configs for diff rendering in SkillAgentSummary\n ...(installedSkillConfigs?.length || installedAgentConfigs?.length\n ? {\n installedSkillConfigs: installedSkillConfigs ?? null,\n installedAgentConfigs: installedAgentConfigs ?? null,\n }\n : {}),\n ...(isEditingFromGlobalScope ? { isEditingFromGlobalScope: true } : {}),\n });\n\n useWizardStore.getState().seedFocusedSkillForActiveDomain();\n}\n\n/** Where an init opens when the loaded source offers no stack to choose. */\nconst FIRST_STEP_WITHOUT_STACKS: WizardStep = \"domains\";\n\n/**\n * Init flow: skills are not populated yet — the stack step runs first, so saved\n * selections are stored as preselections for stack-selection.tsx to merge after\n * the stack/scratch choice (selectStack wipes agents).\n *\n * Unless the loaded source offers no stacks at all — a custom marketplace that\n * ships none, since the built-in catalogue stands in for the default public\n * marketplace alone. That step would then hold nothing but its own \"Start from\n * scratch\" row, so the wizard opens where that row leads, having done what\n * pressing it does.\n */\nfunction hydrateForInit(options: HydrateOptions): void {\n const {\n initialDomains,\n initialAgents,\n installedSkillConfigs,\n installedAgentConfigs,\n isEditingFromGlobalScope,\n } = options;\n\n useWizardStore.setState({\n isInitMode: true,\n ...(initialDomains?.length ? { selectedDomains: initialDomains, currentDomainIndex: 0 } : {}),\n ...(initialAgents?.length ? { selectedAgents: initialAgents } : {}),\n ...(initialAgents?.length && installedAgentConfigs?.length\n ? { agentConfigs: installedAgentConfigs }\n : {}),\n // Snapshot installed configs for diff rendering in SkillAgentSummary\n ...(installedSkillConfigs?.length || installedAgentConfigs?.length\n ? {\n installedSkillConfigs: installedSkillConfigs ?? null,\n installedAgentConfigs: installedAgentConfigs ?? null,\n }\n : {}),\n ...(isEditingFromGlobalScope ? { isEditingFromGlobalScope: true } : {}),\n ...(installedSkillConfigs?.length ? { globalPreselections: installedSkillConfigs } : {}),\n ...(initialAgents?.length || installedAgentConfigs?.length\n ? {\n globalAgentPreselections: {\n agents: initialAgents ?? [],\n configs: installedAgentConfigs ?? [],\n },\n }\n : {}),\n });\n\n if (!offersStacks()) {\n useWizardStore.getState().startFromScratch();\n // Nothing behind this step: the stack step it would have been pushed onto\n // never rendered, so the history it would have gone into stays empty.\n useWizardStore.setState({ step: FIRST_STEP_WITHOUT_STACKS, history: [] });\n }\n\n useWizardStore.getState().seedFocusedSkillForActiveDomain();\n}\n","import { sortBy } from \"remeda\";\nimport { typedValues } from \"../../utils/typed-object.js\";\nimport type { Domain, SkillId } from \"../../types/index.js\";\nimport type { SkillConfig } from \"../../types/config.js\";\nimport { getAvailableSkills, getCellState, getUnmetRequiredBy } from \"../matrix/index.js\";\nimport { matrix, getSkillById } from \"../matrix/matrix-provider.js\";\nimport { deriveScopeBadges } from \"./scope-diff.js\";\nimport type { CategoryRow, CategoryOption } from \"../../components/wizard/category-grid.js\";\n\n// Build CategoryRow[] from matrix for a domain\nexport function buildCategoriesForDomain(\n domain: Domain,\n allSelections: SkillId[],\n installedSkillIds?: SkillId[],\n skillConfigs?: SkillConfig[],\n): CategoryRow[] {\n const categories = sortBy(\n typedValues(matrix.categories).filter((cat) => cat.domain === domain),\n (cat) => cat.order,\n );\n\n const categoryRows: CategoryRow[] = categories.map((cat) => {\n const skillOptions = getAvailableSkills(cat.id, allSelections);\n\n // Sort options by displayName so the grid order is deterministic across\n // machines and source types (readdir/insertion order is otherwise unstable).\n // Lowercased ordinal comparison keeps the order locale-independent.\n const sortedOptions = sortBy(skillOptions, (skill) =>\n getSkillById(skill.id).displayName.toLowerCase(),\n );\n\n const options: CategoryOption[] = sortedOptions.map((skill) => {\n const activeConfig = skillConfigs?.find((sc) => sc.id === skill.id && !sc.excluded);\n const excludedConfig = skillConfigs?.find((sc) => sc.id === skill.id && sc.excluded);\n const { secondaryScope } = deriveScopeBadges(activeConfig, excludedConfig);\n const local = getSkillById(skill.id).local;\n const requiredBy = skill.selected ? undefined : getUnmetRequiredBy(skill.id, allSelections);\n return {\n id: skill.id,\n // The cell verdict, not the raw advisory: inside a pick-one category\n // the shared semantics forgive what the swap resolves.\n state: getCellState(skill.id, allSelections),\n selected: skill.selected,\n ...(local !== undefined && { local }),\n installed: installedSkillIds?.includes(skill.id) || false,\n ...(activeConfig?.scope !== undefined && { scope: activeConfig.scope }),\n ...(secondaryScope !== undefined && { secondaryScope }),\n ...(activeConfig?.origin !== undefined && { source: activeConfig.origin }),\n hasUnmetRequirements: skill.hasUnmetRequirements,\n ...(skill.unmetRequirementsReason !== undefined && {\n unmetRequirementsReason: skill.unmetRequirementsReason,\n }),\n ...(requiredBy !== undefined && { requiredBy }),\n };\n });\n\n return {\n id: cat.id,\n displayName: cat.displayName,\n exclusive: cat.exclusive,\n options,\n };\n });\n\n return categoryRows.filter((row) => row.options.length > 0);\n}\n","import type { AgentScopeConfig, SkillConfig, SkillScope } from \"../../types/config\";\nimport type { AgentName, SkillId } from \"../../types/index\";\n\nexport type ScopeDiffInput = {\n currentSkills: SkillConfig[];\n currentAgents: AgentScopeConfig[];\n installedSkillConfigs: SkillConfig[] | null;\n installedAgentConfigs: AgentScopeConfig[] | null;\n isInitMode: boolean;\n};\n\nexport type DiffRowStatus = \"added\" | \"mode-changed\" | \"removed\" | \"unchanged\";\n\nexport type SkillDiffRow = {\n id: SkillId;\n source: string;\n status: DiffRowStatus;\n};\n\nexport type AgentDiffRow = {\n name: AgentName;\n status: Exclude<DiffRowStatus, \"mode-changed\">;\n};\n\nexport type ScopeDiff = {\n projectSkillRows: SkillDiffRow[];\n globalSkillRows: SkillDiffRow[];\n projectAgentRows: AgentDiffRow[];\n globalAgentRows: AgentDiffRow[];\n hasContent: boolean;\n};\n\n/**\n * Computes the per-scope diff rows the confirm-step summary renders.\n *\n * The diff baseline keeps tombstones as first-class entries. A tombstone\n * occupies the (id, scope) slot: it means \"the global install still exists but\n * is silenced at project scope\" — the dual-scope indicator. Treating the slot\n * as occupied — for both the previous-key set (isNew detection) and removal\n * (slot-occupancy match) — prevents a dual-scope G→P toggle from rendering a\n * spurious `-` at Global or a spurious `+` at Global on the next edit\n * when the stored tombstone is re-read; mode-change (`~`) tracking filters to active baseline\n * entries because tombstones don't represent a live install.\n *\n * Occupying a slot is not the same as filling it, which is why removal reads the\n * ACTIVE baseline alone and every re-surfaced global row is deduped against the\n * inherited set. A baseline tombstone masks an install rather than being one, and\n * an inherited global can be admitted as inherited and matched as removed at once.\n */\nexport function computeScopeDiff(input: ScopeDiffInput): ScopeDiff {\n const { currentSkills, currentAgents, installedSkillConfigs, installedAgentConfigs, isInitMode } =\n input;\n\n const projectSkills = currentSkills.filter((s) => s.scope === \"project\" && !s.excluded);\n const globalSkills = currentSkills.filter((s) => s.scope === \"global\" && !s.excluded);\n const projectAgents = currentAgents.filter((a) => a.scope === \"project\" && !a.excluded);\n const globalAgents = currentAgents.filter((a) => a.scope === \"global\" && !a.excluded);\n const excludedGlobalSkills = currentSkills.filter((s) => s.scope === \"global\" && !!s.excluded);\n const excludedGlobalAgents = currentAgents.filter((a) => a.scope === \"global\" && !!a.excluded);\n\n const prevSkillKeySet = installedSkillConfigs\n ? new Set(installedSkillConfigs.map((s) => skillSlotKey(s.id, s.scope)))\n : null;\n const prevSourceMap = installedSkillConfigs\n ? new Map(\n installedSkillConfigs\n .filter((s) => !s.excluded)\n .map((s) => [skillSlotKey(s.id, s.scope), s.origin]),\n )\n : null;\n const prevAgentKeySet = installedAgentConfigs\n ? new Set(installedAgentConfigs.map((a) => agentSlotKey(a.name, a.scope)))\n : null;\n\n // The installs the baseline actually records. Both readers below want this\n // rather than the raw snapshot: `inheritedGlobal*` re-surfaces an active global\n // the project overrides without a tombstone — a historical no-tombstone\n // dual-scope shape, current tombstones being handled by\n // `uniqueExcludedGlobalSkills` — and removal reports only what an install left.\n const activeSkillBaseline = installedSkillConfigs\n ? installedSkillConfigs.filter((s) => !s.excluded)\n : [];\n const activeAgentBaseline = installedAgentConfigs\n ? installedAgentConfigs.filter((a) => !a.excluded)\n : [];\n const inheritedGlobalSkills = activeSkillBaseline.filter(\n (s) =>\n s.scope === \"global\" &&\n !globalSkills.some((g) => g.id === s.id) &&\n !excludedGlobalSkills.some((e) => e.id === s.id) &&\n projectSkills.some((p) => p.id === s.id),\n );\n const inheritedGlobalAgents = activeAgentBaseline.filter(\n (a) =>\n a.scope === \"global\" &&\n !globalAgents.some((g) => g.name === a.name) &&\n !excludedGlobalAgents.some((e) => e.name === a.name) &&\n projectAgents.some((p) => p.name === a.name),\n );\n\n // Slot-occupancy match over the ACTIVE baseline: an installed entry at\n // (id, scope) is considered removed only if nothing — active OR tombstone —\n // occupies that slot in current. A current tombstone at the same key keeps the\n // slot occupied (dual-scope indicator, not a removal).\n //\n // A baseline TOMBSTONE is never a removal candidate. It masks a global install\n // rather than being one, so its slot held nothing to delete and dropping it\n // takes nothing away — a `-` there announces a deletion that never happens.\n const removedSkills = activeSkillBaseline.filter(\n (s) => !currentSkills.some((c) => c.id === s.id && c.scope === s.scope),\n );\n const removedAgents = activeAgentBaseline.filter(\n (a) => !currentAgents.some((c) => c.name === a.name && c.scope === a.scope),\n );\n\n // The Global section renders at most one row per skill, so both of the ways a\n // baseline global entry can re-surface are deduped against the inherited set:\n // `uniqueExcludedGlobalSkills` for the current tombstone, and the removed-global\n // rows below for the removal match. The second is not covered by the first —\n // an inherited global that the project claims WITHOUT a tombstone occupies no\n // slot in current, so it is admitted as inherited and matched as removed at\n // once, and the same skill lands under Global twice.\n const inheritedSkillIdSet = new Set(inheritedGlobalSkills.map((s) => s.id));\n const uniqueExcludedGlobalSkills = excludedGlobalSkills.filter(\n (s) => !inheritedSkillIdSet.has(s.id),\n );\n const allGlobalSkills = [\n ...globalSkills,\n ...inheritedGlobalSkills,\n ...uniqueExcludedGlobalSkills,\n ];\n const inheritedAgentNameSet = new Set(inheritedGlobalAgents.map((a) => a.name));\n const uniqueExcludedGlobalAgents = excludedGlobalAgents.filter(\n (a) => !inheritedAgentNameSet.has(a.name),\n );\n const allGlobalAgents = [\n ...globalAgents,\n ...inheritedGlobalAgents,\n ...uniqueExcludedGlobalAgents,\n ];\n\n const removedGlobalSkills = isInitMode\n ? []\n : removedSkills.filter((s) => s.scope === \"global\" && !inheritedSkillIdSet.has(s.id));\n const removedProjectSkills = removedSkills.filter((s) => s.scope === \"project\");\n const removedGlobalAgents = isInitMode\n ? []\n : removedAgents.filter((a) => a.scope === \"global\" && !inheritedAgentNameSet.has(a.name));\n const removedProjectAgents = removedAgents.filter((a) => a.scope === \"project\");\n\n const projectSkillRows = [\n ...projectSkills.map((s) => classifyDiffRow(s, prevSkillKeySet, prevSourceMap)),\n ...removedProjectSkills.map(toRemovedSkillRow),\n ];\n const globalSkillRows = [\n ...allGlobalSkills.map((s) => classifyDiffRow(s, prevSkillKeySet, prevSourceMap)),\n ...removedGlobalSkills.map(toRemovedSkillRow),\n ];\n const projectAgentRows = [\n ...projectAgents.map((a) => classifyAgentDiffRow(a, prevAgentKeySet)),\n ...removedProjectAgents.map(toRemovedAgentRow),\n ];\n const globalAgentRows = [\n ...allGlobalAgents.map((a) => classifyAgentDiffRow(a, prevAgentKeySet)),\n ...removedGlobalAgents.map(toRemovedAgentRow),\n ];\n\n const hasContent =\n projectSkillRows.length > 0 ||\n globalSkillRows.length > 0 ||\n projectAgentRows.length > 0 ||\n globalAgentRows.length > 0;\n\n return { projectSkillRows, globalSkillRows, projectAgentRows, globalAgentRows, hasContent };\n}\n\n/**\n * The `(id, scope)` SLOT key this module diffs on. Exported so every surface that computes its own\n * session diff — notably the wizard store's Sources tab — keys on the same slot rather than on the\n * id alone, which is what let one skill read as added on one surface and unchanged on the other.\n */\nexport function skillSlotKey(id: SkillId, scope: SkillScope | undefined): string {\n return `${id}:${scope}`;\n}\n\n/**\n * The `(name, scope)` SLOT key for an agent — the agent-side counterpart of {@link skillSlotKey},\n * exported for the same reason. Today only this module diffs agent slots, so there is nothing to\n * disagree with; the helper exists so that a second surface routes through it from the start rather\n * than re-deriving the key on `name` alone, which is precisely how the skill side ended up with\n * the Sources tab and the confirm step disagreeing about whether the same row was added.\n */\nexport function agentSlotKey(name: AgentName, scope: SkillScope | undefined): string {\n return `${name}:${scope}`;\n}\n\nexport type ScopeBadges = {\n scope: SkillScope | undefined;\n secondaryScope: SkillScope | undefined;\n};\n\n/** Bracketed scope badge: `[G]` for global, `[P]` for project. */\nexport function formatScopeTag(scope: SkillScope): \"[G]\" | \"[P]\" {\n return scope === \"global\" ? \"[G]\" : \"[P]\";\n}\n\n/**\n * Derives the primary + secondary scope badges for a row from its active\n * entry and its excluded tombstone. A tombstone at the OTHER scope renders as a\n * secondary badge (`[P][G]`); a same-scope tombstone renders nothing extra.\n */\nexport function deriveScopeBadges(\n activeConfig: { scope: SkillScope } | undefined,\n excludedConfig: { scope: SkillScope } | undefined,\n): ScopeBadges {\n const secondaryScope =\n excludedConfig && activeConfig && excludedConfig.scope !== activeConfig.scope\n ? excludedConfig.scope\n : undefined;\n return { scope: activeConfig?.scope, secondaryScope };\n}\n\n/**\n * Classifies an active skill entry against the baseline: added, mode-changed, or unchanged.\n *\n * The comparison is on `origin`, because that field IS where a skill's install mode is\n * recorded: `eject` means the project's own copy and anything else names the marketplace the\n * plugin comes from. With no second marketplace to move between, an `origin` that changed is a\n * mode that changed, which is what the `~` marker has always meant to a reader.\n */\nfunction classifyDiffRow(\n skill: SkillConfig,\n prevKeySet: Set<string> | null,\n prevSourceMap: Map<string, string> | null,\n): SkillDiffRow {\n const key = skillSlotKey(skill.id, skill.scope);\n const isNew = prevKeySet === null || !prevKeySet.has(key);\n const prevSource = prevSourceMap?.get(key);\n const modeChanged = !isNew && prevSource != null && prevSource !== skill.origin;\n if (modeChanged) {\n return { id: skill.id, source: skill.origin, status: \"mode-changed\" };\n }\n return { id: skill.id, source: skill.origin, status: isNew ? \"added\" : \"unchanged\" };\n}\n\nfunction classifyAgentDiffRow(\n agent: AgentScopeConfig,\n prevKeySet: Set<string> | null,\n): AgentDiffRow {\n const isNew = prevKeySet === null || !prevKeySet.has(agentSlotKey(agent.name, agent.scope));\n return { name: agent.name, status: isNew ? \"added\" : \"unchanged\" };\n}\n\nfunction toRemovedSkillRow(skill: SkillConfig): SkillDiffRow {\n return { id: skill.id, source: skill.origin, status: \"removed\" };\n}\n\nfunction toRemovedAgentRow(agent: AgentScopeConfig): AgentDiffRow {\n return { name: agent.name, status: \"removed\" };\n}\n","import type { CheckboxItem } from \"../../components/wizard/checkbox-grid.js\";\nimport type { AgentName } from \"../../types/index.js\";\n\nexport type AgentItem = CheckboxItem<AgentName>;\n\nexport type AgentGroup = {\n label: string;\n items: AgentItem[];\n};\n\n/**\n * The agents the wizard offers, in the order its grid lists them.\n *\n * Lives here rather than in `step-agents.tsx` because the grid is not the only\n * surface that has to know which row it opens on: the store seeds `focusedAgentId`\n * from the same roster before the first frame, so that a keystroke buffered ahead\n * of that frame resolves the same agent the user is looking at.\n */\nexport const BUILT_IN_AGENT_GROUPS: AgentGroup[] = [\n {\n label: \"Web\",\n items: [\n {\n id: \"web-developer\",\n label: \"Web Developer\",\n description: \"Frontend features, components, TypeScript\",\n },\n { id: \"web-researcher\", label: \"Web Researcher\", description: \"Frontend pattern discovery\" },\n {\n id: \"web-tester\",\n label: \"Web Tester\",\n description: \"Frontend tests, E2E, component tests\",\n },\n ],\n },\n {\n label: \"API\",\n items: [\n {\n id: \"api-developer\",\n label: \"API Developer\",\n description: \"Backend routes, database, middleware\",\n },\n { id: \"api-researcher\", label: \"API Researcher\", description: \"Backend pattern discovery\" },\n {\n id: \"api-tester\",\n label: \"API Tester\",\n description: \"Endpoint, database, and auth flow tests\",\n },\n ],\n },\n {\n label: \"AI\",\n items: [\n {\n id: \"ai-developer\",\n label: \"AI Developer\",\n description: \"RAG pipelines, agent loops, tool calling\",\n },\n {\n id: \"ai-researcher\",\n label: \"AI Researcher\",\n description: \"Prompt, model, and RAG pipeline discovery\",\n },\n {\n id: \"ai-tester\",\n label: \"AI Tester\",\n description: \"LLM mocking, prompt regression, eval harnesses\",\n },\n ],\n },\n {\n label: \"CLI\",\n items: [\n {\n id: \"cli-developer\",\n label: \"CLI Developer\",\n description: \"CLI commands, interactive prompts\",\n },\n { id: \"cli-tester\", label: \"CLI Tester\", description: \"CLI application tests\" },\n {\n id: \"cli-researcher\",\n label: \"CLI Researcher\",\n description: \"CLI command and config pattern discovery\",\n },\n ],\n },\n {\n label: \"Meta\",\n items: [\n {\n id: \"pm\",\n label: \"PM\",\n description: \"Cross-domain implementation specs; domain frameworks via skills\",\n },\n {\n id: \"reviewer\",\n label: \"Reviewer\",\n description: \"Cross-domain code review; domain knowledge via skills\",\n },\n { id: \"agent-summoner\", label: \"Agent Summoner\", description: \"Create and improve agents\" },\n {\n id: \"skill-summoner\",\n label: \"Skill Summoner\",\n description: \"Create technology-specific skills\",\n },\n { id: \"codex-keeper\", label: \"Codex Keeper\", description: \"AI-focused documentation\" },\n ],\n },\n];\n\n/** IDs of all built-in agents for fast lookup. */\nexport const BUILT_IN_AGENT_IDS = new Set<string>(\n BUILT_IN_AGENT_GROUPS.flatMap((group) => group.items.map((agent) => agent.id)),\n);\n\n/**\n * The agent the grid focuses when nothing is focused yet.\n *\n * Always a built-in: a marketplace's own agents are appended after these groups,\n * so the head of the list does not move with the loaded source.\n */\nexport function firstFocusableAgent(): AgentName {\n const first = BUILT_IN_AGENT_GROUPS[0]?.items[0];\n if (first === undefined) throw new Error(\"The built-in agent roster is empty\");\n return first.id;\n}\n"],"mappings":"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","names":[]}