agents-inc 0.152.1 → 0.154.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.
- package/CHANGELOG.md +57 -0
- package/README.md +31 -35
- package/dist/{chunk-FVDKAVOL.js → chunk-2IMYK4WN.js} +18 -51
- package/dist/chunk-2IMYK4WN.js.map +1 -0
- package/dist/{chunk-PMM2MYMA.js → chunk-4VCWL2IG.js} +649 -357
- package/dist/chunk-4VCWL2IG.js.map +1 -0
- package/dist/{chunk-PZIZNMHK.js → chunk-5MFJ24VM.js} +237 -150
- package/dist/chunk-5MFJ24VM.js.map +1 -0
- package/dist/{chunk-KXYVJGJP.js → chunk-6CNRMCFM.js} +3 -2
- package/dist/{chunk-KXYVJGJP.js.map → chunk-6CNRMCFM.js.map} +1 -1
- package/dist/chunk-7VZV4O6B.js +40 -0
- package/dist/chunk-7VZV4O6B.js.map +1 -0
- package/dist/{chunk-SX5H6TSC.js → chunk-AKQ5QISO.js} +11 -8
- package/dist/chunk-AKQ5QISO.js.map +1 -0
- package/dist/{chunk-BNSRA6HL.js → chunk-AURY6RT6.js} +39 -176
- package/dist/chunk-AURY6RT6.js.map +1 -0
- package/dist/{chunk-LZ52XEPR.js → chunk-B66SC72V.js} +7 -6
- package/dist/chunk-B66SC72V.js.map +1 -0
- package/dist/{chunk-LASI35KT.js → chunk-BZ4CZBOM.js} +14 -28
- package/dist/chunk-BZ4CZBOM.js.map +1 -0
- package/dist/chunk-CBF4ZYV3.js +18540 -0
- package/dist/chunk-CBF4ZYV3.js.map +1 -0
- package/dist/{chunk-5GUOIJSG.js → chunk-CHNA5RVS.js} +3 -15
- package/dist/chunk-CHNA5RVS.js.map +1 -0
- package/dist/{chunk-LDP5ASDM.js → chunk-DRKSYJZ2.js} +2 -19
- package/dist/chunk-DRKSYJZ2.js.map +1 -0
- package/dist/chunk-FMYHWKGG.js +325 -0
- package/dist/chunk-FMYHWKGG.js.map +1 -0
- package/dist/{chunk-SKQWRUPX.js → chunk-GUDGCFSF.js} +59 -33
- package/dist/chunk-GUDGCFSF.js.map +1 -0
- package/dist/{chunk-WKTHWQKM.js → chunk-IPJOMAWC.js} +5070 -6305
- package/dist/chunk-IPJOMAWC.js.map +1 -0
- package/dist/chunk-IXEDSKMH.js +48 -0
- package/dist/chunk-IXEDSKMH.js.map +1 -0
- package/dist/{chunk-TUPYW2IQ.js → chunk-JC7DBPRD.js} +9 -12
- package/dist/chunk-JC7DBPRD.js.map +1 -0
- package/dist/{chunk-ZL7PFNHN.js → chunk-K3O3YQYG.js} +2 -2
- package/dist/{chunk-QRDTLVXG.js → chunk-LA3JPESW.js} +9 -22
- package/dist/chunk-LA3JPESW.js.map +1 -0
- package/dist/{chunk-MWG4VU64.js → chunk-MJFIO5SX.js} +50 -74
- package/dist/chunk-MJFIO5SX.js.map +1 -0
- package/dist/{chunk-L7SZXUBJ.js → chunk-NFH6SA62.js} +7 -6
- package/dist/{chunk-L7SZXUBJ.js.map → chunk-NFH6SA62.js.map} +1 -1
- package/dist/{chunk-GRVKW3CC.js → chunk-NKCY2ULI.js} +3 -2
- package/dist/{chunk-GRVKW3CC.js.map → chunk-NKCY2ULI.js.map} +1 -1
- package/dist/{chunk-TJJPWUMA.js → chunk-NSJ2S7R5.js} +3 -2
- package/dist/{chunk-TJJPWUMA.js.map → chunk-NSJ2S7R5.js.map} +1 -1
- package/dist/{chunk-Q2KG7UV3.js → chunk-OJJLYHM3.js} +2 -1
- package/dist/{chunk-Q2KG7UV3.js.map → chunk-OJJLYHM3.js.map} +1 -1
- package/dist/{chunk-MJ2KHG24.js → chunk-ONWEOS77.js} +6 -6
- package/dist/{chunk-MJ2KHG24.js.map → chunk-ONWEOS77.js.map} +1 -1
- package/dist/{chunk-NR3OZGL4.js → chunk-OZXAJNLA.js} +2 -1
- package/dist/{chunk-NR3OZGL4.js.map → chunk-OZXAJNLA.js.map} +1 -1
- package/dist/{chunk-QZZJFYUQ.js → chunk-PRJD5MMQ.js} +3 -3
- package/dist/chunk-PRJD5MMQ.js.map +1 -0
- package/dist/{chunk-MM7CTTAV.js → chunk-Q5FLW4JG.js} +2 -2
- package/dist/{chunk-MM7CTTAV.js.map → chunk-Q5FLW4JG.js.map} +1 -1
- package/dist/{chunk-5UWKOOIS.js → chunk-QQTYMW7N.js} +131 -209
- package/dist/chunk-QQTYMW7N.js.map +1 -0
- package/dist/{chunk-MVR3SYMN.js → chunk-QUDQTO3O.js} +4 -3
- package/dist/{chunk-MVR3SYMN.js.map → chunk-QUDQTO3O.js.map} +1 -1
- package/dist/{chunk-76ADG7LQ.js → chunk-R54KIGN2.js} +8 -22
- package/dist/chunk-R54KIGN2.js.map +1 -0
- package/dist/{chunk-XHUODHZ4.js → chunk-R7JV22QK.js} +22 -49
- package/dist/chunk-R7JV22QK.js.map +1 -0
- package/dist/{chunk-E5X6RJ4E.js → chunk-TUQF577Z.js} +56 -53
- package/dist/chunk-TUQF577Z.js.map +1 -0
- package/dist/{chunk-IHUY4M22.js → chunk-UW44KSYL.js} +4 -4
- package/dist/{chunk-DTSG5XZB.js → chunk-V3ENMW7G.js} +3 -3
- package/dist/chunk-VZRO7RYT.js +3694 -0
- package/dist/chunk-VZRO7RYT.js.map +1 -0
- package/dist/{chunk-MQ7FLIYS.js → chunk-WRRP47PY.js} +3 -2
- package/dist/{chunk-MQ7FLIYS.js.map → chunk-WRRP47PY.js.map} +1 -1
- package/dist/{chunk-RNJWAKMO.js → chunk-XGMOXMS4.js} +9 -8
- package/dist/chunk-XGMOXMS4.js.map +1 -0
- package/dist/{chunk-STMHDOZD.js → chunk-XMEIVWAS.js} +12 -9
- package/dist/chunk-XMEIVWAS.js.map +1 -0
- package/dist/{chunk-IUQBOCSU.js → chunk-ZBPEFQ4G.js} +2 -1
- package/dist/{chunk-IUQBOCSU.js.map → chunk-ZBPEFQ4G.js.map} +1 -1
- package/dist/chunk-ZU6DAR4S.js +223 -0
- package/dist/chunk-ZU6DAR4S.js.map +1 -0
- package/dist/commands/build/marketplace.js +115 -35
- package/dist/commands/build/marketplace.js.map +1 -1
- package/dist/commands/build/plugins.js +9 -10
- package/dist/commands/build/plugins.js.map +1 -1
- package/dist/commands/compile.js +135 -70
- package/dist/commands/compile.js.map +1 -1
- package/dist/commands/doctor.js +793 -64
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/edit.js +231 -236
- package/dist/commands/edit.js.map +1 -1
- package/dist/commands/eject.js +24 -39
- package/dist/commands/eject.js.map +1 -1
- package/dist/commands/init.js +41 -46
- package/dist/commands/list.js +10 -12
- package/dist/commands/list.js.map +1 -1
- package/dist/commands/search.js +35 -88
- package/dist/commands/search.js.map +1 -1
- package/dist/commands/uninstall.js +212 -167
- package/dist/commands/uninstall.js.map +1 -1
- package/dist/commands/update.js +82 -332
- package/dist/commands/update.js.map +1 -1
- package/dist/components/common/confirm.js +1 -1
- package/dist/components/common/prompt-confirm.js +1 -1
- package/dist/components/common/select-list.js +2 -2
- package/dist/components/common/spinner.js +1 -1
- package/dist/components/wizard/category-grid.js +5 -6
- package/dist/components/wizard/checkbox-grid.js +5 -6
- package/dist/components/wizard/domain-selection.js +12 -13
- package/dist/components/wizard/run-wizard-session.js +30 -36
- package/dist/components/wizard/scroll-affordance.js +2 -2
- package/dist/components/wizard/skill-agent-summary.js +7 -7
- package/dist/components/wizard/source-grid.js +6 -11
- package/dist/components/wizard/stack-selection.js +9 -9
- package/dist/components/wizard/step-agents.js +12 -12
- package/dist/components/wizard/step-build.js +10 -11
- package/dist/components/wizard/step-confirm.js +11 -11
- package/dist/components/wizard/step-sources.js +11 -17
- package/dist/components/wizard/step-stack.js +10 -10
- package/dist/components/wizard/summary-panel.js +10 -10
- package/dist/components/wizard/toast.js +2 -2
- package/dist/components/wizard/wizard-layout.js +15 -16
- package/dist/components/wizard/wizard-tabs.js +6 -12
- package/dist/components/wizard/wizard.js +29 -35
- package/dist/config-exports.js +1 -1
- package/dist/copy-local-skills-WVHJFRPK.js +14 -0
- package/dist/hooks/init.js +49 -48
- package/dist/hooks/init.js.map +1 -1
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/load-agent-defs-5OT54J5M.js +15 -0
- package/dist/{loader-5JP4S7CJ.js → loader-JIZDTR4G.js} +7 -5
- package/dist/recompile-project-agents-VREEPBDV.js +20 -0
- package/dist/{source-loader-MZYCPL2S.js → source-loader-OE6EJFPU.js} +6 -6
- package/dist/src/agents/developer/ai-developer/identity.md +4 -4
- package/dist/src/agents/developer/ai-developer/playbook.md +1 -1
- package/dist/src/agents/developer/api-developer/identity.md +4 -4
- package/dist/src/agents/developer/api-developer/metadata.yaml +1 -1
- package/dist/src/agents/developer/cli-developer/identity.md +4 -4
- package/dist/src/agents/developer/web-developer/identity.md +2 -2
- package/dist/src/agents/developer/web-developer/metadata.yaml +1 -1
- package/dist/src/agents/meta/agent-summoner/identity.md +4 -5
- package/dist/src/agents/meta/agent-summoner/output.md +2 -2
- package/dist/src/agents/meta/agent-summoner/playbook.md +15 -16
- package/dist/src/agents/meta/codex-keeper/identity.md +4 -4
- package/dist/src/agents/meta/codex-keeper/playbook.md +1 -1
- package/dist/src/agents/meta/convention-keeper/identity.md +1 -1
- package/dist/src/agents/meta/skill-summoner/critical-reminders.md +0 -34
- package/dist/src/agents/meta/skill-summoner/critical-requirements.md +27 -3
- package/dist/src/agents/meta/skill-summoner/identity.md +2 -2
- package/{src/agents/planning/web-pm → dist/src/agents/planning/pm}/critical-reminders.md +10 -7
- package/dist/src/agents/planning/{web-pm → pm}/critical-requirements.md +8 -4
- package/dist/src/agents/planning/pm/identity.md +47 -0
- package/dist/src/agents/planning/pm/metadata.yaml +12 -0
- package/dist/src/agents/planning/{web-pm → pm}/output.md +7 -90
- package/dist/src/agents/planning/pm/playbook.md +185 -0
- package/dist/src/agents/researcher/ai-researcher/critical-reminders.md +58 -0
- package/dist/src/agents/researcher/ai-researcher/critical-requirements.md +40 -0
- package/dist/src/agents/researcher/ai-researcher/identity.md +86 -0
- package/dist/src/agents/researcher/ai-researcher/metadata.yaml +10 -0
- package/dist/src/agents/researcher/ai-researcher/output.md +363 -0
- package/dist/src/agents/researcher/ai-researcher/playbook.md +545 -0
- package/dist/src/agents/researcher/api-researcher/critical-reminders.md +16 -0
- package/dist/src/agents/researcher/api-researcher/identity.md +7 -7
- package/dist/src/agents/researcher/cli-researcher/critical-reminders.md +50 -0
- package/dist/src/agents/researcher/cli-researcher/critical-requirements.md +36 -0
- package/dist/src/agents/researcher/cli-researcher/identity.md +87 -0
- package/dist/src/agents/researcher/cli-researcher/metadata.yaml +10 -0
- package/dist/src/agents/researcher/cli-researcher/output.md +343 -0
- package/dist/src/agents/researcher/cli-researcher/playbook.md +370 -0
- package/dist/src/agents/researcher/web-researcher/identity.md +5 -6
- package/dist/src/agents/reviewer/reviewer/critical-reminders.md +29 -0
- package/dist/src/agents/reviewer/reviewer/critical-requirements.md +31 -0
- package/dist/src/agents/reviewer/reviewer/identity.md +41 -0
- package/dist/src/agents/reviewer/reviewer/metadata.yaml +12 -0
- package/dist/src/agents/reviewer/reviewer/output.md +202 -0
- package/dist/src/agents/reviewer/reviewer/playbook.md +141 -0
- package/dist/src/agents/tester/ai-tester/critical-reminders.md +48 -0
- package/dist/src/agents/tester/ai-tester/critical-requirements.md +49 -0
- package/dist/src/agents/tester/ai-tester/identity.md +62 -0
- package/dist/src/agents/tester/ai-tester/metadata.yaml +12 -0
- package/dist/src/agents/tester/ai-tester/output.md +375 -0
- package/dist/src/agents/tester/ai-tester/playbook.md +789 -0
- package/dist/src/agents/tester/api-tester/identity.md +3 -3
- package/dist/src/agents/tester/cli-tester/critical-reminders.md +3 -3
- package/dist/src/agents/tester/cli-tester/critical-requirements.md +2 -2
- package/dist/src/agents/tester/cli-tester/identity.md +3 -3
- package/dist/src/agents/tester/cli-tester/output.md +4 -4
- package/dist/src/agents/tester/cli-tester/playbook.md +3 -3
- package/dist/src/agents/tester/web-tester/identity.md +3 -3
- package/dist/stores/wizard-store.js +8 -6
- package/package.json +13 -2
- package/src/agents/developer/ai-developer/identity.md +4 -4
- package/src/agents/developer/ai-developer/playbook.md +1 -1
- package/src/agents/developer/api-developer/identity.md +4 -4
- package/src/agents/developer/api-developer/metadata.yaml +1 -1
- package/src/agents/developer/cli-developer/identity.md +4 -4
- package/src/agents/developer/web-developer/identity.md +2 -2
- package/src/agents/developer/web-developer/metadata.yaml +1 -1
- package/src/agents/meta/agent-summoner/identity.md +4 -5
- package/src/agents/meta/agent-summoner/output.md +2 -2
- package/src/agents/meta/agent-summoner/playbook.md +15 -16
- package/src/agents/meta/codex-keeper/identity.md +4 -4
- package/src/agents/meta/codex-keeper/playbook.md +1 -1
- package/src/agents/meta/convention-keeper/identity.md +1 -1
- package/src/agents/meta/skill-summoner/critical-reminders.md +0 -34
- package/src/agents/meta/skill-summoner/critical-requirements.md +27 -3
- package/src/agents/meta/skill-summoner/identity.md +2 -2
- package/{dist/src/agents/planning/web-pm → src/agents/planning/pm}/critical-reminders.md +10 -7
- package/src/agents/planning/{web-pm → pm}/critical-requirements.md +8 -4
- package/src/agents/planning/pm/identity.md +47 -0
- package/src/agents/planning/pm/metadata.yaml +12 -0
- package/src/agents/planning/{web-pm → pm}/output.md +7 -90
- package/src/agents/planning/pm/playbook.md +185 -0
- package/src/agents/researcher/ai-researcher/critical-reminders.md +58 -0
- package/src/agents/researcher/ai-researcher/critical-requirements.md +40 -0
- package/src/agents/researcher/ai-researcher/identity.md +86 -0
- package/src/agents/researcher/ai-researcher/metadata.yaml +10 -0
- package/src/agents/researcher/ai-researcher/output.md +363 -0
- package/src/agents/researcher/ai-researcher/playbook.md +545 -0
- package/src/agents/researcher/api-researcher/critical-reminders.md +16 -0
- package/src/agents/researcher/api-researcher/identity.md +7 -7
- package/src/agents/researcher/cli-researcher/critical-reminders.md +50 -0
- package/src/agents/researcher/cli-researcher/critical-requirements.md +36 -0
- package/src/agents/researcher/cli-researcher/identity.md +87 -0
- package/src/agents/researcher/cli-researcher/metadata.yaml +10 -0
- package/src/agents/researcher/cli-researcher/output.md +343 -0
- package/src/agents/researcher/cli-researcher/playbook.md +370 -0
- package/src/agents/researcher/web-researcher/identity.md +5 -6
- package/src/agents/reviewer/reviewer/critical-reminders.md +29 -0
- package/src/agents/reviewer/reviewer/critical-requirements.md +31 -0
- package/src/agents/reviewer/reviewer/identity.md +41 -0
- package/src/agents/reviewer/reviewer/metadata.yaml +12 -0
- package/src/agents/reviewer/reviewer/output.md +202 -0
- package/src/agents/reviewer/reviewer/playbook.md +141 -0
- package/src/agents/tester/ai-tester/critical-reminders.md +48 -0
- package/src/agents/tester/ai-tester/critical-requirements.md +49 -0
- package/src/agents/tester/ai-tester/identity.md +62 -0
- package/src/agents/tester/ai-tester/metadata.yaml +12 -0
- package/src/agents/tester/ai-tester/output.md +375 -0
- package/src/agents/tester/ai-tester/playbook.md +789 -0
- package/src/agents/tester/api-tester/identity.md +3 -3
- package/src/agents/tester/cli-tester/critical-reminders.md +3 -3
- package/src/agents/tester/cli-tester/critical-requirements.md +2 -2
- package/src/agents/tester/cli-tester/identity.md +3 -3
- package/src/agents/tester/cli-tester/output.md +4 -4
- package/src/agents/tester/cli-tester/playbook.md +3 -3
- package/src/agents/tester/web-tester/identity.md +3 -3
- package/src/schemas/metadata.schema.json +31 -2
- package/src/schemas/plugin.schema.json +3 -0
- package/src/schemas/project-config.schema.json +61 -15
- package/src/schemas/project-source-config.schema.json +0 -47
- package/dist/chunk-5GUOIJSG.js.map +0 -1
- package/dist/chunk-5UWKOOIS.js.map +0 -1
- package/dist/chunk-76ADG7LQ.js.map +0 -1
- package/dist/chunk-BNSRA6HL.js.map +0 -1
- package/dist/chunk-E5X6RJ4E.js.map +0 -1
- package/dist/chunk-EEPELKOM.js +0 -5938
- package/dist/chunk-EEPELKOM.js.map +0 -1
- package/dist/chunk-F7T5AFFN.js +0 -20
- package/dist/chunk-F7T5AFFN.js.map +0 -1
- package/dist/chunk-FVDKAVOL.js.map +0 -1
- package/dist/chunk-KFB5CRXZ.js +0 -377
- package/dist/chunk-KFB5CRXZ.js.map +0 -1
- package/dist/chunk-KR65TPKC.js +0 -664
- package/dist/chunk-KR65TPKC.js.map +0 -1
- package/dist/chunk-LASI35KT.js.map +0 -1
- package/dist/chunk-LDP5ASDM.js.map +0 -1
- package/dist/chunk-LZ52XEPR.js.map +0 -1
- package/dist/chunk-M7HO7NBK.js +0 -88
- package/dist/chunk-M7HO7NBK.js.map +0 -1
- package/dist/chunk-MWG4VU64.js.map +0 -1
- package/dist/chunk-ODNDXQH2.js +0 -77
- package/dist/chunk-ODNDXQH2.js.map +0 -1
- package/dist/chunk-P44SXVH3.js +0 -80
- package/dist/chunk-P44SXVH3.js.map +0 -1
- package/dist/chunk-PMM2MYMA.js.map +0 -1
- package/dist/chunk-PZIZNMHK.js.map +0 -1
- package/dist/chunk-Q45ZU6HD.js +0 -37
- package/dist/chunk-Q45ZU6HD.js.map +0 -1
- package/dist/chunk-QRDTLVXG.js.map +0 -1
- package/dist/chunk-QZZJFYUQ.js.map +0 -1
- package/dist/chunk-R5NOI2LP.js +0 -170
- package/dist/chunk-R5NOI2LP.js.map +0 -1
- package/dist/chunk-RNJWAKMO.js.map +0 -1
- package/dist/chunk-SBHBBZKF.js +0 -284
- package/dist/chunk-SBHBBZKF.js.map +0 -1
- package/dist/chunk-SKQWRUPX.js.map +0 -1
- package/dist/chunk-STMHDOZD.js.map +0 -1
- package/dist/chunk-SX5H6TSC.js.map +0 -1
- package/dist/chunk-TUPYW2IQ.js.map +0 -1
- package/dist/chunk-UBEDZ4FD.js +0 -4198
- package/dist/chunk-UBEDZ4FD.js.map +0 -1
- package/dist/chunk-VY6MNOXL.js +0 -20
- package/dist/chunk-VY6MNOXL.js.map +0 -1
- package/dist/chunk-WBCPLH66.js +0 -42
- package/dist/chunk-WBCPLH66.js.map +0 -1
- package/dist/chunk-WKTHWQKM.js.map +0 -1
- package/dist/chunk-XHUODHZ4.js.map +0 -1
- package/dist/chunk-ZPPHXXAP.js +0 -252
- package/dist/chunk-ZPPHXXAP.js.map +0 -1
- package/dist/commands/import/skill.js +0 -344
- package/dist/commands/import/skill.js.map +0 -1
- package/dist/commands/new/agent.js +0 -300
- package/dist/commands/new/agent.js.map +0 -1
- package/dist/commands/new/marketplace.js +0 -310
- package/dist/commands/new/marketplace.js.map +0 -1
- package/dist/commands/new/skill.js +0 -26
- package/dist/commands/validate.js +0 -575
- package/dist/commands/validate.js.map +0 -1
- package/dist/components/wizard/search-modal.js +0 -13
- package/dist/components/wizard/selection-card.js +0 -9
- package/dist/components/wizard/step-settings.js +0 -18
- package/dist/copy-local-skills-6EMVN7RB.js +0 -14
- package/dist/load-agent-defs-BWOUVEAR.js +0 -15
- package/dist/load-agent-defs-BWOUVEAR.js.map +0 -1
- package/dist/loader-5JP4S7CJ.js.map +0 -1
- package/dist/recompile-project-agents-6DL45TDI.js +0 -19
- package/dist/recompile-project-agents-6DL45TDI.js.map +0 -1
- package/dist/source-loader-MZYCPL2S.js.map +0 -1
- package/dist/src/agents/developer/web-architecture/critical-reminders.md +0 -48
- package/dist/src/agents/developer/web-architecture/critical-requirements.md +0 -65
- package/dist/src/agents/developer/web-architecture/identity.md +0 -64
- package/dist/src/agents/developer/web-architecture/metadata.yaml +0 -12
- package/dist/src/agents/developer/web-architecture/output.md +0 -449
- package/dist/src/agents/developer/web-architecture/playbook.md +0 -481
- package/dist/src/agents/pattern/pattern-scout/critical-reminders.md +0 -71
- package/dist/src/agents/pattern/pattern-scout/critical-requirements.md +0 -31
- package/dist/src/agents/pattern/pattern-scout/identity.md +0 -25
- package/dist/src/agents/pattern/pattern-scout/metadata.yaml +0 -10
- package/dist/src/agents/pattern/pattern-scout/output.md +0 -290
- package/dist/src/agents/pattern/pattern-scout/playbook.md +0 -1806
- package/dist/src/agents/pattern/web-pattern-critique/critical-reminders.md +0 -30
- package/dist/src/agents/pattern/web-pattern-critique/critical-requirements.md +0 -28
- package/dist/src/agents/pattern/web-pattern-critique/identity.md +0 -41
- package/dist/src/agents/pattern/web-pattern-critique/metadata.yaml +0 -12
- package/dist/src/agents/pattern/web-pattern-critique/output.md +0 -314
- package/dist/src/agents/pattern/web-pattern-critique/playbook.md +0 -572
- package/dist/src/agents/planning/api-pm/critical-reminders.md +0 -48
- package/dist/src/agents/planning/api-pm/critical-requirements.md +0 -41
- package/dist/src/agents/planning/api-pm/identity.md +0 -39
- package/dist/src/agents/planning/api-pm/metadata.yaml +0 -12
- package/dist/src/agents/planning/api-pm/output.md +0 -475
- package/dist/src/agents/planning/api-pm/playbook.md +0 -129
- package/dist/src/agents/planning/web-pm/identity.md +0 -26
- package/dist/src/agents/planning/web-pm/metadata.yaml +0 -12
- package/dist/src/agents/planning/web-pm/playbook.md +0 -318
- package/dist/src/agents/reviewer/ai-reviewer/critical-reminders.md +0 -40
- package/dist/src/agents/reviewer/ai-reviewer/critical-requirements.md +0 -37
- package/dist/src/agents/reviewer/ai-reviewer/identity.md +0 -51
- package/dist/src/agents/reviewer/ai-reviewer/metadata.yaml +0 -10
- package/dist/src/agents/reviewer/ai-reviewer/output.md +0 -395
- package/dist/src/agents/reviewer/ai-reviewer/playbook.md +0 -90
- package/dist/src/agents/reviewer/api-reviewer/critical-reminders.md +0 -31
- package/dist/src/agents/reviewer/api-reviewer/critical-requirements.md +0 -27
- package/dist/src/agents/reviewer/api-reviewer/identity.md +0 -51
- package/dist/src/agents/reviewer/api-reviewer/metadata.yaml +0 -12
- package/dist/src/agents/reviewer/api-reviewer/output.md +0 -343
- package/dist/src/agents/reviewer/api-reviewer/playbook.md +0 -288
- package/dist/src/agents/reviewer/cli-reviewer/critical-reminders.md +0 -33
- package/dist/src/agents/reviewer/cli-reviewer/critical-requirements.md +0 -30
- package/dist/src/agents/reviewer/cli-reviewer/identity.md +0 -44
- package/dist/src/agents/reviewer/cli-reviewer/metadata.yaml +0 -12
- package/dist/src/agents/reviewer/cli-reviewer/output.md +0 -414
- package/dist/src/agents/reviewer/cli-reviewer/playbook.md +0 -218
- package/dist/src/agents/reviewer/infra-reviewer/critical-reminders.md +0 -38
- package/dist/src/agents/reviewer/infra-reviewer/critical-requirements.md +0 -38
- package/dist/src/agents/reviewer/infra-reviewer/identity.md +0 -53
- package/dist/src/agents/reviewer/infra-reviewer/metadata.yaml +0 -10
- package/dist/src/agents/reviewer/infra-reviewer/output.md +0 -364
- package/dist/src/agents/reviewer/infra-reviewer/playbook.md +0 -161
- package/dist/src/agents/reviewer/web-reviewer/critical-reminders.md +0 -31
- package/dist/src/agents/reviewer/web-reviewer/critical-requirements.md +0 -26
- package/dist/src/agents/reviewer/web-reviewer/identity.md +0 -40
- package/dist/src/agents/reviewer/web-reviewer/metadata.yaml +0 -12
- package/dist/src/agents/reviewer/web-reviewer/output.md +0 -333
- package/dist/src/agents/reviewer/web-reviewer/playbook.md +0 -156
- package/src/agents/developer/web-architecture/critical-reminders.md +0 -48
- package/src/agents/developer/web-architecture/critical-requirements.md +0 -65
- package/src/agents/developer/web-architecture/identity.md +0 -64
- package/src/agents/developer/web-architecture/metadata.yaml +0 -12
- package/src/agents/developer/web-architecture/output.md +0 -449
- package/src/agents/developer/web-architecture/playbook.md +0 -481
- package/src/agents/pattern/pattern-scout/critical-reminders.md +0 -71
- package/src/agents/pattern/pattern-scout/critical-requirements.md +0 -31
- package/src/agents/pattern/pattern-scout/identity.md +0 -25
- package/src/agents/pattern/pattern-scout/metadata.yaml +0 -10
- package/src/agents/pattern/pattern-scout/output.md +0 -290
- package/src/agents/pattern/pattern-scout/playbook.md +0 -1806
- package/src/agents/pattern/web-pattern-critique/critical-reminders.md +0 -30
- package/src/agents/pattern/web-pattern-critique/critical-requirements.md +0 -28
- package/src/agents/pattern/web-pattern-critique/identity.md +0 -41
- package/src/agents/pattern/web-pattern-critique/metadata.yaml +0 -12
- package/src/agents/pattern/web-pattern-critique/output.md +0 -314
- package/src/agents/pattern/web-pattern-critique/playbook.md +0 -572
- package/src/agents/planning/api-pm/critical-reminders.md +0 -48
- package/src/agents/planning/api-pm/critical-requirements.md +0 -41
- package/src/agents/planning/api-pm/identity.md +0 -39
- package/src/agents/planning/api-pm/metadata.yaml +0 -12
- package/src/agents/planning/api-pm/output.md +0 -475
- package/src/agents/planning/api-pm/playbook.md +0 -129
- package/src/agents/planning/web-pm/identity.md +0 -26
- package/src/agents/planning/web-pm/metadata.yaml +0 -12
- package/src/agents/planning/web-pm/playbook.md +0 -318
- package/src/agents/reviewer/ai-reviewer/critical-reminders.md +0 -40
- package/src/agents/reviewer/ai-reviewer/critical-requirements.md +0 -37
- package/src/agents/reviewer/ai-reviewer/identity.md +0 -51
- package/src/agents/reviewer/ai-reviewer/metadata.yaml +0 -10
- package/src/agents/reviewer/ai-reviewer/output.md +0 -395
- package/src/agents/reviewer/ai-reviewer/playbook.md +0 -90
- package/src/agents/reviewer/api-reviewer/critical-reminders.md +0 -31
- package/src/agents/reviewer/api-reviewer/critical-requirements.md +0 -27
- package/src/agents/reviewer/api-reviewer/identity.md +0 -51
- package/src/agents/reviewer/api-reviewer/metadata.yaml +0 -12
- package/src/agents/reviewer/api-reviewer/output.md +0 -343
- package/src/agents/reviewer/api-reviewer/playbook.md +0 -288
- package/src/agents/reviewer/cli-reviewer/critical-reminders.md +0 -33
- package/src/agents/reviewer/cli-reviewer/critical-requirements.md +0 -30
- package/src/agents/reviewer/cli-reviewer/identity.md +0 -44
- package/src/agents/reviewer/cli-reviewer/metadata.yaml +0 -12
- package/src/agents/reviewer/cli-reviewer/output.md +0 -414
- package/src/agents/reviewer/cli-reviewer/playbook.md +0 -218
- package/src/agents/reviewer/infra-reviewer/critical-reminders.md +0 -38
- package/src/agents/reviewer/infra-reviewer/critical-requirements.md +0 -38
- package/src/agents/reviewer/infra-reviewer/identity.md +0 -53
- package/src/agents/reviewer/infra-reviewer/metadata.yaml +0 -10
- package/src/agents/reviewer/infra-reviewer/output.md +0 -364
- package/src/agents/reviewer/infra-reviewer/playbook.md +0 -161
- package/src/agents/reviewer/web-reviewer/critical-reminders.md +0 -31
- package/src/agents/reviewer/web-reviewer/critical-requirements.md +0 -26
- package/src/agents/reviewer/web-reviewer/identity.md +0 -40
- package/src/agents/reviewer/web-reviewer/metadata.yaml +0 -12
- package/src/agents/reviewer/web-reviewer/output.md +0 -333
- package/src/agents/reviewer/web-reviewer/playbook.md +0 -156
- /package/dist/{chunk-ZL7PFNHN.js.map → chunk-K3O3YQYG.js.map} +0 -0
- /package/dist/{chunk-IHUY4M22.js.map → chunk-UW44KSYL.js.map} +0 -0
- /package/dist/{chunk-DTSG5XZB.js.map → chunk-V3ENMW7G.js.map} +0 -0
- /package/dist/{commands/new/skill.js.map → copy-local-skills-WVHJFRPK.js.map} +0 -0
- /package/dist/{components/wizard/search-modal.js.map → load-agent-defs-5OT54J5M.js.map} +0 -0
- /package/dist/{components/wizard/selection-card.js.map → loader-JIZDTR4G.js.map} +0 -0
- /package/dist/{components/wizard/step-settings.js.map → recompile-project-agents-VREEPBDV.js.map} +0 -0
- /package/dist/{copy-local-skills-6EMVN7RB.js.map → source-loader-OE6EJFPU.js.map} +0 -0
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cli/lib/loading/source-loader.ts","../src/cli/lib/installation/is-home-directory.ts","../src/cli/lib/metadata-keys.ts","../src/cli/lib/configuration/config.ts","../src/cli/lib/configuration/config-loader.ts","../src/cli/lib/installation/install-base-dir.ts","../src/cli/lib/configuration/config-generator.ts","../src/cli/lib/configuration/scope-predicates.ts","../src/cli/lib/configuration/config-merger.ts","../src/cli/lib/configuration/project-config.ts","../src/cli/lib/stacks/stacks-loader.ts","../src/cli/utils/type-guards.ts","../src/cli/lib/config-gate/index.ts","../src/cli/lib/configuration/config-writer.ts","../src/cli/lib/configuration/config-types-writer.ts","../src/cli/lib/config-gate/classify.ts","../src/cli/lib/config-gate/deps.ts","../src/cli/lib/config-gate/pair-writer.ts","../src/cli/lib/config-gate/propagate.ts","../src/cli/lib/config-gate/recompile.ts","../src/cli/lib/loading/source-fetcher.ts","../src/cli/lib/skills/local-skill-loader.ts","../src/cli/lib/loading/multi-source-loader.ts","../src/cli/lib/matrix/matrix-loader.ts","../src/cli/lib/matrix/skill-resolution.ts","../src/cli/utils/string.ts","../src/cli/lib/matrix/matrix-resolver.ts","../src/cli/lib/validation-result.ts","../src/cli/lib/matrix/matrix-health-check.ts","../src/cli/lib/plugins/plugin-manifest.ts","../src/cli/lib/plugins/plugin-finder.ts","../src/cli/lib/plugins/plugin-ref.ts","../src/cli/lib/plugins/plugin-info.ts","../src/cli/lib/installation/installation.ts","../src/cli/lib/installation/local-installer.ts","../src/cli/lib/compiler.ts","../src/cli/lib/resolver.ts","../src/cli/lib/versioning.ts","../src/cli/utils/exec.ts","../src/cli/lib/agents/write-compiled-agents.ts","../src/cli/lib/skills/skill-metadata.ts","../src/cli/utils/yaml-schema.ts","../src/cli/lib/skills/skill-copier.ts","../src/cli/lib/skills/skill-plugin-compiler.ts","../src/cli/lib/skills/source-switcher.ts","../src/cli/lib/installation/mode-migrator.ts","../src/cli/lib/plugins/plugin-settings.ts","../src/cli/lib/plugins/plugin-discovery.ts","../src/cli/lib/plugins/plugin-validator.ts","../src/cli/lib/configuration/source-manager.ts"],"sourcesContent":["import os from \"os\";\nimport { unique } from \"remeda\";\nimport path from \"path\";\nimport {\n PROJECT_ROOT,\n SKILL_CATEGORIES_PATH,\n SKILL_RULES_PATH,\n SKILLS_DIR_PATH,\n LOCAL_PSEUDO_CATEGORY,\n} from \"../../consts\";\nimport { defaultCategories } from \"../configuration/default-categories\";\nimport { defaultRules } from \"../configuration/default-rules\";\nimport { defaultStacks } from \"../configuration/default-stacks\";\nimport { isHomeDirectory } from \"../installation/is-home-directory\";\nimport { LOCAL_DEFAULTS } from \"../metadata-keys\";\nimport type {\n AgentDefinition,\n AgentName,\n CategoryMap,\n MergedSkillsMatrix,\n RelationshipDefinitions,\n ResolvedSkill,\n ResolvedStack,\n SkillAssignment,\n SkillId,\n SkillScope,\n Stack,\n Category,\n} from \"../../types\";\nimport { fileExists } from \"../../utils/fs\";\nimport { verbose } from \"../../utils/logger\";\nimport { typedEntries, typedFromEntries, typedKeys } from \"../../utils/typed-object\";\nimport {\n DEFAULT_SOURCE,\n isLocalSource,\n loadProjectSourceConfig,\n resolveSource,\n type ResolvedConfig,\n} from \"../configuration\";\nimport { discoverLocalSkills, type LocalSkillDiscoveryResult } from \"../skills\";\nimport {\n checkMatrixHealth,\n extractAllSkills,\n loadSkillCategories,\n loadSkillRules,\n mergeMatrixWithSkills,\n} from \"../matrix\";\nimport { loadAllAgents } from \"./loader\";\nimport { fetchFromSource, fetchMarketplace } from \"./source-fetcher\";\nimport { loadSkillsFromAllSources } from \"./multi-source-loader\";\nimport { loadStacks, resolveAgentConfigToSkills } from \"../stacks\";\nimport { initializeMatrix, matrix as currentMatrix } from \"../matrix/matrix-provider\";\nimport { BUILT_IN_MATRIX } from \"../../types/generated/matrix\";\n\nexport type SourceLoadOptions = {\n sourceFlag?: string;\n projectDir?: string;\n forceRefresh?: boolean;\n devMode?: boolean;\n /** Skip loading skills from extra sources (multi-source). Only needed for wizard UI tagging. */\n skipExtraSources?: boolean;\n /**\n * The caller only needs the matrix, not skill files on disk. For the default\n * source this skips the `fetchFromSource` clone (the matrix is the pre-computed\n * BUILT_IN_MATRIX anyway) so the load stays offline; `sourcePath` comes back\n * empty. Sources that must be read from disk to build the matrix (local paths,\n * custom remotes) are unaffected.\n */\n matrixOnly?: boolean;\n};\n\nexport type SourceLoadResult = {\n matrix: MergedSkillsMatrix;\n sourceConfig: ResolvedConfig;\n sourcePath: string;\n isLocal: boolean;\n marketplace?: string;\n};\n\nexport async function loadSkillsMatrixFromSource(\n options: SourceLoadOptions = {},\n): Promise<SourceLoadResult> {\n const {\n sourceFlag,\n projectDir,\n forceRefresh = false,\n devMode = false,\n matrixOnly = false,\n } = options;\n\n const sourceConfig = await resolveSource(sourceFlag, projectDir);\n const { source } = sourceConfig;\n\n verbose(`Loading skills from source: ${source}`);\n\n const result = await resolveBaseResult(source, sourceConfig, devMode, forceRefresh, matrixOnly);\n\n const resolvedProjectDir = projectDir || process.cwd();\n\n // Load global local skills first, then project local skills — project wins on conflict\n const homeDir = os.homedir();\n if (!isHomeDirectory(resolvedProjectDir)) {\n result.matrix = await mergeDiscoveredLocalSkills(result.matrix, homeDir, \"global\");\n }\n result.matrix = await mergeDiscoveredLocalSkills(result.matrix, resolvedProjectDir, \"project\");\n\n if (!options.skipExtraSources) {\n await loadSkillsFromAllSources(\n result.matrix,\n sourceConfig,\n resolvedProjectDir,\n forceRefresh,\n result.marketplace,\n );\n }\n\n checkMatrixHealth(result.matrix);\n initializeMatrix(result.matrix);\n\n return result;\n}\n\n/**\n * Resolves the base matrix for the configured source: the pre-computed\n * BUILT_IN_MATRIX for the default source, otherwise a local or remote load.\n */\nasync function resolveBaseResult(\n source: string,\n sourceConfig: SourceLoadResult[\"sourceConfig\"],\n devMode: boolean,\n forceRefresh: boolean,\n matrixOnly: boolean,\n): Promise<SourceLoadResult> {\n if (source === DEFAULT_SOURCE && !devMode) {\n // Default source: use pre-computed BUILT_IN_MATRIX instead of loading from disk.\n // Still resolve sourcePath via fetchFromSource so skill files can be read\n // (e.g. for eject-mode copy) — unless the caller declared matrixOnly, in\n // which case the fetch (a network clone on a cold cache) is skipped entirely.\n // The fetch is cached, so no network call if the clone already exists.\n const sourcePath = matrixOnly ? \"\" : (await fetchFromSource(source, { forceRefresh })).path;\n return {\n matrix: {\n ...BUILT_IN_MATRIX,\n skills: { ...BUILT_IN_MATRIX.skills },\n categories: { ...BUILT_IN_MATRIX.categories },\n suggestedStacks: [...BUILT_IN_MATRIX.suggestedStacks],\n },\n sourceConfig,\n sourcePath,\n isLocal: false,\n marketplace: sourceConfig.marketplace,\n };\n }\n\n const isLocal = isLocalSource(source) || devMode === true;\n return isLocal\n ? loadFromLocal(source, sourceConfig, forceRefresh)\n : loadFromRemote(source, sourceConfig, forceRefresh);\n}\n\ntype MarketplaceLabels = Pick<SourceLoadResult, \"marketplace\">;\n\n/**\n * Resolves the marketplace name from the source's\n * `.claude-plugin/marketplace.json`. A `marketplace` already recorded in the\n * project config wins; sources without a marketplace.json keep whatever the\n * config had (possibly nothing) and are labelled by their source name.\n */\nasync function resolveMarketplaceLabels(\n source: string,\n sourceConfig: ResolvedConfig,\n forceRefresh: boolean,\n): Promise<MarketplaceLabels> {\n try {\n const marketplaceResult = await fetchMarketplace(source, { forceRefresh });\n const marketplace = sourceConfig.marketplace ?? marketplaceResult.marketplace.name;\n verbose(`Using marketplace name from marketplace.json: ${marketplace}`);\n return { marketplace };\n } catch {\n verbose(`Source does not have a marketplace.json — using source name as label`);\n return { marketplace: sourceConfig.marketplace };\n }\n}\n\n/** Merges relationship rule sets: source rules first, so they win first-match lookups. */\nfunction mergeRelationships(\n source: RelationshipDefinitions,\n defaults: RelationshipDefinitions,\n): RelationshipDefinitions {\n return {\n conflicts: [...source.conflicts, ...defaults.conflicts],\n discourages: [...source.discourages, ...defaults.discourages],\n recommends: [...source.recommends, ...defaults.recommends],\n requires: [...source.requires, ...defaults.requires],\n alternatives: [...source.alternatives, ...defaults.alternatives],\n compatibleWith: [...(source.compatibleWith ?? []), ...(defaults.compatibleWith ?? [])],\n };\n}\n\n/** Merges any discovered local skills for `dir` into the matrix, logging the find. */\nasync function mergeDiscoveredLocalSkills(\n matrix: MergedSkillsMatrix,\n dir: string,\n label: SkillScope,\n): Promise<MergedSkillsMatrix> {\n const discovered = await discoverLocalSkills(dir);\n if (!discovered || discovered.skills.length === 0) return matrix;\n verbose(\n `Found ${discovered.skills.length} ${label} local skill(s) in ${discovered.localSkillsPath}`,\n );\n return mergeLocalSkillsIntoMatrix(matrix, discovered);\n}\n\nasync function loadFromLocal(\n source: string,\n sourceConfig: ResolvedConfig,\n forceRefresh: boolean,\n): Promise<SourceLoadResult> {\n const skillsPath = !isLocalSource(source)\n ? PROJECT_ROOT\n : path.isAbsolute(source)\n ? source\n : path.resolve(process.cwd(), source);\n\n verbose(`Loading skills from local path: ${skillsPath}`);\n\n const mergedMatrix = await loadAndMergeFromBasePath(skillsPath);\n const labels = await resolveMarketplaceLabels(skillsPath, sourceConfig, forceRefresh);\n\n return {\n matrix: mergedMatrix,\n sourceConfig,\n sourcePath: skillsPath,\n isLocal: true,\n ...labels,\n };\n}\n\nasync function loadFromRemote(\n source: string,\n sourceConfig: ResolvedConfig,\n forceRefresh: boolean,\n): Promise<SourceLoadResult> {\n verbose(`Fetching skills from remote source: ${source}`);\n\n const fetchResult = await fetchFromSource(source, { forceRefresh });\n\n verbose(`Fetched to: ${fetchResult.path}`);\n\n const mergedMatrix = await loadAndMergeFromBasePath(fetchResult.path);\n const labels = await resolveMarketplaceLabels(source, sourceConfig, forceRefresh);\n\n return {\n matrix: mergedMatrix,\n sourceConfig,\n sourcePath: fetchResult.path,\n isLocal: false,\n ...labels,\n };\n}\n\nasync function loadAndMergeFromBasePath(basePath: string): Promise<MergedSkillsMatrix> {\n const sourceProjectConfig = await loadProjectSourceConfig(basePath);\n\n const skillsDirRelPath = sourceProjectConfig?.skillsDir ?? SKILLS_DIR_PATH;\n const stacksRelFile = sourceProjectConfig?.stacksFile;\n\n // Load source categories and rules (if they exist)\n const sourceCategoriesPath = path.join(basePath, SKILL_CATEGORIES_PATH);\n const sourceRulesPath = path.join(basePath, SKILL_RULES_PATH);\n const hasSourceCategories = await fileExists(sourceCategoriesPath);\n const hasSourceRules = await fileExists(sourceRulesPath);\n\n const sourceCategories = hasSourceCategories\n ? await loadSkillCategories(sourceCategoriesPath)\n : undefined;\n if (sourceCategories) {\n verbose(\n `Loaded source categories: ${sourceCategoriesPath} (${typedKeys(sourceCategories).length} categories)`,\n );\n }\n const categories: CategoryMap = sourceCategories\n ? { ...defaultCategories, ...sourceCategories }\n : defaultCategories;\n\n const sourceRules = hasSourceRules ? await loadSkillRules(sourceRulesPath) : undefined;\n if (sourceRules) {\n verbose(`Loaded source rules: ${sourceRulesPath}`);\n }\n const relationships: RelationshipDefinitions = sourceRules\n ? mergeRelationships(sourceRules.relationships, defaultRules.relationships)\n : defaultRules.relationships;\n\n if (hasSourceCategories || hasSourceRules) {\n verbose(`Matrix merged: CLI (${typedKeys(defaultCategories).length} categories) + source`);\n } else {\n verbose(`Matrix from CLI only (source has no categories/rules files)`);\n }\n\n const skillsDir = path.join(basePath, skillsDirRelPath);\n verbose(`Skills from source: ${skillsDir}`);\n\n const skills = await extractAllSkills(skillsDir);\n const mergedMatrix = mergeMatrixWithSkills(categories, relationships, skills);\n initializeMatrix(mergedMatrix);\n\n // Load stacks from source first, fall back to CLI's built-in defaults\n const sourceStacks = await loadStacks(basePath, stacksRelFile);\n const stacks = sourceStacks.length > 0 ? sourceStacks : defaultStacks;\n if (stacks.length > 0) {\n mergedMatrix.suggestedStacks = stacks.map((stack) => convertStackToResolvedStack(stack));\n const stackSource = sourceStacks.length > 0 ? \"source\" : \"CLI\";\n verbose(`Loaded ${stacks.length} stacks from ${stackSource}`);\n }\n\n // Collect explicit domain definitions from agent metadata.yaml files\n const agents = await loadAllAgents(basePath);\n const agentDefinedDomains = typedFromEntries(\n typedEntries<AgentName, AgentDefinition>(agents).flatMap(([agentId, agentDef]) =>\n agentDef.domain ? [[agentId, agentDef.domain] as const] : [],\n ),\n );\n const domainCount = typedKeys(agentDefinedDomains).length;\n if (domainCount > 0) {\n mergedMatrix.agentDefinedDomains = agentDefinedDomains;\n verbose(`Loaded ${domainCount} agent domain definition(s)`);\n }\n\n return mergedMatrix;\n}\n\n// Stack values are already skill IDs — no alias resolution needed\nexport function convertStackToResolvedStack(stack: Stack): ResolvedStack {\n const agentConfigs = typedKeys<AgentName>(stack.agents).flatMap((agentId) => {\n const agentConfig = stack.agents[agentId];\n return agentConfig ? [{ agentId, agentConfig }] : [];\n });\n\n const skills = typedFromEntries(\n agentConfigs.map(\n ({ agentId, agentConfig }) => [agentId, resolveStackAgentSkills(agentConfig)] as const,\n ),\n );\n\n // First-seen order across agents, matching the historical seen-Set accumulation\n const allSkillIds = unique(\n agentConfigs.flatMap(({ agentConfig }) =>\n resolveAgentConfigToSkills(agentConfig).map((ref) => ref.id),\n ),\n );\n\n const agentCount = typedKeys<AgentName>(stack.agents).length;\n verbose(`Stack '${stack.id}' has ${allSkillIds.length} skills from ${agentCount} agents`);\n\n return {\n id: stack.id,\n name: stack.name,\n description: stack.description,\n skills,\n allSkillIds,\n philosophy: stack.philosophy || \"\",\n };\n}\n\n/** Per-category skill ids for one stack agent, keeping only ids present in the current matrix. */\nfunction resolveStackAgentSkills(\n agentConfig: Partial<Record<Category, SkillAssignment[]>>,\n): Partial<Record<Category, SkillId[]>> {\n const byCategory = typedEntries<Category, SkillAssignment[]>(agentConfig)\n .map(([category, assignments]) => ({\n category,\n validIds: (assignments ?? []).filter((a) => a.id in currentMatrix.skills).map((a) => a.id),\n }))\n .filter(({ validIds }) => validIds.length > 0);\n return typedFromEntries(\n byCategory.map(({ category, validIds }) => [category, validIds] as const),\n );\n}\n\n/**\n * Extract a human-readable name from a source URL.\n * e.g. \"github:agents-inc/skills\" -> \"agents-inc\"\n * \"github:acme-corp/claude-skills\" -> \"acme-corp\"\n */\nexport function extractSourceName(source: string): string {\n // Strip protocol prefix (github:, gh:, https://, etc.)\n const withoutProtocol = source.replace(/^(?:github|gh|gitlab|bitbucket|sourcehut):/, \"\");\n const withoutUrl = withoutProtocol.replace(/^https?:\\/\\/[^/]+\\//, \"\");\n\n // Take the first path segment (org/owner name)\n const firstSegment = withoutUrl.split(\"/\")[0];\n return firstSegment || source;\n}\n\nexport function mergeLocalSkillsIntoMatrix(\n matrix: MergedSkillsMatrix,\n localResult: LocalSkillDiscoveryResult,\n): MergedSkillsMatrix {\n for (const metadata of localResult.skills) {\n const existingSkill = matrix.skills[metadata.id];\n\n // If overwriting an existing remote skill, inherit its category unconditionally.\n // Otherwise, use whatever the local skill declared in its metadata.yaml.\n const category = existingSkill?.category ?? metadata.category;\n const slug = existingSkill?.slug ?? metadata.slug;\n const displayName = existingSkill?.displayName ?? metadata.displayName;\n\n const resolvedSkill: ResolvedSkill = {\n id: metadata.id,\n slug,\n displayName,\n description: metadata.description,\n usageGuidance: metadata.usageGuidance,\n\n category,\n\n author: LOCAL_DEFAULTS.AUTHOR,\n\n conflictsWith: existingSkill?.conflictsWith ?? [],\n isRecommended: existingSkill?.isRecommended ?? false,\n recommendedReason: existingSkill?.recommendedReason,\n requires: existingSkill?.requires ?? [],\n alternatives: existingSkill?.alternatives ?? [],\n discourages: existingSkill?.discourages ?? [],\n compatibleWith: existingSkill?.compatibleWith ?? [],\n\n path: metadata.path,\n\n local: true,\n localPath: metadata.localPath,\n custom: metadata.custom,\n };\n\n matrix.skills[metadata.id] = resolvedSkill;\n\n // Ensure the skill's category exists in matrix.categories so that\n // config-types generation can discover its domain and category.\n // Skip \"local\" — it is a pseudo-category, not a real Category union member.\n if (category !== LOCAL_PSEUDO_CATEGORY && !matrix.categories[category] && metadata.domain) {\n matrix.categories[category] = {\n id: category,\n displayName: category,\n description: `Local skill category`,\n domain: metadata.domain,\n exclusive: false,\n required: false,\n order: 0,\n };\n verbose(`Added local category: ${category} (domain: ${metadata.domain})`);\n }\n\n verbose(`Added local skill: ${metadata.id} (category: ${category})`);\n }\n\n return matrix;\n}\n","import fs from \"fs\";\nimport os from \"os\";\n\n/**\n * True when `dir` is the user's home directory — the global installation root.\n *\n * Symlink-safe: compares via `fs.realpathSync` so a symlinked $HOME (common on\n * macOS) still matches. Falls back to a plain string compare when either path\n * cannot be resolved (e.g. does not exist yet). Calls `os.homedir()` at runtime\n * (not the module-load-time `GLOBAL_INSTALL_ROOT` constant) so it agrees with\n * other runtime `os.homedir()` callers and with test home-dir mocks.\n */\nexport function isHomeDirectory(dir: string): boolean {\n try {\n return fs.realpathSync(dir) === fs.realpathSync(os.homedir());\n } catch {\n return dir === os.homedir();\n }\n}\n","import { STANDARD_FILES, STANDARD_DIRS } from \"../consts\";\nimport type { CategoryPath } from \"../types\";\n\n/**\n * YAML field names used in skill metadata.yaml files.\n * Centralized to avoid string duplication across loaders and compilers.\n */\nexport const METADATA_KEYS = {\n DISPLAY_NAME: \"displayName\",\n CLI_DESCRIPTION: \"cliDescription\",\n CATEGORY: \"category\",\n FORKED_FROM: \"forkedFrom\",\n CONTENT_HASH: \"contentHash\",\n USAGE_GUIDANCE: \"usageGuidance\",\n} as const;\n\n/**\n * Default values used when importing third-party skills (no existing metadata).\n */\nexport const IMPORT_DEFAULTS = {\n // Boundary cast: deliberately outside the generated Category union — external\n // skills have no marketplace category; \"imported\" is a display-only placeholder\n CATEGORY: \"imported\" as CategoryPath,\n AUTHOR: \"@imported\",\n DOMAIN: \"shared\" as const,\n} as const;\n\n/**\n * Default values used for local skills (created via `npx agents-inc new skill` or discovered locally).\n */\nexport const LOCAL_DEFAULTS = {\n // Boundary cast: deliberately outside the generated Category union — scaffold\n // placeholder written into starter files for the user to replace\n CATEGORY: \"dummy-category\" as CategoryPath,\n AUTHOR: \"@dummy-author\",\n DOMAIN: \"dummy\" as const,\n} as const;\n\n/**\n * Files included when computing a skill's content hash.\n * Shared by versioning.ts (for plugin version bumps) and\n * skill-plugin-compiler.ts (for plugin compilation).\n */\nexport const SKILL_CONTENT_FILES = [STANDARD_FILES.SKILL_MD, STANDARD_FILES.REFERENCE_MD] as const;\n\n/**\n * Directories included when computing a skill's content hash.\n * Shared by versioning.ts and skill-plugin-compiler.ts.\n */\nexport const SKILL_CONTENT_DIRS = [STANDARD_DIRS.EXAMPLES, STANDARD_DIRS.SCRIPTS] as const;\n","import os from \"os\";\nimport { uniqueBy } from \"remeda\";\nimport { fileExists } from \"../../utils/fs\";\nimport { verbose, warn } from \"../../utils/logger\";\nimport { getErrorMessage } from \"../../utils/errors\";\nimport { DEFAULT_BRANDING, GITHUB_SOURCE } from \"../../consts\";\nimport { projectSourceConfigSchema } from \"../schemas\";\nimport type { ProjectConfig, SourceEntry } from \"../../types\";\nimport { loadConfig } from \"./config-loader\";\nimport { getProjectConfigPath } from \"../installation/install-base-dir\";\n\nexport const DEFAULT_SOURCE = `${GITHUB_SOURCE.GITHUB_PREFIX}agents-inc/skills`;\nexport const SOURCE_ENV_VAR = \"CC_SOURCE\";\n\n// Re-export types that moved to src/cli/types/config.ts for backward compatibility\nexport type { SourceEntry, BrandingConfig } from \"../../types/config\";\n\n// getProjectConfigPath lives in install-base-dir.ts (a neutral leaf) to avoid an\n// import cycle; re-exported here for existing importers of this module.\nexport { getProjectConfigPath };\n\nexport type ResolvedConfig = {\n source: string;\n sourceOrigin: \"flag\" | \"env\" | \"project\" | \"global\" | \"default\";\n marketplace?: string;\n};\n\nasync function loadSourceConfig(\n dir: string,\n scope: \"project\" | \"global\",\n): Promise<Partial<ProjectConfig> | null> {\n const scopeLabel = scope === \"project\" ? \"Project\" : \"Global\";\n const configPath = getProjectConfigPath(dir);\n\n if (!(await fileExists(configPath))) {\n verbose(`${scopeLabel} config not found at ${configPath}`);\n return null;\n }\n\n let data: Partial<ProjectConfig> | null;\n try {\n data = await loadConfig(configPath, projectSourceConfigSchema);\n } catch (error) {\n verbose(`Failed to load ${scope} source config at ${configPath}: ${getErrorMessage(error)}`);\n return null;\n }\n if (!data) return null;\n\n verbose(`Loaded ${scope} config from ${dir}`);\n return data;\n}\n\nexport async function loadProjectSourceConfig(\n projectDir: string,\n): Promise<Partial<ProjectConfig> | null> {\n return loadSourceConfig(projectDir, \"project\");\n}\n\n/** Load source config from the global home directory (~/.claude-src/config.ts). */\nexport async function loadGlobalSourceConfig(): Promise<Partial<ProjectConfig> | null> {\n return loadSourceConfig(os.homedir(), \"global\");\n}\n\n/** The effective source config plus which scope it was actually loaded from. */\ntype EffectiveSourceConfig = {\n config: Partial<ProjectConfig>;\n origin: \"project\" | \"global\";\n};\n\nasync function loadEffectiveSourceConfig(\n projectDir?: string,\n): Promise<EffectiveSourceConfig | null> {\n const projectConfig = projectDir ? await loadProjectSourceConfig(projectDir) : null;\n if (projectConfig) return { config: projectConfig, origin: \"project\" };\n\n const globalConfig = await loadGlobalSourceConfig();\n if (globalConfig) return { config: globalConfig, origin: \"global\" };\n\n return null;\n}\n\n// Precedence: flag > env > project > global > default\nexport async function resolveSource(\n flagValue?: string,\n projectDir?: string,\n): Promise<ResolvedConfig> {\n const effective = await loadEffectiveSourceConfig(projectDir);\n const marketplace = effective?.config.marketplace;\n\n if (flagValue !== undefined) {\n if (flagValue === \"\" || flagValue.trim() === \"\") {\n throw new Error(\n \"--source flag cannot be empty. Provide a valid source: a local directory path or a git repository URL (e.g., './my-skills' or 'https://github.com/user/repo')\",\n );\n }\n validateSourceFormat(flagValue.trim(), \"--source\");\n verbose(`Source from --source flag: ${flagValue}`);\n return { source: flagValue, sourceOrigin: \"flag\", marketplace };\n }\n\n const envValue = process.env[SOURCE_ENV_VAR];\n if (envValue) {\n const trimmed = envValue.trim();\n if (trimmed === \"\") {\n warn(`${SOURCE_ENV_VAR} is set but empty — ignoring and falling back to next source.`);\n } else {\n try {\n validateSourceFormat(trimmed, SOURCE_ENV_VAR);\n verbose(`Source from ${SOURCE_ENV_VAR} env var: ${trimmed}`);\n return { source: trimmed, sourceOrigin: \"env\", marketplace };\n } catch (error) {\n const message = getErrorMessage(error);\n warn(\n `${SOURCE_ENV_VAR} has an invalid value — ignoring and falling back to next source.\\n${message}`,\n );\n }\n }\n }\n\n if (effective?.config.source) {\n verbose(`Source from ${effective.origin} config: ${effective.config.source}`);\n return {\n source: effective.config.source,\n sourceOrigin: effective.origin,\n marketplace,\n };\n }\n\n verbose(`Using default source: ${DEFAULT_SOURCE}`);\n return { source: DEFAULT_SOURCE, sourceOrigin: \"default\", marketplace };\n}\n\nexport async function resolveAuthor(projectDir?: string): Promise<string | undefined> {\n const effective = await loadEffectiveSourceConfig(projectDir);\n return effective?.config.author;\n}\n\n/** Resolved branding with defaults applied for any missing fields */\nexport type ResolvedBranding = {\n name: string;\n tagline: string;\n};\n\n/** Resolves branding from project config, falling back to global then DEFAULT_BRANDING. */\nexport async function resolveBranding(projectDir?: string): Promise<ResolvedBranding> {\n const effective = await loadEffectiveSourceConfig(projectDir);\n return {\n name: effective?.config.branding?.name ?? DEFAULT_BRANDING.NAME,\n tagline: effective?.config.branding?.tagline ?? DEFAULT_BRANDING.TAGLINE,\n };\n}\n\nexport async function resolveAllSources(\n projectDir?: string,\n): Promise<{ primary: SourceEntry; extras: SourceEntry[] }> {\n const effective = await loadEffectiveSourceConfig(projectDir);\n\n const resolvedConfig = await resolveSource(undefined, projectDir);\n const primary: SourceEntry = {\n name: \"marketplace\",\n url: resolvedConfig.source,\n description: \"Primary skills marketplace\",\n };\n\n const extras = uniqueBy(effective?.config.sources ?? [], (s) => s.name);\n\n return { primary, extras };\n}\n\nconst REMOTE_PROTOCOLS = [\n GITHUB_SOURCE.GITHUB_PREFIX, // \"github:\"\n GITHUB_SOURCE.GH_PREFIX, // \"gh:\"\n \"gitlab:\",\n \"bitbucket:\",\n \"sourcehut:\",\n \"https://\",\n \"http://\",\n] as const;\n\n// Minimum length after protocol prefix for a valid remote source (e.g., \"org/repo\" = 8 chars min)\nconst MIN_REMOTE_PATH_LENGTH = 3;\nconst MAX_SOURCE_LENGTH = 512;\n\n// Null bytes must never appear in source strings — they can bypass C-level string termination in downstream tools\nconst NULL_BYTE_PATTERN = /\\0/;\n\n// Path traversal sequences in git refs/branches/tags (e.g., \"?branch=../../etc/passwd\")\nconst PATH_TRAVERSAL_PATTERN = /\\.\\./;\n\n// UNC path prefixes (Windows network paths): \\\\server\\share or //server/share\n// These can trigger SMB authentication to attacker-controlled servers\nconst UNC_PATH_PATTERN = /^(?:\\/\\/|\\\\\\\\)/;\n\n// Private/reserved IPv4 ranges that should not appear in source URLs (SSRF prevention)\n// Matches: 127.x.x.x, 10.x.x.x, 172.16-31.x.x, 192.168.x.x, 0.0.0.0, 169.254.x.x\nconst PRIVATE_IPV4_PATTERN =\n /^(?:127\\.\\d+\\.\\d+\\.\\d+|10\\.\\d+\\.\\d+\\.\\d+|172\\.(?:1[6-9]|2\\d|3[01])\\.\\d+\\.\\d+|192\\.168\\.\\d+\\.\\d+|0\\.0\\.0\\.0|169\\.254\\.\\d+\\.\\d+)$/;\n\n// IPv6 loopback and private addresses in URL hostname brackets\nconst PRIVATE_IPV6_PATTERN =\n /^\\[(?:::1|::ffff:(?:127\\.\\d+\\.\\d+\\.\\d+|10\\.\\d+\\.\\d+\\.\\d+|192\\.168\\.\\d+\\.\\d+)|fd[0-9a-f]{2}:.*|fe80:.*)\\]$/i;\n\n/**\n * Validates a source string format before it reaches giget or filesystem operations.\n * Catches obviously invalid formats early with clear error messages.\n *\n * @param source - The trimmed, non-empty source value to validate\n * @param flagName - The flag name for error messages (\"--source\" or \"--agent-source\")\n */\nexport function validateSourceFormat(source: string, flagName: string): void {\n // Null bytes can bypass C-level string termination in downstream tools (giget, git)\n if (NULL_BYTE_PATTERN.test(source)) {\n throw new Error(\n `${flagName} contains invalid characters.\\n\\n` +\n `Source values must not contain null bytes.\\n` +\n `Examples:\\n` +\n ` ${flagName} ./my-skills\\n` +\n ` ${flagName} github:user/repo`,\n );\n }\n\n if (source.length > MAX_SOURCE_LENGTH) {\n throw new Error(\n `${flagName} value is too long (${source.length} characters, max ${MAX_SOURCE_LENGTH}).\\n\\n` +\n `Provide a shorter source path or URL.\\n` +\n `Examples:\\n` +\n ` ${flagName} ./my-skills\\n` +\n ` ${flagName} github:user/repo`,\n );\n }\n\n const matchedProtocol = REMOTE_PROTOCOLS.find((prefix) => source.startsWith(prefix));\n\n if (matchedProtocol) {\n validateRemoteSource(source, matchedProtocol, flagName);\n } else {\n validateLocalPath(source, flagName);\n }\n}\n\nfunction validateRemoteSource(source: string, protocol: string, flagName: string): void {\n const pathAfterProtocol = source.slice(protocol.length).trim();\n\n if (pathAfterProtocol.length < MIN_REMOTE_PATH_LENGTH) {\n throw new Error(\n `${flagName} has an incomplete URL: \"${source}\"\\n\\n` +\n `A repository path is required after the protocol prefix.\\n` +\n `Examples:\\n` +\n ` ${flagName} github:user/repo\\n` +\n ` ${flagName} https://github.com/user/repo`,\n );\n }\n\n // Block path traversal in any remote source (refs, branches, query params)\n if (PATH_TRAVERSAL_PATTERN.test(pathAfterProtocol)) {\n throw new Error(\n `${flagName} contains path traversal in URL: \"${source}\"\\n\\n` +\n `Remote source URLs must not contain '..' sequences.\\n` +\n `Examples:\\n` +\n ` ${flagName} github:user/repo\\n` +\n ` ${flagName} https://github.com/user/repo`,\n );\n }\n\n // For https:// and http:// URLs, validate basic URL structure\n if (protocol === \"https://\" || protocol === \"http://\") {\n validateHttpUrl(source, flagName);\n }\n\n // For git shorthand protocols (github:, gh:, gitlab:, etc.), validate org/repo pattern\n if (protocol !== \"https://\" && protocol !== \"http://\") {\n validateGitShorthand(source, pathAfterProtocol, flagName);\n }\n}\n\nfunction validateHttpUrl(source: string, flagName: string): void {\n // Basic URL structure check: must have a hostname with at least one dot or localhost\n const afterProtocol = source.replace(/^https?:\\/\\//, \"\");\n // Strip port number for hostname validation (e.g., \"localhost:8080\" -> \"localhost\")\n const hostnameWithPort = afterProtocol.split(\"/\")[0] ?? \"\";\n const hostname = hostnameWithPort.split(\":\")[0] ?? \"\";\n\n // Allow: dotted hostnames (github.com), localhost, and bracketed IPv6 ([::1])\n const isBracketedIPv6 = hostnameWithPort.startsWith(\"[\") && hostnameWithPort.includes(\"]\");\n if (!hostname || (!hostname.includes(\".\") && hostname !== \"localhost\" && !isBracketedIPv6)) {\n throw new Error(\n `${flagName} has an invalid URL: \"${source}\"\\n\\n` +\n `The URL must include a valid hostname.\\n` +\n `Examples:\\n` +\n ` ${flagName} https://github.com/user/repo\\n` +\n ` ${flagName} https://gitlab.company.com/team/skills`,\n );\n }\n\n // Block private/reserved IP addresses (SSRF prevention via giget)\n if (PRIVATE_IPV4_PATTERN.test(hostname) || PRIVATE_IPV6_PATTERN.test(hostnameWithPort)) {\n throw new Error(\n `${flagName} points to a private or reserved IP address: \"${source}\"\\n\\n` +\n `Source URLs must not target private network addresses.\\n` +\n `Use a public hostname instead.\\n` +\n `Examples:\\n` +\n ` ${flagName} https://github.com/user/repo\\n` +\n ` ${flagName} https://gitlab.company.com/team/skills`,\n );\n }\n}\n\nfunction validateGitShorthand(source: string, repoPath: string, flagName: string): void {\n // Git shorthand format: protocol:owner/repo (must have at least owner/repo)\n if (!repoPath.includes(\"/\")) {\n throw new Error(\n `${flagName} has an invalid repository reference: \"${source}\"\\n\\n` +\n `Git shorthand sources require an owner/repo format.\\n` +\n `Examples:\\n` +\n ` ${flagName} github:user/repo\\n` +\n ` ${flagName} gh:organization/skills`,\n );\n }\n}\n\nfunction validateLocalPath(source: string, flagName: string): void {\n // Check for control characters (except common whitespace)\n // eslint-disable-next-line no-control-regex\n const CONTROL_CHAR_PATTERN = /[\\x00-\\x08\\x0E-\\x1F\\x7F]/u;\n if (CONTROL_CHAR_PATTERN.test(source)) {\n throw new Error(\n `${flagName} contains invalid characters: \"${source}\"\\n\\n` +\n `Source paths must not contain control characters.\\n` +\n `Examples:\\n` +\n ` ${flagName} ./my-skills\\n` +\n ` ${flagName} /home/user/skills`,\n );\n }\n\n // Block UNC paths (Windows network paths like \\\\server\\share or //server/share)\n // These can trigger SMB authentication to attacker-controlled servers, leaking credentials\n if (UNC_PATH_PATTERN.test(source)) {\n throw new Error(\n `${flagName} contains a UNC network path: \"${source}\"\\n\\n` +\n `Network paths (\\\\\\\\server\\\\share or //server/share) are not allowed for security reasons.\\n` +\n `Use a local directory path or a remote URL instead.\\n` +\n `Examples:\\n` +\n ` ${flagName} ./my-skills\\n` +\n ` ${flagName} /home/user/skills\\n` +\n ` ${flagName} https://github.com/user/repo`,\n );\n }\n}\n\nexport function isLocalSource(source: string): boolean {\n if (source.startsWith(\"/\") || source.startsWith(\".\")) {\n return true;\n }\n\n const hasRemoteProtocol = REMOTE_PROTOCOLS.some((prefix) => source.startsWith(prefix));\n\n if (!hasRemoteProtocol) {\n if (source.includes(\"..\") || source.includes(\"~\")) {\n throw new Error(\n `Invalid source path: ${source}. Path traversal patterns like '..' and '~' are not allowed for security reasons. Use absolute paths or remote URLs instead (e.g., '/home/user/skills' or 'https://github.com/user/repo').`,\n );\n }\n }\n\n return !hasRemoteProtocol;\n}\n","import path from \"path\";\nimport { fileURLToPath } from \"url\";\nimport { createJiti } from \"jiti\";\nimport { fileExists } from \"../../utils/fs\";\nimport { verbose } from \"../../utils/logger\";\nimport { getErrorMessage } from \"../../utils/errors\";\nimport { formatZodIssues } from \"../schemas\";\nimport type { z } from \"zod\";\n\n/** Resolve agents-inc/config to the source config-exports.ts so jiti can load it in dev. */\nconst CONFIG_EXPORTS_PATH = path.resolve(\n path.dirname(fileURLToPath(import.meta.url)),\n \"../../config-exports.ts\",\n);\n\n/**\n * Loads a TypeScript config file using jiti.\n * Returns null when the file does not exist.\n * Throws on validation failure or malformed/broken files.\n *\n * @param configPath - Absolute path to the .ts config file\n * @param schema - Optional Zod schema; when provided, T is inferred from it\n */\nexport async function loadConfig<T>(configPath: string, schema?: z.ZodType<T>): Promise<T | null> {\n if (!(await fileExists(configPath))) {\n verbose(`Config not found at ${configPath}`);\n return null;\n }\n\n let raw: unknown;\n try {\n const jiti = createJiti(import.meta.url, {\n moduleCache: false,\n interopDefault: true,\n // Both spellings on purpose. `@agents-inc/cli/config` is the package name the CLI published\n // under until 0.150.0, and a config hand-written against the documentation of the day imports\n // it — but nothing answers to that name in node_modules now that the CLI ships as\n // `agents-inc`, so dropping the key would stop such a config loading on upgrade. Removing it\n // once nobody is on the old package: REPO-24 in todo/repo.md.\n alias: {\n \"agents-inc/config\": CONFIG_EXPORTS_PATH,\n \"@agents-inc/cli/config\": CONFIG_EXPORTS_PATH,\n },\n });\n\n raw = await jiti.import(configPath, { default: true });\n } catch (error) {\n throw new Error(`Failed to load config from '${configPath}': ${getErrorMessage(error)}`, {\n cause: error,\n });\n }\n\n // Empty or whitespace-only files produce an empty module object with no default export.\n // Treat this the same as a missing file rather than returning a confusing empty object.\n if (raw == null || (typeof raw === \"object\" && Object.keys(raw as object).length === 0)) {\n verbose(`Config at ${configPath} has no default export`);\n return null;\n }\n\n if (schema) {\n const result = schema.safeParse(raw);\n if (!result.success) {\n throw new Error(\n `Config validation failed at '${configPath}': ${formatZodIssues(result.error.issues)}`,\n );\n }\n return result.data;\n }\n\n // Boundary cast: jiti returns unknown, caller provides expected type\n return raw as T;\n}\n","import os from \"os\";\nimport path from \"path\";\nimport type { SkillScope } from \"../../types/config.js\";\nimport {\n CLAUDE_DIR,\n CLAUDE_SRC_DIR,\n LOCAL_SKILLS_PATH,\n STANDARD_DIRS,\n STANDARD_FILES,\n} from \"../../consts.js\";\n\n/**\n * Base directory for a scope's installed artifacts: the home directory for\n * `\"global\"` scope, the project directory otherwise (absent scope defaults to\n * project). Calls `os.homedir()` at runtime so test home-dir mocks apply.\n */\nexport function installBaseDir(projectDir: string, scope: SkillScope | undefined): string {\n return scope === \"global\" ? os.homedir() : projectDir;\n}\n\n/** Path to the unified project config (`<dir>/.claude-src/config.ts`). */\nexport function getProjectConfigPath(dir: string): string {\n return path.join(dir, CLAUDE_SRC_DIR, STANDARD_FILES.CONFIG_TS);\n}\n\nexport type InstallPaths = {\n skillsDir: string;\n agentsDir: string;\n configPath: string;\n};\n\nexport function resolveInstallPaths(\n projectDir: string,\n scope: SkillScope = \"project\",\n): InstallPaths {\n const baseDir = installBaseDir(projectDir, scope);\n return {\n skillsDir: path.join(baseDir, LOCAL_SKILLS_PATH),\n agentsDir: path.join(baseDir, CLAUDE_DIR, STANDARD_DIRS.AGENTS),\n configPath: getProjectConfigPath(baseDir),\n };\n}\n","import type {\n AgentName,\n CategoryPath,\n ProjectConfig,\n SkillAssignment,\n SkillId,\n Stack,\n StackAgentConfig,\n Category,\n} from \"../../types\";\nimport { groupBy, indexBy, partition } from \"remeda\";\n\nimport type { AgentScopeConfig, SkillConfig, SkillScope } from \"../../types/config\";\nimport { matrix } from \"../matrix/matrix-provider\";\nimport { EJECT_SOURCE, GLOBAL_CONFIG_NAME, LOCAL_PSEUDO_CATEGORY } from \"../../consts\";\nimport { isActiveAt, activeAgentScopeMap, effectivelyExcludedSkillIds } from \"./scope-predicates\";\nimport { verbose, warn } from \"../../utils/logger\";\nimport { typedEntries, typedFromEntries, typedKeys } from \"../../utils/typed-object\";\n\nexport type SplitConfigResult = {\n global: ProjectConfig;\n project: ProjectConfig;\n};\n\nexport type ProjectConfigOptions = {\n description?: string;\n author?: string;\n};\n\nfunction extractCategoryFromPath(categoryPath: CategoryPath): Category | undefined {\n if (categoryPath === LOCAL_PSEUDO_CATEGORY) return undefined;\n // TypeScript narrows CategoryPath to Category after excluding \"local\"\n return categoryPath;\n}\n\ntype StackBuildInputs = {\n agentList: AgentName[];\n activeSkillsByCategory: Map<Category, SkillId[]>;\n skillScope: Map<SkillId, SkillScope>;\n agentScope: Map<AgentName, SkillScope>;\n existingStack: Partial<Record<AgentName, StackAgentConfig>>;\n /**\n * Skills that are new to this session's top-level selection (not in the prior\n * `existing.config.skills`). When `undefined`, the D-220 per-agent curation\n * preservation rule is disabled and every scope-compatible skill lands on\n * every existing agent (legacy behavior). When defined (possibly empty), the\n * preservation rule applies: skills NOT in an agent's prior stack entry and\n * NOT in this set are omitted from that agent's stack — respecting the\n * user's curation.\n */\n newlyAddedSkillIds?: ReadonlySet<SkillId>;\n /**\n * Keys of `(agent, skillId)` pairs whose scope-compatibility was GAINED this\n * session — either the skill's scope was flipped so it now reaches this\n * agent, or the agent's scope was flipped so previously-filtered skills now\n * reach it. Parallel to `newlyAddedSkillIds`: when the caller opts into\n * D-220 preservation semantics, this set admits triples that the skill-id\n * diff would miss. Keys are produced by `scopeEligibilityKey()`.\n */\n scopeEligibilityGained?: ReadonlySet<string>;\n};\n\n/**\n * Encodes an `(agent, skillId)` pair as a single string for set-membership\n * lookups. Both arguments are typed string unions so a `|` delimiter produces\n * a unique, stable key.\n */\nexport function scopeEligibilityKey(agent: AgentName, skillId: SkillId): string {\n return `${agent}|${skillId}`;\n}\n\nfunction wasPreviouslyPreloaded(\n existingStack: Partial<Record<AgentName, StackAgentConfig>>,\n agent: AgentName,\n category: Category,\n skillId: SkillId,\n): boolean {\n const prior = existingStack[agent]?.[category]?.find((a) => a.id === skillId);\n return prior?.preloaded === true;\n}\n\nfunction getScopeOrThrow<K>(map: Map<K, SkillScope>, key: K, kind: \"skill\" | \"agent\"): SkillScope {\n const scope = map.get(key);\n if (scope === undefined) {\n throw new Error(\n `generateProjectConfigFromSkills: ${kind} '${String(key)}' missing from ` +\n `${kind === \"skill\" ? \"skillConfigs\" : \"agentConfigs\"}. ` +\n `Caller must pass a ${kind === \"skill\" ? \"SkillConfig\" : \"AgentScopeConfig\"} ` +\n `for every selected ${kind}.`,\n );\n }\n return scope;\n}\n\n/** Project skills never reach global agents; global skills reach any agent. */\nexport function isScopePairCompatible(skillScope: SkillScope, agentScope: SkillScope): boolean {\n return !(skillScope === \"project\" && agentScope === \"global\");\n}\n\nfunction isScopeCompatible(\n skillId: SkillId,\n agent: AgentName,\n skillScope: Map<SkillId, SkillScope>,\n agentScope: Map<AgentName, SkillScope>,\n): boolean {\n const sScope = getScopeOrThrow(skillScope, skillId, \"skill\");\n const aScope = getScopeOrThrow(agentScope, agent, \"agent\");\n return isScopePairCompatible(sScope, aScope);\n}\n\n/**\n * Decides whether a given `(agent, category, skillId)` triple lands in the\n * agent's stack for this save. The scope filter has already run in the caller\n * — this function only enforces D-220's per-agent curation rule.\n *\n * Branches:\n * - `agent ∉ existingStack` → seed branch (new agent); every scope-compatible\n * skill lands with `preloaded: false` (or preserved if present for another\n * reason, which cannot happen here).\n * - `agent ∈ existingStack` → preservation branch:\n * * skillId was in `existingStack[agent][category]` → KEEP (idempotent).\n * * skillId ∈ `newlyAddedSkillIds` OR `(agent, skillId)` ∈\n * `scopeEligibilityGained` → APPEND (user's session-level addition or\n * scope-compat flip).\n * * otherwise → OMIT (respect user's prior per-agent curation removal).\n *\n * Legacy path: when `newlyAddedSkillIds` is not provided, the D-220 check is\n * disabled — every scope-compatible skill lands. This preserves the contract\n * of callers that pre-date D-220.\n */\nfunction shouldIncludeTriple(\n agent: AgentName,\n category: Category,\n skillId: SkillId,\n inputs: StackBuildInputs,\n): boolean {\n // Legacy path: callers that don't opt in keep the pre-D-220 behavior.\n if (inputs.newlyAddedSkillIds === undefined) return true;\n\n const agentExistingStack = inputs.existingStack[agent];\n if (agentExistingStack === undefined) {\n // Seeding branch: agent is new this session → full ownership-derived stack.\n return true;\n }\n\n const priorCategory = agentExistingStack[category];\n if (priorCategory && priorCategory.some((a) => a.id === skillId)) return true;\n\n if (inputs.newlyAddedSkillIds.has(skillId)) return true;\n const scopeEligibility = inputs.scopeEligibilityGained;\n if (scopeEligibility && scopeEligibility.has(scopeEligibilityKey(agent, skillId))) {\n return true;\n }\n return false;\n}\n\nfunction buildAgentStack(agent: AgentName, inputs: StackBuildInputs): StackAgentConfig | undefined {\n const agentStack: StackAgentConfig = {};\n for (const [category, skillIds] of inputs.activeSkillsByCategory) {\n const assignments = skillIds\n .filter((id) => isScopeCompatible(id, agent, inputs.skillScope, inputs.agentScope))\n .filter((id) => shouldIncludeTriple(agent, category, id, inputs))\n .map<SkillAssignment>((id) => ({\n id,\n preloaded: wasPreviouslyPreloaded(inputs.existingStack, agent, category, id),\n }));\n if (assignments.length > 0) {\n agentStack[category] = assignments;\n }\n }\n return typedKeys<Category>(agentStack).length > 0 ? agentStack : undefined;\n}\n\nfunction buildStackForSelection(\n inputs: StackBuildInputs,\n): Partial<Record<AgentName, StackAgentConfig>> | undefined {\n // No agents in play → this caller is not managing the stack. Return\n // `undefined` (key omitted) so the merger preserves any existing stack.\n if (inputs.agentList.length === 0) {\n verbose(`buildStackForSelection: no agents — returning undefined (stack untouched)`);\n return undefined;\n }\n\n // Agents are in play → the generator authoritatively rebuilt the stack from\n // the current selection. An empty result is a real \"nothing preloads\" outcome\n // (e.g. the last categorized skill was removed), so return `{}` — NOT\n // `undefined`. The merger trusts `{}` and drops the stale existing stack,\n // whereas `undefined` would resurrect it (the removed-last-skill bug).\n const result: Partial<Record<AgentName, StackAgentConfig>> = {};\n for (const agent of inputs.agentList) {\n const built = buildAgentStack(agent, inputs);\n if (built) result[agent] = built;\n }\n return result;\n}\n\n/**\n * Generates a ProjectConfig from a list of selected skill IDs, rebuilding the\n * stack property (agent -> category -> SkillAssignment[]) from the current\n * wizard selection plus any previously-saved stack entries.\n *\n * Ownership rules (what lands in each agent's stack):\n * - agent is selected AND skill is non-excluded AND agent is non-excluded\n * - scope filter: a project-scoped skill never lands on a global-scoped agent\n *\n * Preloaded flags are inherited from `options.existingStack` when the same\n * (agent, category, skill) triple was present before. New pairs default to\n * `preloaded: false` — preloaded is author-asserted via stack YAML at init\n * time and is never auto-set here.\n *\n * @param name - Project name for the config\n * @param selectedSkillIds - Skill IDs selected by the user in the wizard\n * @param options - Optional description, author, selectedAgents, skillConfigs,\n * agentConfigs, and existingStack fields. When skillConfigs is\n * provided, it is used directly as `skills` in the config;\n * otherwise SkillConfig entries are synthesized with defaults.\n * @returns Complete ProjectConfig ready to be saved to config.ts\n */\ntype ResolvedSkillEntry = { skillId: SkillId; category: Category };\n\n/**\n * Resolves selected ids against the matrix: warns and drops unknown ids, extracts\n * each skill's category, and drops ids whose every config entry is excluded.\n * A skill with an excluded global entry AND an active project entry is KEPT —\n * the active entry still needs to reach the stack builder.\n */\nfunction resolveValidSkills(\n selectedSkillIds: SkillId[],\n skillConfigs: SkillConfig[],\n): { validSkills: ResolvedSkillEntry[]; foundCount: number; skippedCount: number } {\n const looked = selectedSkillIds.map((skillId) => {\n const skill = matrix.skills[skillId];\n if (!skill) warn(`Skill '${skillId}' NOT FOUND in matrix`, { suppressInTest: true });\n return { skillId, skill };\n });\n const found = looked.filter(\n (entry): entry is typeof entry & { skill: NonNullable<typeof entry.skill> } =>\n entry.skill != null,\n );\n const skippedCount = looked.length - found.length;\n\n if (skippedCount > 0) {\n const matrixSample = typedKeys<SkillId>(matrix.skills).slice(0, 5).join(\", \");\n warn(\n `${skippedCount}/${selectedSkillIds.length} skills not found in matrix. ` +\n `Matrix keys sample: [${matrixSample}]`,\n { suppressInTest: true },\n );\n }\n\n const excludedSkillIds = effectivelyExcludedSkillIds(skillConfigs);\n\n const validSkills = found\n .map(({ skillId, skill }) => ({\n skillId,\n category: extractCategoryFromPath(skill.category),\n }))\n .filter((entry): entry is typeof entry & { category: Category } => entry.category != null)\n .filter((entry) => !excludedSkillIds.has(entry.skillId));\n\n return { validSkills, foundCount: found.length, skippedCount };\n}\n\n/**\n * Per-skill scope, active-entry-authoritative: when a skill has both an excluded\n * and an active entry (excluded global + active project), excluded entries spread\n * first so active entries overwrite them.\n */\nfunction buildSkillScopeMap(skillConfigs: SkillConfig[]): Map<SkillId, SkillScope> {\n const [excludedConfigs, activeConfigs] = partition(skillConfigs, (s) => Boolean(s.excluded));\n return new Map([...excludedConfigs, ...activeConfigs].map((s) => [s.id, s.scope]));\n}\n\n/**\n * One active AgentScopeConfig per selected agent. When the caller provided\n * agentConfigs, every selected agent MUST have a non-excluded entry (invariant\n * throw); otherwise agents default to project scope.\n */\nfunction resolveActiveAgentConfigs(\n agentList: AgentName[],\n providedConfigs: AgentScopeConfig[] | undefined,\n): AgentScopeConfig[] {\n const providedByName = providedConfigs\n ? indexBy(\n providedConfigs.filter((a) => !a.excluded),\n (a) => a.name,\n )\n : {};\n return agentList.map((agentName) => {\n if (providedConfigs) {\n const provided = providedByName[agentName];\n if (!provided) {\n throw new Error(\n `generateProjectConfigFromSkills: selected agent '${agentName}' has no ` +\n `non-excluded AgentScopeConfig in agentConfigs.`,\n );\n }\n return provided;\n }\n return { name: agentName, scope: \"project\" as const };\n });\n}\n\nexport function generateProjectConfigFromSkills(\n name: string,\n selectedSkillIds: SkillId[],\n options?: ProjectConfigOptions & {\n selectedAgents?: AgentName[];\n skillConfigs?: SkillConfig[];\n agentConfigs?: AgentScopeConfig[];\n existingStack?: Partial<Record<AgentName, StackAgentConfig>>;\n /**\n * Skills new to this session (not present in the prior on-disk config).\n * Passing this field (even as an empty array) opts into D-220's per-agent\n * curation preservation: existing agents' stack entries are treated as\n * authoritative, and skills absent from a given agent's prior stack are\n * only appended when they appear in this set (or in `scopeEligibilityGained`).\n * When undefined, behavior falls back to pre-D-220 semantics.\n */\n newlyAddedSkillIds?: readonly SkillId[];\n /**\n * `(agent, skillId)` keys whose scope-compat transitioned from incompatible\n * to compatible this session. Admits scope-flip cases that `newlyAddedSkillIds`\n * (keyed by skill id only) cannot express. Keys are built with\n * {@link scopeEligibilityKey}.\n */\n scopeEligibilityGained?: ReadonlySet<string>;\n },\n): ProjectConfig {\n const agentList = options?.selectedAgents ? [...options.selectedAgents].sort() : [];\n\n // Invariant: when selectedAgents is provided, callers must also supply the\n // authoritative SkillConfig and AgentScopeConfig entries so scope lookups\n // never silently default. Enforced here to prevent Bug 1-class regressions\n // where a missing config silently resolves every scope to \"project\".\n if (agentList.length > 0) {\n if (!options?.skillConfigs) {\n throw new Error(\n `generateProjectConfigFromSkills: selectedAgents was passed without skillConfigs. ` +\n `Callers must pass a SkillConfig for every selected skill.`,\n );\n }\n if (!options.agentConfigs) {\n throw new Error(\n `generateProjectConfigFromSkills: selectedAgents was passed without agentConfigs. ` +\n `Callers must pass an AgentScopeConfig for every selected agent.`,\n );\n }\n }\n\n // Safe after invariant: when agentList is non-empty these are guaranteed present.\n // When agentList is empty, no scope/ownership work runs so `[]` is a valid no-op.\n const skillConfigs = options?.skillConfigs ?? [];\n const agentConfigs = options?.agentConfigs ?? [];\n\n verbose(\n `generateProjectConfigFromSkills: ${selectedSkillIds.length} skills, ` +\n `matrix has ${typedKeys<SkillId>(matrix.skills).length} entries, ` +\n `agents=[${agentList.join(\", \")}]`,\n );\n\n const { validSkills, foundCount, skippedCount } = resolveValidSkills(\n selectedSkillIds,\n skillConfigs,\n );\n\n verbose(\n `generateProjectConfigFromSkills: ${foundCount} found, ${skippedCount} not found, ` +\n `${agentList.length} agents in stack`,\n );\n\n const activeSkillsByCategory = new Map(\n typedEntries(groupBy(validSkills, (entry) => entry.category)).map(([category, entries]) => [\n category,\n entries.map((entry) => entry.skillId),\n ]),\n );\n\n const skillScope = buildSkillScopeMap(skillConfigs);\n const agentScope = activeAgentScopeMap(agentConfigs);\n\n // Opt-in D-220 preservation: only when the caller provides the delta set.\n // `newlyAddedSkillIds === undefined` triggers legacy seed-everything behavior\n // (preserves pre-D-220 callers and existing unit tests that set up\n // `existingStack` without the new field).\n const newlyAddedSkillIdsSet: ReadonlySet<SkillId> | undefined =\n options?.newlyAddedSkillIds === undefined ? undefined : new Set(options.newlyAddedSkillIds);\n\n const stackProperty = buildStackForSelection({\n agentList,\n activeSkillsByCategory,\n skillScope,\n agentScope,\n existingStack: options?.existingStack ?? {},\n ...(newlyAddedSkillIdsSet !== undefined && { newlyAddedSkillIds: newlyAddedSkillIdsSet }),\n ...(options?.scopeEligibilityGained !== undefined && {\n scopeEligibilityGained: options.scopeEligibilityGained,\n }),\n });\n\n const skills: SkillConfig[] =\n options?.skillConfigs ??\n selectedSkillIds.map((id) => ({ id, scope: \"project\" as const, source: EJECT_SOURCE }));\n\n const activeAgentConfigs = resolveActiveAgentConfigs(agentList, options?.agentConfigs);\n // Excluded agents aren't in selectedAgents but must be preserved in config\n const excludedAgentConfigs = agentConfigs.filter((ac) => ac.excluded);\n const finalAgentConfigs: AgentScopeConfig[] = [...activeAgentConfigs, ...excludedAgentConfigs];\n\n return {\n name,\n agents: finalAgentConfigs,\n skills,\n ...(stackProperty && { stack: stackProperty }),\n ...(options?.description && { description: options.description }),\n ...(options?.author && { author: options.author }),\n };\n}\n\n/**\n * Extracts the stack property (agent -> category -> SkillAssignment[]) from a Stack definition.\n *\n * Stack values are already normalized to SkillAssignment[] by loadStacks().\n * Preserves all assignments and preloaded flags for round-trip fidelity.\n *\n * @param stack - Loaded Stack definition with normalized agent configs\n * @returns Partial mapping of agent names to category-skill assignment mappings\n */\nexport function buildStackProperty(stack: Stack): Partial<Record<AgentName, StackAgentConfig>> {\n return typedFromEntries(\n typedEntries<AgentName, StackAgentConfig>(stack.agents)\n .filter(([, agentConfig]) => agentConfig && typedKeys<Category>(agentConfig).length > 0)\n .map(([agentId, agentConfig]) => {\n const resolvedMappings: StackAgentConfig = typedFromEntries(\n typedEntries<Category, SkillAssignment[]>(agentConfig).filter(\n ([, assignments]) => assignments && assignments.length > 0,\n ),\n );\n return [agentId, resolvedMappings] as const;\n })\n .filter(([, mappings]) => typedKeys<Category>(mappings).length > 0),\n );\n}\n\n/** Splits one agent's stack per category: global skills → global config, project skills → project config. */\nfunction splitAgentStack(\n agentStack: StackAgentConfig,\n globalSkillIds: ReadonlySet<SkillId>,\n): { global: StackAgentConfig; project: StackAgentConfig } {\n const perCategory = typedEntries<Category, SkillAssignment[]>(agentStack)\n .filter(([, assignments]) => assignments !== undefined)\n .map(([category, assignments]) => {\n const [globalOnly, projectOnly] = partition(assignments, (a) => globalSkillIds.has(a.id));\n return { category, globalOnly, projectOnly };\n });\n return {\n global: Object.fromEntries(\n perCategory.filter((c) => c.globalOnly.length > 0).map((c) => [c.category, c.globalOnly]),\n ),\n project: Object.fromEntries(\n perCategory.filter((c) => c.projectOnly.length > 0).map((c) => [c.category, c.projectOnly]),\n ),\n };\n}\n\n/**\n * Splits a ProjectConfig by scope into global and project partitions.\n * Skills with `scope: \"global\"` go to the global partition, `scope: \"project\"` to the project partition.\n * Agents are split based on which skills reference them in the stack.\n * Domains are preserved in both configs as-is (the project config extends global at runtime).\n */\nexport function splitConfigByScope(config: ProjectConfig): SplitConfigResult {\n // Every entry is either active-global or project-owned (project-scoped, or an\n // excluded-global tombstone routed to the project partition as an override).\n const [globalSkills, projectSkills] = partition(config.skills, (s) => isActiveAt(s, \"global\"));\n const [globalAgents, projectAgents] = partition(config.agents, (a) => isActiveAt(a, \"global\"));\n\n // Split stack by agent partition, filtering global agents' stacks to only reference global skills.\n // Project agents keep ALL skill references (both project and global) since global skills are available everywhere.\n const globalSkillIds = new Set(globalSkills.map((s) => s.id));\n const globalStack: typeof config.stack = {};\n const projectStack: typeof config.stack = {};\n\n if (config.stack) {\n for (const agent of globalAgents) {\n const agentStack = config.stack[agent.name];\n if (!agentStack) continue;\n const split = splitAgentStack(agentStack, globalSkillIds);\n if (typedKeys<Category>(split.global).length > 0) {\n globalStack[agent.name] = split.global;\n }\n if (typedKeys<Category>(split.project).length > 0) {\n projectStack[agent.name] = split.project;\n }\n }\n for (const agent of projectAgents) {\n if (config.stack[agent.name]) {\n projectStack[agent.name] = config.stack[agent.name];\n }\n }\n }\n\n // Split selectedAgents by scope: global agents go to global config, project agents to project config\n const globalAgentNames = new Set(globalAgents.map((a) => a.name));\n const [globalSelectedAgents, projectSelectedAgents] = partition(\n config.selectedAgents ?? [],\n (a) => globalAgentNames.has(a),\n );\n\n // Domains are a UI/preference concept — all selected domains go in global config.\n // Project config inherits domains from global at runtime, so it gets none.\n const globalConfig: ProjectConfig = {\n ...config,\n name: GLOBAL_CONFIG_NAME,\n agents: globalAgents,\n skills: globalSkills,\n ...(Object.keys(globalStack).length > 0 ? { stack: globalStack } : { stack: undefined }),\n domains: config.domains,\n selectedAgents: globalSelectedAgents.length > 0 ? globalSelectedAgents : undefined,\n };\n\n const projectConfig: ProjectConfig = {\n ...config,\n name: config.name,\n agents: projectAgents,\n skills: projectSkills,\n ...(Object.keys(projectStack).length > 0 ? { stack: projectStack } : { stack: undefined }),\n domains: undefined,\n selectedAgents: projectSelectedAgents.length > 0 ? projectSelectedAgents : undefined,\n };\n\n return { global: globalConfig, project: projectConfig };\n}\n","import type { AgentName, SkillId } from \"../../types/index.js\";\nimport type { AgentScopeConfig, SkillConfig, SkillScope } from \"../../types/config.js\";\n\n/** Shared shape of scoped config entries (skills and agents). */\nexport type ScopedEntry = { scope?: SkillScope; excluded?: boolean };\n\n/** Active (non-excluded) entry at the given scope. */\nexport function isActiveAt(entry: ScopedEntry, scope: SkillScope): boolean {\n return entry.scope === scope && !entry.excluded;\n}\n\n/** Tombstone masking a global install (`scope === \"global\"` + excluded). */\nexport function isGlobalTombstone(entry: ScopedEntry): boolean {\n return entry.scope === \"global\" && !!entry.excluded;\n}\n\n/**\n * Entry the project owns: a project-scoped entry, or the project's own global\n * tombstone. Inherited global-active entries belong to the global config.\n */\nexport function isProjectOwned(entry: ScopedEntry): boolean {\n return entry.scope === \"project\" || isGlobalTombstone(entry);\n}\n\n/** Names of active project-scoped agents. */\nexport function activeProjectAgentNames(agents: readonly AgentScopeConfig[]): AgentName[] {\n return agents.filter((a) => isActiveAt(a, \"project\")).map((a) => a.name);\n}\n\n/** Scope of each active (non-excluded) skill, keyed by id. */\nexport function activeSkillScopeMap(\n skills: readonly SkillConfig[] | undefined,\n): Map<SkillId, SkillScope> {\n return new Map((skills ?? []).filter((s) => !s.excluded).map((s) => [s.id, s.scope]));\n}\n\n/** Scope of each active (non-excluded) agent, keyed by name. */\nexport function activeAgentScopeMap(\n agents: readonly AgentScopeConfig[] | undefined,\n): Map<AgentName, SkillScope> {\n return new Map((agents ?? []).filter((a) => !a.excluded).map((a) => [a.name, a.scope]));\n}\n\n/**\n * Ids of skills that are effectively excluded: they have an excluded entry and no\n * active (non-excluded) entry with the same id rescues them. A skill with an\n * excluded global entry AND an active project entry is NOT effectively excluded.\n */\nexport function effectivelyExcludedSkillIds(skills: readonly SkillConfig[]): Set<SkillId> {\n const activeIds = new Set(skills.filter((s) => !s.excluded).map((s) => s.id));\n return new Set(skills.filter((s) => s.excluded && !activeIds.has(s.id)).map((s) => s.id));\n}\n","import { indexBy, uniqueBy } from \"remeda\";\n\nimport type { ProjectConfig, SkillId } from \"../../types\";\nimport type { AgentScopeConfig, SkillConfig } from \"../../types/config\";\nimport { loadProjectConfig } from \"./project-config\";\nimport { loadProjectSourceConfig } from \"./config\";\nimport { isGlobalTombstone, isProjectOwned, type ScopedEntry } from \"./scope-predicates\";\n\n/**\n * How authoritative `newConfig` is over entries absent from it (D-233 Scenario C):\n * - `\"all\"` — global-context EDIT at ~/: the wizard loaded the ENTIRE global config, so any\n * absent agent/skill was removed. Every existing entry is in scope.\n * - `\"owned\"` — project-context EDIT: the wizard loaded the full project roster and owns only\n * PROJECT-OWNED entries (project-scoped + the project's own global tombstones).\n * Inherited global-active entries are read-only and are always preserved.\n * - `undefined` — init / non-edit merges: additive union-preserve (never drop absent entries).\n */\nexport type AuthoritativeScope = \"all\" | \"owned\";\n\nexport type MergeContext = {\n projectDir: string;\n authoritativeScope?: AuthoritativeScope;\n /**\n * Skill ids the wizard could NOT resolve against the loaded source matrix this session\n * (D-233 Scenario C). An existing config entry whose id is in this set must always be preserved:\n * the wizard never offered a choice about it, so its absence from `newConfig` is not a\n * deselection and must not be dropped by `authoritativeScope`.\n */\n unresolvableSkillIds?: readonly SkillId[];\n};\n\nexport type MergeResult = {\n config: ProjectConfig;\n merged: boolean;\n existingConfigPath?: string;\n};\n\n/**\n * Compound identity key for an agent entry. Includes scope and the excluded\n * discriminator so that `{name, scope:\"project\"}` and `{name, scope:\"global\"}`\n * (and their tombstone variants) are treated as distinct entries rather than\n * collapsed onto `name` alone (D-221).\n */\nconst agentKey = (a: AgentScopeConfig): string =>\n `${a.name}:${a.scope}${a.excluded ? \":excluded\" : \"\"}`;\n\n/**\n * Compound identity key for a skill entry. Same shape as {@link agentKey}:\n * `id:scope` for actives, `id:scope:excluded` for tombstones. Prevents the\n * D-221 class of bugs where two distinct-scope entries collide onto `id`.\n */\nconst skillKey = (s: SkillConfig): string => `${s.id}:${s.scope}${s.excluded ? \":excluded\" : \"\"}`;\n\n/** Names of agents carrying a global tombstone — i.e. dual-scope entries the project owns. */\nfunction agentTombstoneNames(agents: AgentScopeConfig[]): Set<string> {\n return new Set(agents.filter(isGlobalTombstone).map((a) => a.name));\n}\n\n/** Ids of skills carrying a global tombstone — i.e. dual-scope entries the project owns. */\nfunction skillTombstoneIds(skills: SkillConfig[]): Set<string> {\n return new Set(skills.filter(isGlobalTombstone).map((s) => s.id));\n}\n\n/**\n * True when an existing entry is within the current edit session's authority, so its absence\n * from `newConfig` means a deliberate removal (drop) rather than an untouched entry (preserve).\n *\n * `\"all\"` (global edit): every entry is owned. `\"owned\"` (project edit): only project-scoped\n * entries and the project's own global tombstones — inherited global-active entries belong to\n * the global config and must never be dropped from a project edit.\n */\nfunction isWithinSessionAuthority(entry: ScopedEntry, scope: AuthoritativeScope): boolean {\n if (scope === \"all\") return true;\n return isProjectOwned(entry);\n}\n\n/**\n * Pure merge logic: existing values take precedence for identity fields;\n * agents and skills are merged so that `newConfig` is authoritative for every\n * `name`/`id` it references. Existing entries survive in-place when their\n * compound key matches a new entry (same name, scope, excluded). Existing\n * entries whose NAME/ID appears in new but whose compound key does NOT match\n * a new entry are dropped — this is how scope migrations (P→G, G→P) remove\n * stale rows and how P→G tombstone removal is honored. Existing entries whose\n * name/ID is absent from new are preserved unchanged — EXCEPT names/ids the\n * project owned as dual-scope this session (they carry a global tombstone in the\n * existing config): when new carries nothing for such a name, the user fully\n * deselected the dual-scope row, so both the lingering active project entry and\n * the stale tombstone are dropped together (D-233 Scenario B full-deselect).\n *\n * A final compound-key dedup (keeping first occurrence, which in our concat\n * order is the existing-derived or first-new entry) collapses any pre-existing\n * on-disk corruption rather than carrying multiplied duplicates forward.\n *\n * Dual-scope semantics (active at one scope + excluded tombstone at another)\n * are preserved because `newConfig.agents`/`newConfig.skills` carry BOTH\n * entries for the same name/id when that dual state is legitimate (wizard\n * output from `generateProjectConfigFromSkills` + `toggleAgentScope`).\n *\n * D-221 root cause (fixed here): the prior name-only key collapsed\n * distinct-scope entries, and the positional `.map()` over existing rewrote\n * every collision slot — multiplying pre-existing duplicates and failing to\n * drop stale rows on scope migration.\n *\n * `authoritativeScope` (D-233 Scenario C): a full `cc edit` pass presents the complete roster\n * the wizard could edit, so an entry within that authority which is absent from `newConfig` was\n * deliberately removed and must be dropped (even a plain active entry with no tombstone), rather\n * than union-preserved. `\"all\"` (global edit) covers every entry; `\"owned\"` (project edit) covers\n * only project-scoped entries and the project's own global tombstones — inherited global-active\n * entries are always preserved. `undefined` (init) keeps additive union-preserve.\n *\n * `unresolvableSkillIds` narrows the authoritative drop: a skill id the wizard could not resolve\n * from the loaded source this session is exempt and always preserved, because the wizard had no way\n * to offer a choice about it, so its absence is not a deselection (D-233 Scenario C data-loss guard).\n */\ntype MergeOptions = Pick<MergeContext, \"authoritativeScope\" | \"unresolvableSkillIds\">;\n\nexport function mergeConfigs(\n newConfig: ProjectConfig,\n existingConfig: ProjectConfig,\n options?: MergeOptions,\n): ProjectConfig {\n const merged = { ...newConfig };\n const unresolvableSkillIds = new Set(options?.unresolvableSkillIds ?? []);\n\n if (existingConfig.name) {\n merged.name = existingConfig.name;\n }\n\n if (existingConfig.description) {\n merged.description = existingConfig.description;\n }\n\n if (existingConfig.source && !newConfig.source) {\n merged.source = existingConfig.source;\n }\n\n if (existingConfig.agents && existingConfig.agents.length > 0) {\n const newAgentsByKey = indexBy(merged.agents, agentKey);\n const newAgentNames = new Set(merged.agents.map((a) => a.name));\n const existingKeys = new Set(existingConfig.agents.map(agentKey));\n // Names the project managed as dual-scope this session: a global tombstone in the\n // existing config marks an agent whose global install the project actively overrode.\n // When newConfig carries NO entry for such a name, the user fully deselected the\n // dual-scope row — both the lingering active project entry and the stale tombstone\n // must drop together, not be preserved (D-233 Scenario B full-deselect).\n const dualScopeAgentNames = agentTombstoneNames(existingConfig.agents);\n const updatedExisting = existingConfig.agents.flatMap((existing) => {\n const matching = newAgentsByKey[agentKey(existing)];\n if (matching) return [matching];\n // Name is actively managed by newConfig but this exact (scope, excluded)\n // slot is NOT in new → the wizard intentionally dropped this row\n // (scope migration or tombstone cleanup). Drop it.\n if (newAgentNames.has(existing.name)) return [];\n if (dualScopeAgentNames.has(existing.name)) return [];\n // Authoritative edit: an in-authority agent absent from newConfig (even a plain active\n // one with no tombstone) was deselected and must be dropped (D-233 Scenario C).\n if (\n options?.authoritativeScope &&\n isWithinSessionAuthority(existing, options.authoritativeScope)\n )\n return [];\n return [existing];\n });\n const addedAgents = merged.agents.filter((a) => !existingKeys.has(agentKey(a)));\n merged.agents = uniqueBy([...updatedExisting, ...addedAgents], agentKey);\n } else {\n merged.agents = uniqueBy(merged.agents, agentKey);\n }\n\n if (existingConfig.skills && existingConfig.skills.length > 0) {\n const newSkillsByKey = indexBy(merged.skills, skillKey);\n const newSkillIds = new Set(merged.skills.map((s) => s.id));\n const existingKeys = new Set(existingConfig.skills.map(skillKey));\n // Skill-side twin of dualScopeAgentNames — see the agent branch above (D-233).\n const dualScopeSkillIds = skillTombstoneIds(existingConfig.skills);\n const updatedExisting = existingConfig.skills.flatMap((existing) => {\n const matching = newSkillsByKey[skillKey(existing)];\n if (matching) return [matching];\n if (newSkillIds.has(existing.id)) return [];\n if (dualScopeSkillIds.has(existing.id)) return [];\n // Skill-side twin — see the agent branch above (D-233 Scenario C).\n // A skill the wizard could not resolve from the loaded source this session is exempt from\n // the authoritative drop: its absence from newConfig is a resolution gap, not a deselection,\n // so it must always be preserved (D-233 Scenario C data-loss guard).\n if (\n options?.authoritativeScope &&\n isWithinSessionAuthority(existing, options.authoritativeScope) &&\n !unresolvableSkillIds.has(existing.id)\n )\n return [];\n return [existing];\n });\n const addedSkills = merged.skills.filter((s) => !existingKeys.has(skillKey(s)));\n merged.skills = uniqueBy([...updatedExisting, ...addedSkills], skillKey);\n } else {\n merged.skills = uniqueBy(merged.skills, skillKey);\n }\n\n // Stack is the pure output of the mutator — trust newConfig.stack whenever it\n // is defined. Only fall back to existingConfig.stack when the new config has\n // none (preserves existing during non-stack-touching operations).\n if (newConfig.stack === undefined && existingConfig.stack) {\n merged.stack = existingConfig.stack;\n }\n\n if (existingConfig.author) {\n merged.author = existingConfig.author;\n }\n\n if (existingConfig.agentsSource) {\n merged.agentsSource = existingConfig.agentsSource;\n }\n\n if (existingConfig.marketplace) {\n merged.marketplace = existingConfig.marketplace;\n }\n\n // Preserve the registered project paths from the existing (global) config — the wizard\n // result never carries them, and losing them silently disables propagation of global\n // changes to registered projects (D-233 Scenario C: the tombstone reconcile never runs).\n if (existingConfig.projects && !newConfig.projects) {\n merged.projects = existingConfig.projects;\n }\n\n return merged;\n}\n\nexport async function mergeWithExistingConfig(\n newConfig: ProjectConfig,\n context: MergeContext,\n): Promise<MergeResult> {\n const existingFullConfig = await loadProjectConfig(context.projectDir);\n if (existingFullConfig) {\n // A full `cc edit` pass loads the complete roster, so newConfig is authoritative over the\n // entries it owns — every entry for a global edit (`\"all\"`), or project-owned entries for a\n // project edit (`\"owned\"`). Absent owned entries were deselected and are dropped rather than\n // union-preserved (D-233 Scenario C). Init leaves the scope undefined (additive union).\n const config = mergeConfigs(newConfig, existingFullConfig.config, {\n authoritativeScope: context.authoritativeScope,\n unresolvableSkillIds: context.unresolvableSkillIds,\n });\n\n return {\n config,\n merged: true,\n existingConfigPath: existingFullConfig.configPath,\n };\n }\n\n // No existing full config, try simple project source config for author/agentsSource\n const localConfig = { ...newConfig };\n const existingProjectConfig = await loadProjectSourceConfig(context.projectDir);\n if (existingProjectConfig?.author) {\n localConfig.author = existingProjectConfig.author;\n }\n if (existingProjectConfig?.agentsSource) {\n localConfig.agentsSource = existingProjectConfig.agentsSource;\n }\n\n return { config: localConfig, merged: false };\n}\n","import os from \"os\";\nimport path from \"path\";\nimport { fileExists } from \"../../utils/fs\";\nimport { verbose, warn } from \"../../utils/logger\";\nimport { getErrorMessage } from \"../../utils/errors\";\nimport type { ProjectConfig, ValidationResult } from \"../../types\";\nimport { normalizeStackRecord } from \"../stacks/stacks-loader\";\nimport { projectConfigLoaderSchema } from \"../schemas\";\nimport { formatZodErrors } from \"../schema-validator\";\nimport { getProjectConfigPath } from \"../installation/install-base-dir\";\nimport { isHomeDirectory } from \"../installation/is-home-directory\";\nimport { loadConfig } from \"./config-loader\";\n\nexport type LoadedProjectConfig = {\n config: ProjectConfig;\n configPath: string;\n};\n\n/**\n * Thrown when a project config file exists on disk but cannot be loaded into a\n * usable config — a syntax/evaluation error, no default export, or a shape the\n * loader schema rejects. This is deliberately distinct from a MISSING file\n * (which is a legitimate `null`): a corrupt config is an error that callers must\n * surface, never swallow into `null`. Collapsing both into `null` let a broken\n * install pass as absent (e.g. `compile` treating it as config-less and\n * resurrecting every built-in agent).\n */\nexport class ConfigLoadError extends Error {\n constructor(\n readonly configPath: string,\n readonly reason: string,\n ) {\n super(`Config at '${configPath}' could not be loaded: ${reason}`);\n this.name = \"ConfigLoadError\";\n }\n}\n\n/**\n * Load project config from a specific directory only (no global fallback).\n *\n * Returns `null` only when the config file does not exist. When the file exists\n * but cannot be parsed into a usable config, throws {@link ConfigLoadError} —\n * the caller decides how to report it.\n */\nexport async function loadProjectConfigFromDir(\n projectDir: string,\n): Promise<LoadedProjectConfig | null> {\n const configPath = getProjectConfigPath(projectDir);\n\n if (!(await fileExists(configPath))) {\n verbose(`Project config not found at ${configPath}`);\n return null;\n }\n\n // The file exists. From here, any failure to produce a usable config means the\n // file is corrupt — surface it as ConfigLoadError rather than returning `null`,\n // which is indistinguishable from \"missing\".\n let raw: unknown;\n try {\n // Load raw object and validate with Zod (lenient schema accepts custom values via z.string() casts)\n raw = await loadConfig<ProjectConfig>(configPath);\n } catch (error) {\n throw new ConfigLoadError(configPath, getErrorMessage(error));\n }\n\n if (!raw || typeof raw !== \"object\") {\n throw new ConfigLoadError(configPath, \"the file has no valid default export\");\n }\n\n const result = projectConfigLoaderSchema.safeParse(raw);\n if (!result.success) {\n throw new ConfigLoadError(configPath, formatZodErrors(result.error).join(\"; \"));\n }\n\n // Normalize the loose stack values (bare strings, objects, arrays) BEFORE claiming\n // ProjectConfig, so the boundary cast below is the only one on this path.\n const parsed = result.data;\n const normalizedStack = parsed.stack ? normalizeStackRecord(parsed.stack) : undefined;\n // Boundary cast: loader schema is lenient (optional name, loose strings);\n // validateProjectConfig enforces the strict shape after load\n const config = {\n ...parsed,\n ...(normalizedStack && { stack: normalizedStack }),\n } as ProjectConfig;\n\n if (!config.name) {\n warn(\n `Project config at '${configPath}' is missing required 'name' field — defaulting to directory name`,\n );\n config.name = path.basename(projectDir);\n }\n if (!config.skills) {\n warn(`Project config at '${configPath}' is missing 'skills' array — defaulting to empty`);\n config.skills = [];\n }\n\n verbose(`Loaded project config from ${configPath}`);\n return {\n config,\n configPath,\n };\n}\n\n/**\n * Load project config with global fallback.\n * Checks the given projectDir first, then falls back to the home directory.\n */\nexport async function loadProjectConfig(projectDir: string): Promise<LoadedProjectConfig | null> {\n const projectResult = await loadProjectConfigFromDir(projectDir);\n if (projectResult) return projectResult;\n\n // Global fallback: try home directory\n const homeDir = os.homedir();\n if (!isHomeDirectory(projectDir)) {\n return loadProjectConfigFromDir(homeDir);\n }\n\n return null;\n}\n\n/**\n * Validates a loaded config value. Shape validity is defined by\n * `projectConfigLoaderSchema` (the single definition); on top of the schema's\n * lenient shape, a usable project config additionally requires `name` and\n * `agents` to be present.\n */\nexport function validateProjectConfig(config: unknown): ValidationResult {\n const result = projectConfigLoaderSchema.safeParse(config);\n if (!result.success) {\n return { valid: false, errors: formatZodErrors(result.error), warnings: [] };\n }\n\n const errors = [\n ...(result.data.name ? [] : [\"name is required and must be a string\"]),\n ...(result.data.agents ? [] : [\"agents is required and must be an array\"]),\n ];\n return { valid: errors.length === 0, errors, warnings: [] };\n}\n","import path from \"path\";\nimport { mapValues, pipe, flatMap, unique } from \"remeda\";\nimport { getErrorMessage } from \"../../utils/errors\";\nimport { verbose, warn } from \"../../utils/logger\";\nimport { hasSkill } from \"../matrix/matrix-provider\";\nimport type {\n AgentName,\n SkillAssignment,\n SkillId,\n SkillReference,\n Stack,\n StackAgentConfig,\n Category,\n} from \"../../types\";\nimport { stacksConfigSchema } from \"../schemas\";\nimport { typedEntries, typedKeys } from \"../../utils/typed-object\";\nimport { isSkillAssignment } from \"../../utils/type-guards\";\nimport { STACKS_FILE_PATH } from \"../../consts\";\nimport { loadConfig } from \"../configuration/config-loader\";\nimport { defaultStacks } from \"../configuration/default-stacks\";\n\nconst stacksCache = new Map<string, Stack[]>();\n\n/**\n * Normalizes a raw agent config (from Zod-parsed config) to StackAgentConfig.\n * Converts bare strings to `{ id, preloaded: false }` and wraps single values in arrays.\n * Used by both loadStacks() and loadProjectConfig() to handle all 3 config formats:\n * 1. bare string: `framework: \"web-framework-react\"`\n * 2. single object: `framework: { id: \"web-framework-react\", preloaded: true }`\n * 3. array: `methodology: [{ id: ..., preloaded: true }, { id: ... }]`\n */\nexport function normalizeAgentConfig(agentConfig: Record<string, unknown>): StackAgentConfig {\n // Boundary casts: Zod-parsed config has loose types (bare strings, objects, arrays)\n // that are normalized to typed SkillAssignment[] values\n return mapValues(agentConfig, (value) => {\n const items = Array.isArray(value) ? value : [value];\n return items.map((item): SkillAssignment => {\n if (typeof item === \"string\") return { id: item as SkillId, preloaded: false };\n if (isSkillAssignment(item)) return item;\n warn(`Malformed skill assignment in stack data: ${JSON.stringify(item)}`);\n return item as SkillAssignment;\n });\n }) as StackAgentConfig;\n}\n\n/**\n * Normalizes a raw stack record (agent -> raw category config) to the typed form.\n * Applies normalizeAgentConfig to each agent entry.\n */\nexport function normalizeStackRecord(\n rawStack: Record<string, Record<string, unknown>>,\n): Record<string, StackAgentConfig> {\n return mapValues(rawStack, (agentConfig) => normalizeAgentConfig(agentConfig));\n}\n\nexport async function loadStacks(configDir: string, stacksFile?: string): Promise<Stack[]> {\n const resolvedStacksFile = stacksFile ?? STACKS_FILE_PATH;\n const cacheKey = `${configDir}:${resolvedStacksFile}`;\n const cached = stacksCache.get(cacheKey);\n if (cached) return cached;\n\n const stacksPath = path.join(configDir, resolvedStacksFile);\n\n try {\n const raw = await loadConfig(stacksPath, stacksConfigSchema);\n\n if (raw == null) {\n verbose(`No stacks file found at ${stacksPath}`);\n return [];\n }\n\n // Normalize: all values to SkillAssignment[] so StackAgentConfig is always SkillAssignment[]\n // Boundary casts: Zod stacksConfigSchema outputs loose Record types;\n // narrowing to Stack[\"agents\"] after normalization guarantees SkillAssignment[] values\n const stacks: Stack[] = raw.stacks.map((stack) => ({\n ...stack,\n agents: mapValues(\n stack.agents as Partial<Record<AgentName, Record<string, unknown>>>,\n (agentConfig) => normalizeAgentConfig(agentConfig as Record<string, unknown>),\n ) as Stack[\"agents\"],\n }));\n\n stacksCache.set(cacheKey, stacks);\n verbose(`Loaded ${stacks.length} stacks from ${stacksPath}`);\n\n return stacks;\n } catch (error) {\n const errorMessage = getErrorMessage(error);\n throw new Error(`Failed to load stacks from '${stacksPath}': ${errorMessage}`, {\n cause: error,\n });\n }\n}\n\nexport async function loadStackById(stackId: string, configDir: string): Promise<Stack | null> {\n const stacks = await loadStacks(configDir);\n const stack = stacks.find((s) => s.id === stackId);\n\n if (stack) {\n verbose(`Found stack: ${stack.name} (${stackId})`);\n return stack;\n }\n\n // Fall back to CLI's built-in default stacks\n const defaultStack = defaultStacks.find((s) => s.id === stackId) ?? null;\n if (defaultStack) {\n verbose(`Found default stack: ${defaultStack.name} (${stackId})`);\n } else {\n verbose(`Stack '${stackId}' not found in source or defaults`);\n }\n return defaultStack;\n}\n\n// Converts a StackAgentConfig (category -> SkillAssignment[]) to an array of SkillReferences.\n// Values are already normalized to SkillAssignment[] by loadStacks().\nexport function resolveAgentConfigToSkills(agentConfig: StackAgentConfig): SkillReference[] {\n return typedEntries<Category, SkillAssignment[]>(agentConfig).flatMap(([category, assignments]) =>\n (assignments ?? []).map((assignment): SkillReference => {\n if (!hasSkill(assignment.id)) {\n warn(\n `Skill '${assignment.id}' for category '${category}' not found in matrix. It may be a custom or local skill.`,\n { suppressInTest: true },\n );\n }\n return {\n id: assignment.id,\n usage: `when working with ${category}`,\n preloaded: assignment.preloaded ?? false,\n };\n }),\n );\n}\n\n/** Extracts all unique skill IDs from a stack config (agent -> category -> SkillAssignment[]). */\nexport function getStackSkillIds(stack: Record<string, StackAgentConfig>): SkillId[] {\n return pipe(\n Object.values(stack),\n flatMap(resolveAgentConfigToSkills),\n (refs) => refs.map((r) => r.id),\n unique(),\n );\n}\n\nexport function resolveStackSkills(stack: Stack): Record<string, SkillReference[]> {\n const result = mapValues(stack.agents, (agentConfig) =>\n agentConfig ? resolveAgentConfigToSkills(agentConfig) : [],\n );\n\n verbose(\n `Resolved skills for ${typedKeys<AgentName>(result).length} agents in stack '${stack.id}'`,\n );\n\n return result;\n}\n","import {\n CATEGORIES,\n DOMAINS,\n AGENT_NAMES,\n SKILL_IDS,\n SKILL_SLUGS,\n} from \"../types/generated/source-types\";\nimport type {\n Category,\n Domain,\n AgentName,\n SkillId,\n SkillSlug,\n} from \"../types/generated/source-types\";\nimport type { CategoryPath, SkillAssignment } from \"../types/skills\";\nimport { LOCAL_PSEUDO_CATEGORY } from \"../consts\";\n\n/** Narrows unknown parse output to a plain object record (rejects arrays and primitives). */\nexport function isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\n/** Runtime check that a string is a valid Category value from the generated union */\nexport function isCategory(value: string): value is Category {\n return (CATEGORIES as readonly string[]).includes(value);\n}\n\n/** Runtime check that a string is a valid Domain value from the generated union */\nexport function isDomain(value: string): value is Domain {\n return (DOMAINS as readonly string[]).includes(value);\n}\n\n/** Runtime check that a string is a valid AgentName value from the generated union */\nexport function isAgentName(value: string): value is AgentName {\n return (AGENT_NAMES as readonly string[]).includes(value);\n}\n\n/** Runtime check that a string is a valid CategoryPath (Category | \"local\") */\nexport function isCategoryPath(value: string): value is CategoryPath {\n return value === LOCAL_PSEUDO_CATEGORY || isCategory(value);\n}\n\n/** Runtime check that a string is a valid SkillId from the generated union */\nexport function isSkillId(value: string): value is SkillId {\n return (SKILL_IDS as readonly string[]).includes(value);\n}\n\n/** Runtime check that a string is a valid SkillSlug from the generated union */\nexport function isSkillSlug(value: string): value is SkillSlug {\n return (SKILL_SLUGS as readonly string[]).includes(value);\n}\n\n/**\n * Structural check for a SkillAssignment object (`{ id, preloaded? }`).\n * The id's SkillId-ness is structural, not union-checked: assignments flow from\n * runtime sources whose skills may not be in the generated union.\n */\nexport function isSkillAssignment(value: unknown): value is SkillAssignment {\n if (typeof value !== \"object\" || value === null) return false;\n // Boundary cast: probing an unknown object's field inside the guard\n return typeof (value as { id?: unknown }).id === \"string\";\n}\n","import os from \"os\";\nimport path from \"path\";\nimport type { ProjectConfig, SkillId } from \"../../types\";\nimport type { SkillConfig, SourceEntry } from \"../../types/config\";\nimport { CLAUDE_SRC_DIR, CLI_INVOKE_COMMAND, STANDARD_FILES } from \"../../consts\";\nimport { ensureDir, writeFile } from \"../../utils/fs\";\nimport { verbose } from \"../../utils/logger\";\nimport { isHomeDirectory } from \"../installation/is-home-directory\";\nimport { getProjectConfigPath } from \"../installation/install-base-dir\";\nimport { loadProjectConfigFromDir } from \"../configuration/project-config\";\nimport { normalizeStackRecord } from \"../stacks/stacks-loader\";\nimport { isActiveAt } from \"../configuration/scope-predicates\";\nimport { splitConfigByScope } from \"../configuration/config-generator\";\nimport { generateConfigSource } from \"../configuration/config-writer\";\nimport {\n regenerateConfigTypes,\n type ConfigTypesBackgroundData,\n type ConfigTypesExtras,\n} from \"../configuration/config-types-writer\";\nimport {\n classifyGlobalChange,\n consequenceTier,\n tierPropagates,\n tierRegeneratesTypes,\n NO_CHANGES,\n type GlobalChangeSet,\n} from \"./classify.js\";\nimport { resolveGateDeps, type GateDeps, type LoadedGateDeps } from \"./deps.js\";\nimport { GlobalPairWriteViolation, withGateToken } from \"./gate-token.js\";\nimport {\n ensureBlankPair as ensureBlankPairInternal,\n writeGlobalConfigHalf,\n writeGlobalPair,\n writeGlobalTypesHalf,\n writeGlobalTypesHalfFromData,\n} from \"./pair-writer.js\";\nimport {\n buildConfigTypesBackgroundData,\n buildProjectTypesExtras,\n mergeGlobalConfigs,\n normalizeProjectPath,\n propagateGlobalChangesToProjects,\n pruneGlobalEntriesFromRegisteredProjects,\n reconcileProjectSplitAgainstGlobal,\n resolveEffectiveGlobalConfig,\n writeProjectConfigPair,\n type PropagationResult,\n} from \"./propagate.js\";\nimport { NOTHING_RECOMPILED, recompilePropagated } from \"./recompile.js\";\nimport type { PropagatedRecompileSummary } from \"../operations/project/recompile-project-agents.js\";\n\nexport type { GateDeps } from \"./deps.js\";\nexport type { ConsequenceTier, GlobalChangeSet } from \"./classify.js\";\nexport { GlobalPairWriteViolation } from \"./gate-token.js\";\n\n/**\n * What one gated write did, for the caller to render.\n *\n * A write that propagates recompiles the propagated projects' agents itself:\n * both audited gaps in the previous contract (a project-context source\n * migration, a global uninstall) were instances of a caller forgetting to. A\n * report the caller may only log cannot go stale the same way, and per-project\n * failure isolation already lives in `recompilePropagatedProjectAgents`, so\n * internalizing the recompile adds no new failure mode.\n */\nexport type GateReport = {\n /** True when either half of the global pair was actually rewritten. */\n globalWritten: boolean;\n changes: GlobalChangeSet;\n propagated: PropagationResult;\n recompile: PropagatedRecompileSummary;\n};\n\n/**\n * The gate's public entry points are the ONLY code that mints the pair-write\n * privilege, and each one holds it across its whole consequence flow rather than\n * around the individual write (D-309).\n *\n * `pair-writer.ts` used to open the token inside each of its own functions, which\n * meant reaching that module by any route — a dynamic import, a re-export — came\n * with the privilege attached, and the runtime tripwire in `utils/fs.ts` had\n * nothing left to refuse. Moving the mint here inverts that: the private writers\n * REQUIRE a token they cannot produce, so authorization is a property of how the\n * write was ENTERED, which is exactly what the gate is meant to guarantee.\n *\n * The window is wider than the write itself — propagation and the recompile run\n * inside it too. That is accepted: everything in the window is the gate's own\n * code carrying out consequences the same entry already owes.\n *\n * Every entry below that writes or drives a write opens the token with\n * `withGateToken`, including `propagateGlobalRemoval`, which today reaches only\n * project pairs — the rule is \"a gate entry holds the privilege for its flow\",\n * not \"the ones whose current implementation happens to need it\".\n *\n * The two exceptions are `writeProjectPartial` and\n * `writeMarketplaceScaffoldConfig`. Both refuse the home directory as their first\n * act and then write a PROJECT's or a MARKETPLACE's own config, which the\n * tripwire never guards; handing them the global-pair privilege would only blunt\n * the refusal they exist to make.\n */\n\n/** A write whose classification obliged nothing beyond the global pair. */\nconst NOTHING_PROPAGATED: PropagationResult = { updated: [], skipped: [] };\n\nfunction report(\n globalWritten: boolean,\n changes: GlobalChangeSet,\n propagated: PropagationResult = NOTHING_PROPAGATED,\n recompile: PropagatedRecompileSummary = NOTHING_RECOMPILED,\n): GateReport {\n return { globalWritten, changes, propagated, recompile };\n}\n\n/**\n * Carries out a classified global change's consequences: fan the change out to\n * every registered project, then recompile the ones it rewrote.\n *\n * `currentProjectDir` is excluded from the fan-out — its own pair is written by\n * the call that triggered this, and its agents are compiled by the command.\n */\nasync function applyConsequences(\n globalConfig: ProjectConfig,\n changes: GlobalChangeSet,\n deps: LoadedGateDeps,\n currentProjectDir?: string,\n): Promise<{ propagated: PropagationResult; recompile: PropagatedRecompileSummary }> {\n const tier = consequenceTier(changes);\n if (!tierPropagates(tier) || !globalConfig.projects?.length) {\n return { propagated: NOTHING_PROPAGATED, recompile: NOTHING_RECOMPILED };\n }\n\n const propagated = await propagateGlobalChangesToProjects(\n globalConfig,\n deps.matrix,\n deps.agents,\n currentProjectDir,\n { regenerateTypes: tierRegeneratesTypes(tier) },\n );\n if (propagated.updated.length > 0) {\n verbose(`Propagated global changes to ${propagated.updated.length} project(s)`);\n }\n\n const recompile = tierRegeneratesTypes(tier)\n ? await recompilePropagated(propagated.updated)\n : NOTHING_RECOMPILED;\n\n return { propagated, recompile };\n}\n\n/**\n * Loaders for a caller that holds no matrix of its own. Nothing is fetched\n * unless classification proves the write has consequences that read it, so a\n * registration-only mutation stays offline.\n *\n * `matrixOnly` + `skipExtraSources` are the offline policy the other config\n * readers already use: extra-source loading only annotates wizard UI tagging and\n * never changes the emitted config or types.\n */\nexport function lazyGateDeps(projectDir: string): GateDeps {\n return {\n loadMatrix: async () => {\n const { loadSkillsMatrixFromSource } = await import(\"../loading/source-loader.js\");\n const { matrix } = await loadSkillsMatrixFromSource({\n projectDir,\n skipExtraSources: true,\n matrixOnly: true,\n });\n return matrix;\n },\n loadAgents: async () => {\n const { loadAgentDefs } = await import(\"../operations/project/load-agent-defs.js\");\n return (await loadAgentDefs({ projectDir })).agents;\n },\n };\n}\n\nexport type WizardWriteArgs = {\n finalConfig: ProjectConfig;\n matrix: LoadedGateDeps[\"matrix\"];\n agents: LoadedGateDeps[\"agents\"];\n projectDir: string;\n projectConfigPath: string;\n projectInstallationExists: boolean;\n};\n\n/**\n * Writes config.ts and config-types.ts split by scope.\n * When installing into a project directory:\n * - Global config/types go to ~/.claude-src/\n * - Project config/types go to {projectDir}/.claude-src/ (with import from global)\n * When installing from home directory, writes a single standalone config.\n */\nexport async function writeScopedFromWizard(args: WizardWriteArgs): Promise<GateReport> {\n return withGateToken(async () => {\n const { finalConfig, matrix, agents, projectDir, projectConfigPath } = args;\n // Use os.homedir() at runtime (not GLOBAL_INSTALL_ROOT constant) so the path\n // agrees with getGlobalConfigImportPath() which also calls os.homedir() at runtime\n const homeDir = os.homedir();\n const deps: LoadedGateDeps = { matrix, agents };\n\n if (!isHomeDirectory(projectDir)) {\n return writeFromProjectContext(args, homeDir, deps);\n }\n\n // Installing from ~/ — write directly to global config (no import preamble)\n const priorGlobal = await loadProjectConfigFromDir(homeDir);\n const changes = classifyGlobalChange(priorGlobal?.config, finalConfig);\n const globalWritten = await writeGlobalPair(finalConfig, projectConfigPath, matrix, agents);\n\n const { propagated, recompile } = await applyConsequences(finalConfig, changes, deps);\n return report(globalWritten, changes, propagated, recompile);\n });\n}\n\nasync function writeFromProjectContext(\n args: WizardWriteArgs,\n homeDir: string,\n deps: LoadedGateDeps,\n): Promise<GateReport> {\n const { finalConfig, matrix, agents, projectDir, projectConfigPath } = args;\n\n // Installing from project — split by scope for project config generation.\n const { global: globalConfig, project: projectSplitConfig } = splitConfigByScope(finalConfig);\n const globalConfigPath = getProjectConfigPath(homeDir);\n\n // Merge new global-scoped items into the existing global config.\n // - Existing items are preserved (never removed from global during project init)\n // - New global items are added\n // - If no existing global config, write the full global split\n const existingGlobal = await loadProjectConfigFromDir(homeDir);\n const effective = await resolveEffectiveGlobalConfig(\n globalConfig,\n existingGlobal?.config,\n projectDir,\n );\n const effectiveGlobalConfig = effective.config;\n\n const changes = classifyGlobalChange(existingGlobal?.config, effectiveGlobalConfig);\n\n let globalWritten = false;\n if (effective.changed) {\n await ensureDir(path.dirname(globalConfigPath));\n globalWritten = await writeGlobalPair(effectiveGlobalConfig, globalConfigPath, matrix, agents);\n verbose(`Updated global config at ${globalConfigPath}`);\n } else {\n verbose(\"Global config unchanged, skipping write\");\n }\n\n const { propagated, recompile } = await applyConsequences(\n effectiveGlobalConfig,\n changes,\n deps,\n projectDir,\n );\n\n // Reconcile the project's own entries against the global config this write inlines.\n // Without it this branch hands the raw split straight to the inlining writer, so a\n // skill/agent the project owns at project scope AND a colliding live global install\n // both land as active entries in the same project config.\n const reconciledProjectConfig = reconcileProjectSplitAgainstGlobal(\n projectSplitConfig,\n effectiveGlobalConfig,\n matrix,\n );\n\n // Write project config if the project installation already exists OR if there are project-scoped items.\n // Skip only when no existing project installation AND no project-scoped items — creating an empty\n // project config with just `import globalConfig` and `{ ...globalConfig }` is pointless.\n const hasProjectItems =\n reconciledProjectConfig.skills.length > 0 || reconciledProjectConfig.agents.length > 0;\n\n if (args.projectInstallationExists || hasProjectItems) {\n await ensureDir(path.dirname(projectConfigPath));\n await writeProjectConfigPair(\n projectDir,\n reconciledProjectConfig,\n effectiveGlobalConfig,\n matrix,\n agents,\n );\n verbose(`Updated project config at ${projectConfigPath}`);\n } else {\n verbose(\n \"Skipped project config — no existing project installation and no project-scoped items\",\n );\n }\n\n return report(globalWritten, changes, propagated, recompile);\n}\n\n/**\n * Regenerates a single scope's config-types.ts from its persisted config,\n * matching the wizard write path exactly (D-228 writer selection):\n * - global scope (home dir): standalone unions narrowed to the config's entries\n * - project scope: import-and-extend form (falls back to standalone when no\n * global config-types.ts exists)\n *\n * Writes no config half at either scope: the config on disk is the input.\n * Returns whether a file was actually rewritten (always false at project scope,\n * where the writer does not report).\n */\nexport async function writeScopeConfigTypes(\n projectDir: string,\n config: ProjectConfig,\n deps: LoadedGateDeps,\n extras?: ConfigTypesExtras,\n): Promise<boolean> {\n return withGateToken(async () => {\n if (isHomeDirectory(projectDir)) {\n return writeGlobalTypesHalf(\n config,\n getProjectConfigPath(projectDir),\n deps.matrix,\n deps.agents,\n extras,\n );\n }\n\n await regenerateConfigTypes(\n projectDir,\n Promise.resolve(buildConfigTypesBackgroundData(deps.matrix, deps.agents)),\n extras ?? buildProjectTypesExtras(config, deps.matrix),\n );\n return false;\n });\n}\n\n/**\n * Regenerates a scope's config-types.ts from the config already on disk, which\n * is the truth and is never rewritten — the documented hand-edit workflow is\n * \"edit config.ts, then compile\", so the file the user edited must survive it.\n *\n * At the home directory the types are the standalone unions narrowed to that\n * config, and the fan-out is UNCONDITIONAL: a hand edit leaves no prior state to\n * diff against, so there is nothing to classify and the only safe assumption is\n * that every registered project's inlined copy is stale. At project and\n * marketplace directories the import-and-extend writer applies and nothing is\n * propagated — a project config is nobody else's input.\n */\nexport async function reconcileTypesFromDisk(\n projectDir: string,\n config: ProjectConfig,\n deps: LoadedGateDeps,\n options?: { extras?: ConfigTypesExtras; currentProjectDir?: string },\n): Promise<GateReport> {\n return withGateToken(async () => {\n const changes = classifyGlobalChange(undefined, config);\n const globalWritten = await writeScopeConfigTypes(projectDir, config, deps, options?.extras);\n\n if (!isHomeDirectory(projectDir)) return report(false, changes);\n if (!config.projects?.length) return report(globalWritten, changes);\n\n const propagated = await propagateGlobalChangesToProjects(\n config,\n deps.matrix,\n deps.agents,\n options?.currentProjectDir,\n );\n if (propagated.updated.length > 0) {\n verbose(`Propagated global changes to ${propagated.updated.length} project(s)`);\n }\n const recompile = await recompilePropagated(propagated.updated);\n\n return report(globalWritten, changes, propagated, recompile);\n });\n}\n\n/**\n * Regenerates a scope's `config-types.ts` after `new skill` / `new agent` /\n * `new marketplace` scaffolded an entity whose literal the unions must carry.\n *\n * Fronts the raw types writer because the home directory is reachable at those\n * call sites — all three run at `process.cwd()` — and the raw writer refuses it.\n * Here the write goes through the pair writer holding the gate token instead.\n *\n * No fan-out: a scaffolded entity widens the types unions only. The global\n * `config.ts` is untouched, so no registered project's inlined copy of it went\n * stale and there is nothing to propagate.\n */\nexport async function writeScaffoldedEntityTypes(\n projectDir: string,\n backgroundData: Promise<ConfigTypesBackgroundData>,\n extras?: ConfigTypesExtras,\n): Promise<void> {\n await withGateToken(async () => {\n if (!isHomeDirectory(projectDir)) {\n await regenerateConfigTypes(projectDir, backgroundData, extras);\n return;\n }\n\n const data = await backgroundData;\n const loaded = await loadProjectConfigFromDir(projectDir);\n await writeGlobalTypesHalfFromData(\n getProjectConfigPath(projectDir),\n data,\n loaded?.config,\n extras,\n );\n });\n}\n\n/**\n * The transforms the gate will apply to the global config on a caller's behalf.\n *\n * A closed union rather than a caller-supplied function: every variant is\n * analysable and testable on its own, and no caller-authored transform runs\n * inside the only code allowed to write the pair.\n */\nexport type GlobalMutation =\n | { kind: \"migrate-skill-sources\"; sources: ReadonlyMap<SkillId, string> }\n | { kind: \"deregister-project\"; projectDir: string }\n | { kind: \"set-source\"; source: string; fallbackName: string }\n | { kind: \"add-source\"; entry: SourceEntry }\n | { kind: \"remove-source\"; name: string };\n\n/** The migrated `source` for an active-global entry, or the entry unchanged. */\nfunction withMigratedSource(\n skill: SkillConfig,\n migratedSources: ReadonlyMap<SkillId, string>,\n): SkillConfig {\n if (!isActiveAt(skill, \"global\")) return skill;\n const source = migratedSources.get(skill.id);\n if (source === undefined || source === skill.source) return skill;\n return { ...skill, source };\n}\n\n/**\n * Rewrites `source` on exactly the active-global entries listed in `migratedSources`,\n * returning every other entry — including global entries this session did not migrate —\n * identical by reference.\n */\nexport function applyMigratedGlobalSources(\n globalSkills: SkillConfig[],\n migratedSources: ReadonlyMap<SkillId, string>,\n): { skills: SkillConfig[]; changed: boolean } {\n const skills = globalSkills.map((skill) => withMigratedSource(skill, migratedSources));\n return { skills, changed: skills.some((skill, index) => skill !== globalSkills[index]) };\n}\n\n/**\n * The config a partial write commits: the scalars and arrays already on disk,\n * with the required fields filled. Mirrors what the partial writer has always\n * defaulted, so a scalar mutation cannot silently empty an install.\n */\nfunction fillRequiredFields(\n partial: Partial<ProjectConfig>,\n fallbackName: string | undefined,\n): ProjectConfig {\n const name = partial.name ?? fallbackName;\n if (!name) {\n throw new Error(\n `Cannot write config: no project config found. Run \\`${CLI_INVOKE_COMMAND} init\\` first.`,\n );\n }\n return { ...partial, name, skills: partial.skills ?? [], agents: partial.agents ?? [] };\n}\n\n/** Applies a mutation to the config on disk, or null when it is a no-op. */\nfunction applyMutation(\n mutation: GlobalMutation,\n current: Partial<ProjectConfig>,\n): Partial<ProjectConfig> | null {\n switch (mutation.kind) {\n case \"migrate-skill-sources\": {\n const { skills, changed } = applyMigratedGlobalSources(\n current.skills ?? [],\n mutation.sources,\n );\n return changed ? { ...current, skills } : null;\n }\n case \"deregister-project\": {\n const projects = current.projects ?? [];\n if (projects.length === 0) return null;\n const normalized = normalizeProjectPath(mutation.projectDir);\n const filtered = projects.filter((p) => p !== normalized);\n return filtered.length === projects.length ? null : { ...current, projects: filtered };\n }\n case \"set-source\":\n return { ...current, source: mutation.source };\n case \"add-source\": {\n const sources = current.sources ?? [];\n if (sources.some((s) => s.name === mutation.entry.name)) {\n throw new Error(`Source \"${mutation.entry.name}\" already exists`);\n }\n return { ...current, sources: [...sources, mutation.entry] };\n }\n case \"remove-source\": {\n const sources = current.sources ?? [];\n const filtered = sources.filter((s) => s.name !== mutation.name);\n if (filtered.length === sources.length)\n throw new Error(`Source \"${mutation.name}\" not found`);\n return { ...current, sources: filtered };\n }\n default: {\n const _exhaustive: never = mutation;\n return _exhaustive;\n }\n }\n}\n\n/** The name a mutation invents when the global config has none yet. */\nfunction fallbackNameFor(mutation: GlobalMutation): string | undefined {\n return mutation.kind === \"set-source\" ? mutation.fallbackName : undefined;\n}\n\n/**\n * Applies a typed transform to the global config and carries out whatever its\n * classification obliges. No variant is exempt from classification by\n * construction: a source change propagates because project configs inline the\n * global scalars, and a deregistration does not because nothing inlines the\n * registration list.\n */\nexport async function mutateGlobal(mutation: GlobalMutation, deps: GateDeps): Promise<GateReport> {\n return withGateToken(async () => {\n const homeDir = os.homedir();\n // The full loader, not the scalar one: it normalizes every stack assignment\n // back to `SkillAssignment[]`. The writer compacts an exclusive category to its\n // bare value on the way out, and re-emitting that bare form without\n // normalization drops the category — so a scalar mutation would silently strip\n // every exclusive category from the global stack.\n const loadedGlobal = await loadProjectConfigFromDir(homeDir);\n if (!loadedGlobal) return report(false, NO_CHANGES);\n\n const current = loadedGlobal.config;\n const mutated = applyMutation(mutation, current);\n if (!mutated) return report(false, NO_CHANGES);\n\n const prior = fillRequiredFields(current, fallbackNameFor(mutation));\n const next = fillRequiredFields(mutated, fallbackNameFor(mutation));\n const changes = classifyGlobalChange(prior, next);\n\n const globalWritten = await writeGlobalConfigHalf(next, getProjectConfigPath(homeDir));\n if (!next.projects?.length) return report(globalWritten, changes);\n\n const loaded = await resolveGateDeps(deps, consequenceTier(changes));\n if (!loaded) return report(globalWritten, changes);\n\n const { propagated, recompile } = await applyConsequences(next, changes, loaded);\n return report(globalWritten, changes, propagated, recompile);\n });\n}\n\n/**\n * Prunes the CLI-inlined global entries from every registered project after a\n * GLOBAL uninstall, and recompiles their agents.\n *\n * Writes no pair: the pair this would derive from has just been deleted. That is\n * the reason this is its own entry rather than a flag on a writing one — the\n * removal case must not be reachable from a code path whose job is to write.\n *\n * Call AFTER the global manifest has been removed so the regenerated project\n * types fall back to the standalone form instead of importing from the\n * now-deleted global config-types.ts.\n */\nexport async function propagateGlobalRemoval(\n preRemovalGlobalConfig: ProjectConfig,\n deps: LoadedGateDeps,\n): Promise<GateReport> {\n return withGateToken(async () => {\n const changes = classifyGlobalChange(preRemovalGlobalConfig, {\n ...preRemovalGlobalConfig,\n skills: [],\n agents: [],\n selectedAgents: [],\n });\n\n const propagated = await pruneGlobalEntriesFromRegisteredProjects(\n preRemovalGlobalConfig,\n deps.matrix,\n deps.agents,\n );\n const recompile = await recompilePropagated(propagated.updated);\n\n return report(false, changes, propagated, recompile);\n });\n}\n\n/**\n * Creates the blank global pair when none exists. No classification and no\n * fan-out: the registration list propagation reads lives in the file that was\n * just found absent, so a pair created here has no registered projects.\n */\nexport async function ensureBlankPair(): Promise<boolean> {\n return withGateToken(() => ensureBlankPairInternal());\n}\n\nexport type WriteProjectPartialOptions = {\n /** Name to invent when the partial has none. Absent → a missing name is an error. */\n fallbackName?: string;\n};\n\n/**\n * The partial with every stack assignment normalized back to `SkillAssignment[]`.\n *\n * Every caller of this entry reads the config with the LENIENT loader\n * (`loadProjectSourceConfig`), overlays one scalar, and hands the result back.\n * That loader passes the on-disk stack through untouched, and the writer emits an\n * exclusive category in its BARE form (`\"web-framework\": \"web-framework-react\"`,\n * no array) — so on a load / re-emit round trip `compactCategories`, which keeps\n * only non-empty arrays, drops the category and the user silently loses an\n * assignment they never touched (D-308).\n *\n * Normalizing at this boundary rather than inside the writer keeps the fix on the\n * one path that can present a denormalized stack: the full loader\n * (`loadProjectConfigFromDir`) already runs `normalizeStackRecord`, so every other\n * writer input arrives normalized.\n */\nfunction withNormalizedStack(partial: Partial<ProjectConfig>): Partial<ProjectConfig> {\n if (!partial.stack) return partial;\n return { ...partial, stack: normalizeStackRecord(partial.stack) };\n}\n\n/**\n * Writes a partial config to a PROJECT's `.claude-src/config.ts`, filling\n * required defaults. Refuses the home directory: the global pair's config half\n * may never be written without its types sibling and without classification.\n */\nexport async function writeProjectPartial(\n projectDir: string,\n partial: Partial<ProjectConfig>,\n options: WriteProjectPartialOptions = {},\n): Promise<void> {\n if (isHomeDirectory(projectDir)) {\n throw new GlobalPairWriteViolation(getProjectConfigPath(projectDir));\n }\n\n const configPath = getProjectConfigPath(projectDir);\n await ensureDir(path.join(projectDir, CLAUDE_SRC_DIR));\n await writeFile(\n configPath,\n generateConfigSource(fillRequiredFields(withNormalizedStack(partial), options.fallbackName)),\n );\n}\n\n/**\n * Writes a scaffolded marketplace's `config.ts`, optionally preceded by a\n * comment. Renders the source here rather than taking rendered text so the\n * config generator stays inside the gate's reach; refuses the home directory,\n * where scaffolding a marketplace would replace the pair's config half with a\n * config that declares one dummy skill.\n */\nexport async function writeMarketplaceScaffoldConfig(\n marketplaceDir: string,\n config: ProjectConfig,\n leadingComment = \"\",\n): Promise<void> {\n if (isHomeDirectory(marketplaceDir)) {\n throw new GlobalPairWriteViolation(getProjectConfigPath(marketplaceDir));\n }\n\n await writeFile(\n path.join(marketplaceDir, CLAUDE_SRC_DIR, STANDARD_FILES.CONFIG_TS),\n leadingComment + generateConfigSource(config),\n );\n}\n\n/**\n * `normalizeProjectPath` is the single rule for any value compared against the\n * global config's `projects` array, so a reader that only wants to MATCH a\n * registration (never write one) gets it from here rather than reimplementing\n * `fs.realpathSync` and drifting from the rule the registrations were stored\n * under. It writes nothing, so exporting it hands out no privilege.\n */\nexport { mergeGlobalConfigs, normalizeProjectPath };\n","import os from \"os\";\nimport path from \"path\";\nimport type { Category, ProjectConfig } from \"../../types\";\nimport { CLAUDE_SRC_DIR, DEFAULT_PLUGIN_NAME, GLOBAL_CONFIG_NAME } from \"../../consts\";\nimport { isSkillAssignment } from \"../../utils/type-guards\";\nimport { matrix } from \"../matrix/matrix-provider\";\nimport { assembleConfigTypesSource, STACK_AGENT_CONFIG_LOOSE_LINE } from \"./config-types-writer\";\n\n/**\n * This module renders config sources; it writes nothing. The partial-config\n * writer and the blank-global-pair creator that used to live here are\n * `writeProjectPartial` and `ensureBlankPair` in `config-gate/`, which is the\n * only code allowed to put either half of the pair on disk.\n */\n\nexport type ConfigSourceOptions = {\n /**\n * When true, generates a project config that imports and extends the global config.\n * The global config import path is resolved internally via `getGlobalConfigImportPath()`.\n */\n isProjectConfig?: boolean;\n\n /**\n * When provided alongside `isProjectConfig`, inlines global skills/agents directly\n * instead of generating `import globalConfig` and spread syntax.\n * Produces a self-contained, readable config snapshot.\n */\n globalConfig?: ProjectConfig;\n};\n\n/** Fields that are extracted into typed named variables below the export default */\nconst EXTRACTED_FIELDS = new Set([\"skills\", \"agents\", \"stack\", \"domains\", \"selectedAgents\"]);\n\n/** One config entry as an indented array-element line. */\nfunction renderEntryLine(entry: unknown): string {\n return ` ${JSON.stringify(entry)},`;\n}\n\n/** One scalar field as an indented object-property line. */\nfunction renderScalarField(key: string, value: unknown): string {\n return ` ${JSON.stringify(key)}: ${JSON.stringify(value)},`;\n}\n\ntype ConfigArrays = {\n skills: unknown[];\n agents: unknown[];\n stack: Record<string, unknown> | undefined;\n domains: unknown[];\n selectedAgents: string[];\n};\n\n/** The five extracted array/stack fields of a cleaned config, defaulted for emission. */\nfunction extractConfigArrays(cleaned: Record<string, unknown>): ConfigArrays {\n // Boundary cast: cleaned comes from JSON.parse(JSON.stringify(...)) so arrays are plain JSON values\n return {\n skills: (cleaned.skills as unknown[]) ?? [],\n agents: (cleaned.agents as unknown[]) ?? [],\n stack: cleaned.stack as Record<string, unknown> | undefined,\n domains: (cleaned.domains as unknown[]) ?? [],\n selectedAgents: (cleaned.selectedAgents as string[]) ?? [],\n };\n}\n\n/**\n * Generates a TypeScript config file source from a ProjectConfig object.\n * The export default sits at the top as a table of contents, with typed named\n * variables (skills, agents, stack, domains) declared below it.\n *\n * When `options.isProjectConfig` is true, the generated config imports from the global\n * config and spreads global arrays into skills, agents, and domains.\n */\n/**\n * Shared pre-emission cleanup: JSON round-trip (drops undefined values), optional\n * `projects` removal (project configs never emit the global tracking list), and\n * stack compaction (strip `{ id, preloaded: false }` to bare strings while\n * preserving SkillAssignment[] arrays).\n */\nfunction cleanForEmission(\n config: ProjectConfig,\n options: { dropProjects: boolean },\n): Record<string, unknown> {\n const cleaned: Record<string, unknown> = JSON.parse(JSON.stringify(config));\n if (options.dropProjects) {\n delete cleaned.projects;\n }\n if (cleaned.stack) {\n // Boundary cast: cleaned comes from JSON.parse(JSON.stringify(...)), so the stack\n // is a plain JSON record of agent -> category -> assignment arrays\n cleaned.stack = compactStackAssignments(\n cleaned.stack as Record<string, Record<string, unknown[]>>,\n );\n }\n return cleaned;\n}\n\nexport function generateConfigSource(config: ProjectConfig, options?: ConfigSourceOptions): string {\n if (options?.isProjectConfig && options.globalConfig) {\n return generateProjectConfigWithInlinedGlobal(\n cleanForEmission(config, { dropProjects: true }),\n cleanForEmission(options.globalConfig, { dropProjects: true }),\n );\n }\n\n if (options?.isProjectConfig) {\n return generateProjectConfigWithGlobalImport(\n cleanForEmission(config, { dropProjects: true }),\n getGlobalConfigImportPath(),\n );\n }\n\n return generateStandaloneConfig(cleanForEmission(config, { dropProjects: false }));\n}\n\n/**\n * Generates a standalone config source with typed named variables above the export default.\n * The export default at the bottom acts as a table of contents, referencing the named variables.\n */\nfunction generateStandaloneConfig(cleaned: Record<string, unknown>): string {\n const { skills, agents, stack, domains, selectedAgents } = extractConfigArrays(cleaned);\n\n const hasSkills = skills.length > 0;\n const hasAgents = agents.length > 0;\n const hasStack = stack != null && Object.keys(stack).length > 0;\n const hasDomains = domains.length > 0;\n const hasSelectedAgents = selectedAgents.length > 0;\n\n // Build type imports based on what's used\n const typeImports = buildTypeImports({\n hasSkills,\n hasAgents,\n hasStack,\n hasDomains,\n hasSelectedAgents,\n });\n\n const lines: string[] = [`import type { ${typeImports} } from \"./config-types\";`];\n\n // Add named variable declarations above the export default\n if (hasSkills) {\n lines.push(``);\n lines.push(`const skills: SkillConfig[] = [`);\n lines.push(skills.map(renderEntryLine).join(\"\\n\"));\n lines.push(`];`);\n }\n\n if (hasAgents) {\n lines.push(``);\n lines.push(`const agents: AgentScopeConfig[] = [`);\n lines.push(agents.map(renderEntryLine).join(\"\\n\"));\n lines.push(`];`);\n }\n\n if (hasStack) {\n lines.push(``);\n const stackBody = JSON.stringify(stack, null, 2);\n lines.push(`const stack: Partial<Record<ProjectAgentName, StackAgentConfig>> = ${stackBody};`);\n }\n\n if (hasDomains) {\n lines.push(``);\n const items = domains.map((d) => JSON.stringify(d)).join(\", \");\n lines.push(`const domains: Domain[] = [${items}];`);\n }\n\n if (hasSelectedAgents) {\n lines.push(``);\n const items = selectedAgents.map((a) => JSON.stringify(a)).join(\", \");\n lines.push(`const selectedAgents: SelectedAgentName[] = [${items}];`);\n }\n\n // Extracted fields reference their named variable (or an empty literal when the\n // variable was not emitted); `stack`/`selectedAgents` are omitted entirely when absent.\n const renderExportField = (key: string, value: unknown): string[] => {\n if (!EXTRACTED_FIELDS.has(key)) return [renderScalarField(key, value)];\n if (key === \"skills\") return [` skills${hasSkills ? \"\" : \": []\"},`];\n if (key === \"agents\") return [` agents${hasAgents ? \"\" : \": []\"},`];\n if (key === \"stack\") return hasStack ? [` stack,`] : [];\n if (key === \"domains\") return [` domains${hasDomains ? \"\" : \": []\"},`];\n return hasSelectedAgents ? [` selectedAgents,`] : [];\n };\n const exportFields = Object.entries(cleaned).flatMap(([key, value]) =>\n renderExportField(key, value),\n );\n\n lines.push(``);\n lines.push(`export default {`);\n lines.push(...exportFields);\n lines.push(`} satisfies ProjectConfig;`);\n\n lines.push(``);\n return lines.join(\"\\n\");\n}\n\n/**\n * Builds the type import list based on which extracted fields are present.\n * ProjectConfig is always included. Other types are included only when used.\n */\nfunction buildTypeImports(flags: {\n hasSkills: boolean;\n hasAgents: boolean;\n hasStack: boolean;\n hasDomains: boolean;\n hasSelectedAgents?: boolean;\n}): string {\n return [\n flags.hasDomains && \"Domain\",\n \"ProjectConfig\",\n flags.hasStack && \"ProjectAgentName\",\n (flags.hasStack || flags.hasSelectedAgents) && \"SelectedAgentName\",\n flags.hasAgents && \"AgentScopeConfig\",\n flags.hasSkills && \"SkillConfig\",\n flags.hasStack && \"StackAgentConfig\",\n ]\n .filter((t): t is string => Boolean(t))\n .join(\", \");\n}\n\n/**\n * Generates a project config source that imports from the global config and extends it.\n * Typed named variables are declared above the export default. The export default at\n * the bottom acts as a table of contents. Arrays (skills, agents, domains) are spread\n * with globalConfig first, then project items.\n */\nfunction generateProjectConfigWithGlobalImport(\n cleaned: Record<string, unknown>,\n globalImportPath: string,\n): string {\n const importPath = `${globalImportPath}/config`;\n\n const { skills, agents, stack, domains, selectedAgents } = extractConfigArrays(cleaned);\n\n const hasProjectDomains = domains.length > 0;\n const hasStack = stack != null && Object.keys(stack).length > 0;\n const hasProjectSelectedAgents = selectedAgents.length > 0;\n\n // Build type imports\n const typeImports = buildTypeImports({\n hasSkills: true, // Always present (spread from global)\n hasAgents: true, // Always present (spread from global)\n hasStack,\n hasDomains: hasProjectDomains,\n hasSelectedAgents: hasProjectSelectedAgents,\n });\n\n const lines: string[] = [\n `import globalConfig from \"${importPath}\";`,\n `import type { ${typeImports} } from \"./config-types\";`,\n ];\n\n // Skills variable (always present with global spread)\n lines.push(``);\n const skillItems = skills.map(renderEntryLine).join(\"\\n\");\n lines.push(`const skills: SkillConfig[] = [`);\n lines.push(` ...globalConfig.skills,`);\n if (skillItems) lines.push(skillItems);\n lines.push(`];`);\n\n // Agents variable (always present with global spread)\n lines.push(``);\n const agentItems = agents.map(renderEntryLine).join(\"\\n\");\n lines.push(`const agents: AgentScopeConfig[] = [`);\n lines.push(` ...globalConfig.agents,`);\n if (agentItems) lines.push(agentItems);\n lines.push(`];`);\n\n // Stack variable (only if project has stack assignments)\n if (hasStack) {\n lines.push(``);\n const stackBody = JSON.stringify(stack, null, 2);\n lines.push(`const stack: Partial<Record<ProjectAgentName, StackAgentConfig>> = ${stackBody};`);\n }\n\n // Domains variable (only if project has domains)\n if (hasProjectDomains) {\n lines.push(``);\n const domainItems = domains.map(renderEntryLine).join(\"\\n\");\n lines.push(`const domains: Domain[] = [`);\n lines.push(` ...(globalConfig.domains ?? []),`);\n if (domainItems) lines.push(domainItems);\n lines.push(`];`);\n }\n\n // selectedAgents variable (only if project has selectedAgents)\n if (hasProjectSelectedAgents) {\n lines.push(``);\n const items = selectedAgents.map((a) => JSON.stringify(a)).join(\", \");\n lines.push(\n `const selectedAgents: SelectedAgentName[] = [...(globalConfig.selectedAgents ?? []), ${items}];`,\n );\n }\n\n // Build scalar fields (everything that isn't an extracted field or name)\n const scalarFields = Object.entries(cleaned)\n .filter(([key]) => !EXTRACTED_FIELDS.has(key) && key !== \"name\")\n .map(([key, value]) => renderScalarField(key, value))\n .join(\"\\n\");\n\n // Build export default (table of contents at bottom)\n const exportFields: string[] = [\n ` ...globalConfig,`,\n ` name: ${JSON.stringify(resolveProjectName(cleaned))},`,\n ` skills,`,\n ` agents,`,\n ...(hasStack ? [` stack,`] : []),\n ...(hasProjectDomains ? [` domains,`] : []),\n ...(hasProjectSelectedAgents ? [` selectedAgents,`] : []),\n ...(scalarFields ? [scalarFields] : []),\n ];\n\n lines.push(``);\n lines.push(`export default {`);\n lines.push(...exportFields);\n lines.push(`} satisfies ProjectConfig;`);\n\n lines.push(``);\n return lines.join(\"\\n\");\n}\n\n/** Project configs never inherit \"global\" as their name from the globalConfig spread. */\nfunction resolveProjectName(cleaned: Record<string, unknown>): unknown {\n return cleaned.name && cleaned.name !== GLOBAL_CONFIG_NAME ? cleaned.name : DEFAULT_PLUGIN_NAME;\n}\n\ntype InlinedGlobalPartition = {\n /** Global entries with active entries replaced by their project tombstones. */\n globalSkills: unknown[];\n globalAgents: unknown[];\n /** Active (non-excluded) project entries. */\n projectSkills: unknown[];\n projectAgents: unknown[];\n /** Project stack filtered to project-scoped agents only. */\n filteredStack: Record<string, unknown> | undefined;\n /** Merged unique global + project values. */\n domains: unknown[];\n selectedAgents: string[];\n};\n\n/**\n * Pure partition of project + global entries for the inlined snapshot.\n *\n * Excluded globals are routed to the project partition by splitConfigByScope,\n * but render under \"// global\" in the output for readability. When inlining,\n * active global entries are replaced by their excluded tombstones — the\n * tombstone masks the global entry for this project; the active project entry\n * (if any) appears separately in the project section. The project stack keeps\n * only project-scoped agents: global agents' stack entries live in the global\n * config only.\n */\nfunction partitionInlinedConfigEntries(\n cleaned: Record<string, unknown>,\n cleanedGlobal: Record<string, unknown>,\n): InlinedGlobalPartition {\n const project = extractConfigArrays(cleaned);\n const global = extractConfigArrays(cleanedGlobal);\n\n const isExcluded = (entry: unknown): boolean =>\n (entry as { excluded?: boolean }).excluded === true;\n const idOf = (entry: unknown): string => (entry as { id: string }).id;\n const nameOf = (entry: unknown): string => (entry as { name: string }).name;\n\n const excludedGlobalSkills = project.skills.filter(isExcluded);\n const excludedGlobalAgents = project.agents.filter(isExcluded);\n const projectSkills = project.skills.filter((s) => !isExcluded(s));\n const projectAgents = project.agents.filter((a) => !isExcluded(a));\n\n const excludedSkillIds = new Set(excludedGlobalSkills.map(idOf));\n const excludedAgentNames = new Set(excludedGlobalAgents.map(nameOf));\n const globalSkills = [\n ...global.skills.filter((s) => !excludedSkillIds.has(idOf(s))),\n ...excludedGlobalSkills,\n ];\n const globalAgents = [\n ...global.agents.filter((a) => !excludedAgentNames.has(nameOf(a))),\n ...excludedGlobalAgents,\n ];\n\n const projectAgentNames = new Set(projectAgents.map(nameOf));\n const filteredStack: Record<string, unknown> | undefined = project.stack\n ? Object.fromEntries(\n Object.entries(project.stack).filter(([agent]) => projectAgentNames.has(agent)),\n )\n : undefined;\n\n return {\n globalSkills,\n globalAgents,\n projectSkills,\n projectAgents,\n filteredStack,\n domains: [...new Set([...global.domains, ...project.domains])],\n selectedAgents: [...new Set([...global.selectedAgents, ...project.selectedAgents])],\n };\n}\n\n/**\n * Generates a project config with global skills/agents inlined directly.\n * No `import globalConfig` — the output is a self-contained readable snapshot.\n * Global items appear first with a `// global` comment, followed by project items\n * with a `// project` comment (only when project items exist).\n */\nfunction generateProjectConfigWithInlinedGlobal(\n cleaned: Record<string, unknown>,\n cleanedGlobal: Record<string, unknown>,\n): string {\n const partition = partitionInlinedConfigEntries(cleaned, cleanedGlobal);\n const { globalSkills, globalAgents, projectSkills, projectAgents, filteredStack } = partition;\n\n const hasGlobalSkills = globalSkills.length > 0;\n const hasProjectSkills = projectSkills.length > 0;\n const hasSkills = hasGlobalSkills || hasProjectSkills;\n\n const hasGlobalAgents = globalAgents.length > 0;\n const hasProjectAgents = projectAgents.length > 0;\n const hasAgents = hasGlobalAgents || hasProjectAgents;\n\n const hasStack = filteredStack != null && Object.keys(filteredStack).length > 0;\n const hasDomains = partition.domains.length > 0;\n const hasSelectedAgents = partition.selectedAgents.length > 0;\n\n const typeImports = buildTypeImports({\n hasSkills,\n hasAgents,\n hasStack,\n hasDomains,\n hasSelectedAgents,\n });\n\n const lines: string[] = [`import type { ${typeImports} } from \"./config-types\";`];\n\n // Skills variable\n if (hasSkills) {\n lines.push(``);\n lines.push(`const skills: SkillConfig[] = [`);\n lines.push(\n ...(hasGlobalSkills ? [` // global`, ...globalSkills.map(renderEntryLine)] : []),\n ...(hasProjectSkills ? [` // project`, ...projectSkills.map(renderEntryLine)] : []),\n );\n lines.push(`];`);\n }\n\n // Agents variable\n if (hasAgents) {\n lines.push(``);\n lines.push(`const agents: AgentScopeConfig[] = [`);\n lines.push(\n ...(hasGlobalAgents ? [` // global`, ...globalAgents.map(renderEntryLine)] : []),\n ...(hasProjectAgents ? [` // project`, ...projectAgents.map(renderEntryLine)] : []),\n );\n lines.push(`];`);\n }\n\n // Stack variable (project agents only)\n if (hasStack) {\n lines.push(``);\n const stackBody = JSON.stringify(filteredStack, null, 2);\n lines.push(`const stack: Partial<Record<ProjectAgentName, StackAgentConfig>> = ${stackBody};`);\n }\n\n // Domains variable\n if (hasDomains) {\n lines.push(``);\n const items = partition.domains.map((d) => JSON.stringify(d)).join(\", \");\n lines.push(`const domains: Domain[] = [${items}];`);\n }\n\n // selectedAgents variable (merged global + project, deduplicated)\n if (hasSelectedAgents) {\n lines.push(``);\n const items = partition.selectedAgents.map((a) => JSON.stringify(a)).join(\", \");\n lines.push(`const selectedAgents: SelectedAgentName[] = [${items}];`);\n }\n\n // Scalar fields: project values take precedence; global values emit first when not overridden\n const projectScalarFields = Object.entries(cleaned).filter(\n ([key]) => !EXTRACTED_FIELDS.has(key) && key !== \"name\",\n );\n const projectScalarKeys = new Set(projectScalarFields.map(([key]) => key));\n const globalScalarFields = Object.entries(cleanedGlobal).filter(\n ([key]) => !EXTRACTED_FIELDS.has(key) && key !== \"name\" && !projectScalarKeys.has(key),\n );\n\n const exportFields: string[] = [\n ` name: ${JSON.stringify(resolveProjectName(cleaned))},`,\n ...globalScalarFields.map(([key, value]) => renderScalarField(key, value)),\n ...projectScalarFields.map(([key, value]) => renderScalarField(key, value)),\n hasSkills ? ` skills,` : ` skills: [],`,\n hasAgents ? ` agents,` : ` agents: [],`,\n ...(hasStack ? [` stack,`] : []),\n ...(hasDomains ? [` domains,`] : []),\n ...(hasSelectedAgents ? [` selectedAgents,`] : []),\n ];\n\n lines.push(``);\n lines.push(`export default {`);\n lines.push(...exportFields);\n lines.push(`} satisfies ProjectConfig;`);\n\n lines.push(``);\n return lines.join(\"\\n\");\n}\n\n/**\n * Compacts one SkillAssignment down to the smallest form that still carries its information.\n * - { id: \"...\", preloaded: false } → \"...\" (the flag is the default, so the id says everything)\n * - { id: \"...\", preloaded: true } → { id: \"...\", preloaded: true } (preserved)\n */\nfunction compactAssignment(assignment: unknown): unknown {\n if (isSkillAssignment(assignment) && \"preloaded\" in assignment) {\n return assignment.preloaded ? { id: assignment.id, preloaded: true } : assignment.id;\n }\n return assignment;\n}\n\n/**\n * True when the active matrix DECLARES this category as holding at most one skill. Read from the\n * matrix singleton so a source repo's category overrides are honoured. A category the matrix does\n * not declare is deliberately NOT treated as exclusive — the same rule local-installer applies.\n */\nfunction isExclusiveCategory(category: string): boolean {\n // Boundary cast: category keys come from JSON-cleaned config data, not the Category union\n return matrix.categories[category as Category]?.exclusive === true;\n}\n\n/**\n * The emitted value for one category's assignments.\n *\n * An exclusive category can only ever hold one skill, so its array wrapper carries nothing the\n * reader needs and the bare value IS the assignment. Non-exclusive categories keep their array\n * even at length one — there the wrapper is load-bearing, because a second skill may join.\n *\n * Two skills in an exclusive category means the caller built something the config cannot express.\n * Dropping the extra would write a config that does not match what was selected, and nothing\n * downstream could tell, so it fails here instead.\n */\nfunction compactCategoryAssignments(category: string, assignments: unknown[]): unknown {\n const compacted = assignments.map(compactAssignment);\n if (!isExclusiveCategory(category)) return compacted;\n\n if (compacted.length > 1) {\n throw new Error(\n `Category '${category}' is exclusive but holds ${compacted.length} skills: ${JSON.stringify(compacted)}`,\n );\n }\n return compacted[0];\n}\n\nfunction compactCategories(categories: Record<string, unknown[]>): Record<string, unknown> {\n return Object.fromEntries(\n Object.entries(categories)\n .filter(([, assignments]) => Array.isArray(assignments) && assignments.length > 0)\n .map(([category, assignments]) => [\n category,\n compactCategoryAssignments(category, assignments),\n ]),\n );\n}\n\nfunction compactStackAssignments(\n stack: Record<string, Record<string, unknown[]>>,\n): Record<string, Record<string, unknown>> {\n return Object.fromEntries(\n Object.entries(stack)\n .map(([agent, categories]) => [agent, compactCategories(categories)] as const)\n .filter(([, categories]) => Object.keys(categories).length > 0),\n );\n}\n\n/**\n * Returns the absolute path to the global .claude-src directory.\n * Used as the import path for project configs that extend global.\n */\nexport function getGlobalConfigImportPath(): string {\n return path.join(os.homedir(), CLAUDE_SRC_DIR);\n}\n\n/**\n * Generates a blank global config source (empty arrays, no import preamble).\n */\nexport function generateBlankGlobalConfigSource(): string {\n return `import type { ProjectConfig } from \"./config-types\";\n\nexport default {\n \"name\": \"${GLOBAL_CONFIG_NAME}\",\n \"skills\": [],\n \"agents\": [],\n \"domains\": []\n} satisfies ProjectConfig;\\n`;\n}\n\n/**\n * Generates blank global config-types source (all types are `never`).\n */\nexport function generateBlankGlobalConfigTypesSource(): string {\n return assembleConfigTypesSource({\n skillId: \"never\",\n agentName: \"never\",\n selectedAgentName: \"never\",\n projectAgentName: \"SelectedAgentName\",\n domain: \"never\",\n category: \"never\",\n stackAgentConfig: STACK_AGENT_CONFIG_LOOSE_LINE,\n });\n}\n","import path from \"path\";\nimport { groupBy, unique } from \"remeda\";\nimport type {\n AgentName,\n Category,\n CategoryPath,\n Domain,\n MergedSkillsMatrix,\n ProjectConfig,\n ResolvedSkill,\n SkillId,\n} from \"../../types\";\nimport { loadProjectConfigFromDir } from \"./project-config\";\nimport { isHomeDirectory } from \"../installation/is-home-directory\";\n// The gate's private token module, imported here by exception (eslint records\n// it): this is one of the two enforcement guards, and `gate-token.ts` is a\n// dependency-free leaf, so the import cannot cycle back through the gate.\nimport { GlobalPairWriteViolation } from \"../config-gate/gate-token.js\";\nimport { activeProjectAgentNames } from \"./scope-predicates\";\nimport {\n CLAUDE_SRC_DIR,\n CLI_INVOKE_COMMAND,\n GLOBAL_INSTALL_ROOT,\n LOCAL_PSEUDO_CATEGORY,\n STANDARD_FILES,\n} from \"../../consts\";\nimport { directoryExists, fileExists, writeFile } from \"../../utils/fs\";\nimport { verbose } from \"../../utils/logger\";\nimport { typedEntries, typedKeys } from \"../../utils/typed-object\";\nimport { EFFORT_NAMES, MODEL_NAMES } from \"../../types/matrix\";\n\nconst MULTI_LINE_THRESHOLD = 6;\n\n/**\n * Emitted for a union with no members. `never` is the identity element for a\n * union: an empty install must accept NO member, and `never | \"web-framework-react\"`\n * reduces to `\"web-framework-react\"`, so a project types file that extends an empty\n * global union still narrows. Emitting `string` here would instead absorb every\n * literal and silently disable type checking of the generated config.ts.\n * Matches generateBlankGlobalConfigTypesSource, which emits `never` for the same state.\n */\nconst EMPTY_UNION_TYPE = \"never\";\n\n/**\n * Extra just-created skill IDs / agent names / domains / categories to fold into\n * a regenerated config-types.ts (entities that exist in config but not yet in the\n * loaded matrix). buildProjectTypesExtras returns Required<ConfigTypesExtras>.\n */\nexport type ConfigTypesExtras = {\n extraSkillIds?: string[];\n extraAgentNames?: string[];\n extraDomains?: string[];\n extraCategories?: string[];\n};\n\n/**\n * Returns the absolute path to the global config-types.ts if it exists, or null.\n * Used to determine whether a project config-types.ts should import from global.\n */\nexport async function getGlobalConfigTypesPath(): Promise<string | null> {\n const globalConfigTypesPath = path.join(\n GLOBAL_INSTALL_ROOT,\n CLAUDE_SRC_DIR,\n STANDARD_FILES.CONFIG_TYPES_TS,\n );\n if (await fileExists(globalConfigTypesPath)) {\n return globalConfigTypesPath;\n }\n return null;\n}\n\n/**\n * Computes a relative import path from a project's .claude-src/ to the global .claude-src/.\n * Returns a POSIX-style relative path suitable for TypeScript import statements.\n */\nfunction computeGlobalTypesImportPath(projectDir: string): string {\n const projectClaudeSrc = path.join(projectDir, CLAUDE_SRC_DIR);\n const globalClaudeSrc = path.join(GLOBAL_INSTALL_ROOT, CLAUDE_SRC_DIR);\n const relativePath = path.relative(projectClaudeSrc, globalClaudeSrc);\n // Convert to POSIX separators for TypeScript imports\n return relativePath.split(path.sep).join(\"/\");\n}\n\n/** Max skills per category before switching to multi-line format in StackAgentConfig */\nconst STACK_AGENT_CONFIG_INLINE_THRESHOLD = 3;\n\n/**\n * A vocabulary constant as a single-line TypeScript literal union. Deliberately not `formatUnion`:\n * that one breaks onto several lines past a threshold, which would be invalid inside an emitted\n * property, and these lists are fixed and short.\n */\nfunction formatLiteralUnion(members: readonly string[]): string {\n return members.map((m) => `\"${m}\"`).join(\" | \");\n}\n\n/**\n * Types emitted before the dynamically-generated StackAgentConfig.\n * Includes InstallMode, SkillConfig, AgentScopeConfig, and the generic SkillAssignment.\n */\nexport const PROJECT_CONFIG_TYPES_BEFORE = `export type InstallMode = \"eject\" | \"plugin\" | \"mixed\";\n\nexport type SkillConfig = {\n id: SkillId;\n scope: \"project\" | \"global\";\n source: string;\n excluded?: boolean;\n};\n\nexport type AgentScopeConfig = {\n name: AgentName;\n scope: \"project\" | \"global\";\n model?: ${formatLiteralUnion(MODEL_NAMES)};\n effort?: ${formatLiteralUnion(EFFORT_NAMES)};\n excluded?: boolean;\n};\n\nexport type SkillAssignment<S extends SkillId = SkillId> = S | { id: S; preloaded: boolean };\n`;\n\n/**\n * The ProjectConfig interface, emitted after StackAgentConfig.\n */\nexport const PROJECT_CONFIG_INTERFACE_AFTER = `export interface ProjectConfig {\n /** Project/plugin name (kebab-case) */\n name: string;\n\n /** Project description */\n description?: string;\n\n /** Per-agent configuration with scope */\n agents: AgentScopeConfig[];\n\n /** Per-skill configuration with scope and source */\n skills: SkillConfig[];\n\n /** Author handle (e.g., \"@vince\") */\n author?: string;\n\n /** Stack configuration: agent -> category -> skill assignment */\n stack?: Partial<Record<ProjectAgentName, StackAgentConfig>>;\n\n /** Skills source path or URL */\n source?: string;\n\n /** Marketplace identifier for plugin installation */\n marketplace?: string;\n\n /** Agents source path or URL (when agents come from a different source than skills) */\n agentsSource?: string;\n\n /** Selected domains from the wizard */\n domains?: Domain[];\n\n /** Selected agents from the wizard */\n selectedAgents?: SelectedAgentName[];\n\n /** Tracked project installation paths (global config only) */\n projects?: string[];\n}\n`;\n\n/**\n * Loose StackAgentConfig line emitted when no per-category skill constraint applies. Admits a\n * single assignment as well as an array: project configs always get this line, and they carry the\n * bare (unwrapped) form for exclusive categories.\n */\nexport const STACK_AGENT_CONFIG_LOOSE_LINE =\n \"export type StackAgentConfig = Partial<Record<Category, SkillAssignment | SkillAssignment[]>>;\";\n\n/**\n * Assembles a config-types.ts source from its per-alias union lines — the single\n * template shared by generateConfigTypesSource, generateProjectConfigTypesSource,\n * and generateBlankGlobalConfigTypesSource. Their emitted text is identical apart\n * from the alias contents, the StackAgentConfig line, and the optional\n * (project-only) import block.\n *\n * The emitted ProjectConfig interface (PROJECT_CONFIG_INTERFACE_AFTER) deliberately\n * diverges from types/config.ts: it uses the narrowed generated aliases\n * (SelectedAgentName, ProjectAgentName, per-category StackAgentConfig) so a user's\n * config.ts is type-checked against only the installed skills/agents rather than\n * the full runtime union.\n */\nexport function assembleConfigTypesSource(parts: {\n importBlock?: string;\n skillId: string;\n agentName: string;\n selectedAgentName: string;\n projectAgentName: string;\n domain: string;\n category: string;\n stackAgentConfig: string;\n}): string {\n const importSection = parts.importBlock ? `${parts.importBlock}\\n\\n` : \"\";\n return `// AUTO-GENERATED by agents-inc — DO NOT EDIT\n\n${importSection}export type SkillId = ${parts.skillId};\n\nexport type AgentName = ${parts.agentName};\n\nexport type SelectedAgentName = ${parts.selectedAgentName};\n\nexport type ProjectAgentName = ${parts.projectAgentName};\n\nexport type Domain = ${parts.domain};\n\nexport type Category = ${parts.category};\n\n${PROJECT_CONFIG_TYPES_BEFORE}\n${parts.stackAgentConfig}\n\n${PROJECT_CONFIG_INTERFACE_AFTER}`;\n}\n\nfunction formatSkillUnion(skills: SkillId[]): string {\n const sorted = [...skills].sort();\n const quoted = sorted.map((s) => `\"${s}\"`);\n if (quoted.length <= STACK_AGENT_CONFIG_INLINE_THRESHOLD) {\n return quoted.join(\" | \");\n }\n return \"\\n\" + quoted.map((q) => ` | ${q}`).join(\"\\n\") + \"\\n \";\n}\n\n/**\n * Generates a per-category constrained StackAgentConfig type from skill-by-category groupings.\n * Falls back to the loose line when no categories have skills.\n *\n * The union is over WHICH skill may be assigned; exclusivity is about HOW MANY, so an exclusive\n * category emits a bare `SkillAssignment<...>` (no array) however long its candidate list is. A\n * category the matrix does not declare is not treated as exclusive — same rule the installer\n * applies, on the same reasoning: a constraint must fire on a flag the data actually carries.\n */\nfunction generateStackAgentConfig(\n skillsByCategory: Map<Category, SkillId[]>,\n matrix: MergedSkillsMatrix,\n): string {\n if (skillsByCategory.size === 0) {\n return STACK_AGENT_CONFIG_LOOSE_LINE;\n }\n\n const properties = [...skillsByCategory.entries()]\n .sort(([a], [b]) => a.localeCompare(b))\n .map(([category, skills]) => {\n const arraySuffix = matrix.categories[category]?.exclusive === true ? \"\" : \"[]\";\n return ` \"${category}\"?: SkillAssignment<${formatSkillUnion(skills)}>${arraySuffix};`;\n });\n\n return [\"export type StackAgentConfig = {\", ...properties, \"};\"].join(\"\\n\");\n}\n\n/**\n * Builds a Map of Category -> SkillId[] from the matrix, filtered to only include\n * categories and skills that are in the provided arrays.\n */\nfunction buildSkillsByCategory(\n skillIds: SkillId[],\n categories: Category[],\n matrix: MergedSkillsMatrix,\n): Map<Category, SkillId[]> {\n const categorySet = new Set(categories);\n const eligible = [...new Set(skillIds)]\n .map((id) => ({ id, category: matrix.skills[id]?.category }))\n .filter(\n (entry): entry is { id: SkillId; category: Category } =>\n entry.category !== undefined &&\n entry.category !== LOCAL_PSEUDO_CATEGORY &&\n categorySet.has(entry.category),\n );\n\n return new Map(\n typedEntries(groupBy(eligible, (entry) => entry.category)).map(([category, entries]) => [\n category,\n entries.map((entry) => entry.id),\n ]),\n );\n}\n\n/**\n * Domains that only ever appear on custom categories — the subtraction rule:\n * a domain is custom only if it NEVER appears on a non-custom (marketplace)\n * category. Explicitly-passed extra domains are always treated as custom.\n */\nfunction collectCustomDomains(\n matrix: MergedSkillsMatrix,\n customCategorySet: Set<string>,\n extraDomains: string[],\n): Set<string> {\n const categories = typedKeys(matrix.categories)\n .map((key) => ({ key, domain: matrix.categories[key]?.domain }))\n .filter((c): c is { key: Category; domain: Domain } => c.domain !== undefined);\n\n const marketplaceDomains = new Set(\n categories.filter((c) => !customCategorySet.has(c.key)).map((c) => c.domain),\n );\n const customOnlyDomains = categories\n .filter((c) => customCategorySet.has(c.key))\n .map((c) => c.domain)\n .filter((domain) => !marketplaceDomains.has(domain));\n\n return new Set<string>([...customOnlyDomains, ...extraDomains]);\n}\n\nexport type ConfigTypesBackgroundData = {\n matrix: MergedSkillsMatrix;\n agentNames: AgentName[];\n customAgentNames: AgentName[];\n};\n\n/**\n * Kicks off background loading of the matrix and agents needed for config-types.ts regeneration.\n * Returns a promise that resolves with the loaded data. Callers should NOT await this immediately;\n * instead, pass the promise to `regenerateConfigTypes` after the main operation completes.\n *\n * @param sourceFlag Optional --source flag value\n * @param projectDir The project root directory\n */\nexport function loadConfigTypesDataInBackground(\n sourceFlag: string | undefined,\n projectDir: string,\n): Promise<ConfigTypesBackgroundData> {\n // Dynamic imports to avoid circular dependency issues at module load time\n const promise = (async (): Promise<ConfigTypesBackgroundData> => {\n const claudeSrcDir = path.join(projectDir, CLAUDE_SRC_DIR);\n if (!(await directoryExists(claudeSrcDir))) {\n throw new Error(`${CLAUDE_SRC_DIR}/ not found — run '${CLI_INVOKE_COMMAND} init' first`);\n }\n\n const { loadSkillsMatrixFromSource } = await import(\"../loading/source-loader\");\n const { loadMergedAgents } = await import(\"../loading/loader\");\n\n const sourceResult = await loadSkillsMatrixFromSource({\n sourceFlag,\n projectDir,\n skipExtraSources: true,\n });\n\n const allAgents = await loadMergedAgents(sourceResult.sourcePath);\n const agentNames = typedKeys<AgentName>(allAgents);\n const customAgentNames = agentNames.filter((name) => allAgents[name]?.custom === true);\n\n return { matrix: sourceResult.matrix, agentNames, customAgentNames };\n })();\n\n // Prevent unhandled rejection if the command exits before awaiting this promise\n promise.catch(() => {});\n\n return promise;\n}\n\n/**\n * Regenerates config-types.ts with the latest matrix data, merging in any extra entities\n * that were just created (e.g., a new skill or agent). Errors propagate to callers.\n *\n * @param projectDir The project root directory\n * @param backgroundData Promise from loadConfigTypesDataInBackground\n * @param extras Optional extra skill IDs or agent names to include (for just-created entities)\n */\nexport async function regenerateConfigTypes(\n projectDir: string,\n backgroundData: Promise<ConfigTypesBackgroundData>,\n extras?: ConfigTypesExtras,\n): Promise<void> {\n // The home directory's config-types.ts is the global pair's types half, which\n // only config-gate may write. Refusing here rather than leaving it to the\n // write primitive's tripwire names the offending entry point, and — unlike the\n // tripwire — survives a unit test that mocks `utils/fs`.\n if (isHomeDirectory(projectDir)) {\n throw new GlobalPairWriteViolation(\n path.join(projectDir, CLAUDE_SRC_DIR, STANDARD_FILES.CONFIG_TYPES_TS),\n );\n }\n\n const data = await backgroundData;\n\n const claudeSrcDir = path.join(projectDir, CLAUDE_SRC_DIR);\n\n // When a global installation exists and we're regenerating for a project,\n // generate a project config-types.ts that imports from the global one\n const isProjectScope = !isHomeDirectory(projectDir);\n const globalConfigTypes = isProjectScope ? await getGlobalConfigTypesPath() : null;\n const loadedConfig = await loadProjectConfigFromDir(projectDir);\n\n let source: string;\n if (globalConfigTypes) {\n const selectedAgentNames = loadedConfig?.config?.selectedAgents;\n const agents = loadedConfig?.config?.agents;\n const projectScopedAgentNames = agents ? activeProjectAgentNames(agents) : undefined;\n source = generateProjectConfigTypesSource({\n globalTypesImportPath: computeGlobalTypesImportPath(projectDir),\n projectSkillIds: extras?.extraSkillIds ?? [],\n projectAgentNames: extras?.extraAgentNames ?? [],\n projectDomains: extras?.extraDomains ?? [],\n projectCategories: extras?.extraCategories ?? [],\n ...(selectedAgentNames?.length ? { selectedAgentNames } : {}),\n ...(projectScopedAgentNames?.length ? { projectScopedAgentNames } : {}),\n });\n verbose(\"Using project config-types.ts that imports from global\");\n } else {\n // Narrowed to the config on disk, exactly as the wizard write path narrows the\n // standalone form. The full matrix is the fallback only when there is no config\n // to narrow to — a union covering every skill the source offers would declare\n // literals the sibling config.ts never installs, and `satisfies` would stop\n // catching a config that names one of them.\n source = generateConfigTypesSource(\n data.matrix,\n data.agentNames,\n data.customAgentNames,\n extras,\n loadedConfig?.config,\n );\n }\n\n const configTypesPath = path.join(claudeSrcDir, STANDARD_FILES.CONFIG_TYPES_TS);\n await writeFile(configTypesPath, source);\n verbose(`Regenerated ${STANDARD_FILES.CONFIG_TYPES_TS}`);\n}\n\n/**\n * Generates a config-types.ts source from marketplace data.\n * The generated file provides type safety for config.ts via `import type` + `satisfies`.\n *\n * @param customAgentNames Agent names that are custom (from sources with `custom: true`)\n * @param extras Optional extra skill IDs or agent names to include (for just-created entities)\n * @param config Optional ProjectConfig to narrow unions to only installed items.\n * When provided, SkillId/AgentName/Category/Domain are derived from\n * the config's skills[] and agents[] rather than the full matrix.\n */\nexport function generateConfigTypesSource(\n matrix: MergedSkillsMatrix,\n agentNames: AgentName[],\n customAgentNames: AgentName[] = [],\n extras?: ConfigTypesExtras,\n config?: ProjectConfig,\n): string {\n // Boundary cast: extra IDs from CLI args may not match strict union patterns\n const extraSkillIds = (extras?.extraSkillIds ?? []) as SkillId[];\n const extraAgentNamesArr = (extras?.extraAgentNames ?? []) as AgentName[];\n const extraDomainsArr = extras?.extraDomains ?? [];\n const extraCategoriesArr = (extras?.extraCategories ?? []) as Category[];\n\n let skillIds: SkillId[];\n let sortedAgents: AgentName[];\n let domains: string[];\n let categories: Category[];\n\n if (config) {\n // Narrow to only installed/configured items\n const configSkillIds = config.skills.map((s) => s.id);\n skillIds = unique([...configSkillIds, ...extraSkillIds]).sort();\n\n const configAgentNames = config.agents.map((a) => a.name);\n sortedAgents = unique([...configAgentNames, ...extraAgentNamesArr]).sort();\n\n // Derive categories from installed skills via matrix lookup\n const configCategories = deriveCategories(configSkillIds, matrix);\n categories = unique([...configCategories, ...extraCategoriesArr]).sort();\n\n // Derive domains from included categories via matrix lookup\n // Also include config.domains (user-selected domains) that may not have skills in this scope\n const configDomains = deriveDomains(categories, matrix);\n domains = unique([...configDomains, ...(config.domains ?? []), ...extraDomainsArr]).sort();\n } else {\n // Fall back to full matrix (e.g., blank global config)\n skillIds = unique([...typedKeys(matrix.skills), ...extraSkillIds]).sort();\n sortedAgents = unique([...agentNames, ...extraAgentNamesArr]).sort();\n domains = unique([...extractDomains(matrix), ...extraDomainsArr]).sort();\n categories = unique([...typedKeys(matrix.categories), ...extraCategoriesArr]).sort();\n }\n\n // Determine which skills are custom\n const customSkillSet = new Set<SkillId>([\n ...extraSkillIds,\n ...typedKeys(matrix.skills).filter((id) => matrix.skills[id]?.custom === true),\n ]);\n\n // Determine which agents are custom\n const customAgentSet = new Set<AgentName>([...customAgentNames, ...extraAgentNamesArr]);\n\n // Determine which categories are custom (referenced by custom skills or passed as extras)\n const customCategorySet = new Set<Category>([\n ...extraCategoriesArr,\n ...typedKeys(matrix.skills)\n .map((id) => matrix.skills[id])\n .filter((skill): skill is ResolvedSkill => skill?.custom === true)\n .map((skill) => skill.category)\n .filter(isNonLocalCategory),\n ]);\n\n const customDomainSet = collectCustomDomains(matrix, customCategorySet, extraDomainsArr);\n\n const skillIdLine = formatMaybeSectionedUnion(skillIds, (id) => customSkillSet.has(id));\n const agentNameLine = formatMaybeSectionedUnion(sortedAgents, (name) => customAgentSet.has(name));\n const domainLine = formatMaybeSectionedUnion(domains, (d) => customDomainSet.has(d));\n const categoryLine = formatMaybeSectionedUnion(categories, (s) => customCategorySet.has(s));\n\n const selectedAgentNameLine = config?.selectedAgents?.length\n ? formatUnion(config.selectedAgents)\n : \"AgentName\";\n\n const projectScopedAgents = config?.agents ? activeProjectAgentNames(config.agents) : [];\n const projectAgentNameLine =\n projectScopedAgents.length > 0 ? formatUnion(projectScopedAgents) : \"SelectedAgentName\";\n\n const skillsByCategory = buildSkillsByCategory(skillIds, categories, matrix);\n const stackAgentConfigType = generateStackAgentConfig(skillsByCategory, matrix);\n\n return assembleConfigTypesSource({\n skillId: skillIdLine,\n agentName: agentNameLine,\n selectedAgentName: selectedAgentNameLine,\n projectAgentName: projectAgentNameLine,\n domain: domainLine,\n category: categoryLine,\n stackAgentConfig: stackAgentConfigType,\n });\n}\n\n// Sorted deriveDomains over every category — kept separate: this is the full-matrix domain\n// union for the standalone types file, not a per-selection derivation.\nfunction extractDomains(matrix: MergedSkillsMatrix): string[] {\n return deriveDomains(typedKeys(matrix.categories), matrix).sort();\n}\n\n/**\n * Derives the set of categories that the given skill IDs belong to,\n * by looking up each skill's category in the matrix.\n */\n/** Category present and not the \"local\" pseudo-category. */\nconst isNonLocalCategory = (category: CategoryPath | undefined): category is Category =>\n Boolean(category) && category !== LOCAL_PSEUDO_CATEGORY;\n\nexport function deriveCategories(skillIds: SkillId[], matrix: MergedSkillsMatrix): Category[] {\n return unique(\n skillIds\n .map((id) => matrix.skills[id]?.category)\n // Boundary cast: CategoryPath to Category for matrix key lookup\n .filter(isNonLocalCategory),\n );\n}\n\n/**\n * Derives the set of domains that the given categories belong to,\n * by looking up each category's domain in the matrix.\n */\nexport function deriveDomains(categories: Category[], matrix: MergedSkillsMatrix): string[] {\n return unique(\n categories\n .map((cat) => matrix.categories[cat]?.domain)\n .filter((domain): domain is Domain => domain !== undefined),\n );\n}\n\n/**\n * Renders a union type with optional // Custom and // Marketplace section comments.\n * If all members are in one group, only that group's header is shown.\n * If both groups exist, renders with section comments and always uses multi-line format.\n */\nfunction formatSectionedUnion(custom: string[], marketplace: string[]): string {\n if (custom.length === 0 && marketplace.length === 0) {\n return EMPTY_UNION_TYPE;\n }\n\n // Only one group present: show single header\n if (marketplace.length === 0) {\n const lines = custom.map((m) => ` | \"${m}\"`);\n return \"\\n // Custom\\n\" + lines.join(\"\\n\");\n }\n if (custom.length === 0) {\n const lines = marketplace.map((m) => ` | \"${m}\"`);\n return \"\\n // Marketplace\\n\" + lines.join(\"\\n\");\n }\n\n // Both groups: custom first, then marketplace\n const customLines = custom.map((m) => ` | \"${m}\"`);\n const marketplaceLines = marketplace.map((m) => ` | \"${m}\"`);\n return (\n \"\\n // Custom\\n\" +\n customLines.join(\"\\n\") +\n \"\\n // Marketplace\\n\" +\n marketplaceLines.join(\"\\n\")\n );\n}\n\n/**\n * Formats a union, using section comments when custom members exist,\n * or plain formatUnion when there are no custom members.\n */\nfunction formatMaybeSectionedUnion<T extends string>(\n members: T[],\n isCustom: (member: T) => boolean,\n): string {\n if (members.length === 0) {\n return EMPTY_UNION_TYPE;\n }\n\n const custom = members.filter(isCustom);\n const marketplace = members.filter((m) => !isCustom(m));\n\n // No custom members: use standard formatting (preserves single-line for small unions)\n if (custom.length === 0) {\n return formatUnion(members);\n }\n\n return formatSectionedUnion(custom, marketplace);\n}\n\nfunction formatUnion(members: string[]): string {\n if (members.length === 0) {\n return EMPTY_UNION_TYPE;\n }\n\n const quoted = members.map((m) => `\"${m}\"`);\n\n if (quoted.length < MULTI_LINE_THRESHOLD) {\n return quoted.join(\" | \");\n }\n\n return \"\\n\" + quoted.map((q) => ` | ${q}`).join(\"\\n\");\n}\n\nexport type ProjectConfigTypesOptions = {\n /**\n * Absolute path to the global .claude-src directory.\n * When set, generates import statements that extend global types.\n */\n globalTypesImportPath: string;\n /** Project-only skill IDs (not including global) */\n projectSkillIds: string[];\n /** Project-only agent names (not including global) */\n projectAgentNames: string[];\n /** Project-only domains (not including global) */\n projectDomains: string[];\n /** Project-only categories (not including global) */\n projectCategories?: string[];\n /** Selected agent names from config (narrows SelectedAgentName) */\n selectedAgentNames?: string[];\n /** Project-scoped agent names (narrows ProjectAgentName for stack keys) */\n projectScopedAgentNames?: string[];\n};\n\n/**\n * Generates a project config-types.ts source that imports global types and extends them.\n * Each type union is `GlobalType | \"project-item-1\" | \"project-item-2\"`.\n * When projectCategories are provided, Category extends GlobalCategory instead of being `string`.\n */\nexport function generateProjectConfigTypesSource(options: ProjectConfigTypesOptions): string {\n const importPath = `${options.globalTypesImportPath}/config-types`;\n\n const skillIdUnion = formatExtendedUnion(\"GlobalSkillId\", options.projectSkillIds);\n const agentNameUnion = formatExtendedUnion(\"GlobalAgentName\", options.projectAgentNames);\n const domainUnion = formatExtendedUnion(\"GlobalDomain\", options.projectDomains);\n\n const projectCategories = options.projectCategories ?? [];\n const categoryUnion =\n projectCategories.length > 0\n ? formatExtendedUnion(\"GlobalCategory\", projectCategories)\n : \"GlobalCategory\";\n\n const selectedAgentNameUnion = options.selectedAgentNames?.length\n ? formatUnion(options.selectedAgentNames)\n : \"AgentName\";\n\n const projectAgentNameUnion = options.projectScopedAgentNames?.length\n ? formatUnion(options.projectScopedAgentNames)\n : \"SelectedAgentName\";\n\n // Import Category as GlobalCategory when we have project categories or need to re-export it\n const categoryImport = ` Category as GlobalCategory,\\n`;\n\n const importBlock = `import type {\n SkillId as GlobalSkillId,\n AgentName as GlobalAgentName,\n Domain as GlobalDomain,\n${categoryImport}} from \"${importPath}\";`;\n\n return assembleConfigTypesSource({\n importBlock,\n skillId: skillIdUnion,\n agentName: agentNameUnion,\n selectedAgentName: selectedAgentNameUnion,\n projectAgentName: projectAgentNameUnion,\n domain: domainUnion,\n category: categoryUnion,\n stackAgentConfig: STACK_AGENT_CONFIG_LOOSE_LINE,\n });\n}\n\n/**\n * Formats a union that extends a global type alias.\n * Returns `GlobalType` when no project members exist, or `GlobalType | \"a\" | \"b\"` with members.\n */\nfunction formatExtendedUnion(globalTypeName: string, projectMembers: string[]): string {\n if (projectMembers.length === 0) {\n return globalTypeName;\n }\n\n const sorted = [...projectMembers].sort();\n const quoted = sorted.map((m) => `\"${m}\"`);\n\n if (quoted.length < MULTI_LINE_THRESHOLD) {\n return `${globalTypeName} | ${quoted.join(\" | \")}`;\n }\n\n return `\\n | ${globalTypeName}\\n` + quoted.map((q) => ` | ${q}`).join(\"\\n\");\n}\n","import { isDeepEqual } from \"remeda\";\nimport type { AgentName, ProjectConfig, SkillId } from \"../../types\";\nimport type { AgentScopeConfig, SkillConfig } from \"../../types/config\";\n\n/**\n * The work one global config write owes, decided from what actually moved\n * between the config on disk and the config being written.\n *\n * T1 — the generated type unions or the compiled agents are derived from what\n * changed: rewrite both halves of the pair, propagate to every registered\n * project, recompile those projects' agents.\n * T2 — a scalar the unions do not encode changed. Project configs inline the\n * global scalars verbatim, so the config half propagates; no union moves,\n * so no types are regenerated and no agent is recompiled.\n * T3 — only the `projects[]` registration list changed. Nothing is propagated,\n * and the matrix / agent definitions propagation would need are never\n * loaded.\n * T4 — nothing moved. No file is touched.\n */\nexport type ConsequenceTier = \"T1\" | \"T2\" | \"T3\" | \"T4\";\n\nexport type GlobalChangeSet = {\n skills: {\n added: SkillId[];\n removed: SkillId[];\n /**\n * Ids whose `source` moved. Separate from `otherChanged` because the\n * per-skill source decides the reference form a compiled agent emits\n * (`<id>:<id>` for a marketplace-sourced skill, the bare id for an ejected\n * one), so a source change that skipped the recompile leaves every\n * registered project's agents naming a reference that no longer resolves.\n */\n sourceChanged: SkillId[];\n otherChanged: SkillId[];\n };\n agents: {\n added: AgentName[];\n removed: AgentName[];\n changed: AgentName[];\n };\n stackChanged: boolean;\n domainsChanged: boolean;\n selectedAgentsChanged: boolean;\n /** Names of the inlined scalar fields that moved, in config key order. */\n scalarsChanged: string[];\n projectsChanged: boolean;\n};\n\n/** The identity element of {@link GlobalChangeSet} — nothing moved, so T4. */\nexport const NO_CHANGES: GlobalChangeSet = {\n skills: { added: [], removed: [], sourceChanged: [], otherChanged: [] },\n agents: { added: [], removed: [], changed: [] },\n stackChanged: false,\n domainsChanged: false,\n selectedAgentsChanged: false,\n scalarsChanged: [],\n projectsChanged: false,\n};\n\n/** The five fields the config writer extracts into typed named variables. */\nconst EXTRACTED_FIELDS = new Set([\"skills\", \"agents\", \"stack\", \"domains\", \"selectedAgents\"]);\n\n/** The registration list — bookkeeping, never emitted into a project config. */\nconst REGISTRATION_FIELD = \"projects\";\n\n/**\n * Normalizes a config the way the writer does immediately before emission: a\n * JSON round-trip, so an explicitly-`undefined` field and an absent one compare\n * equal. Without it every write that merely reconstructs an object produces\n * phantom diffs.\n */\nfunction normalize(config: ProjectConfig): Record<string, unknown> {\n return JSON.parse(JSON.stringify(config));\n}\n\n/** Field value as the writer would emit it, or undefined when absent. */\nfunction field(config: Record<string, unknown>, key: string): unknown {\n return config[key];\n}\n\nfunction skillsById(config: Record<string, unknown>): Map<SkillId, SkillConfig> {\n const skills = (config.skills ?? []) as SkillConfig[];\n return new Map(skills.map((skill) => [skill.id, skill]));\n}\n\nfunction agentsByName(config: Record<string, unknown>): Map<AgentName, AgentScopeConfig> {\n const agents = (config.agents ?? []) as AgentScopeConfig[];\n return new Map(agents.map((agent) => [agent.name, agent]));\n}\n\n/** The scalar keys either side carries, in `next`-first order with `prev` extras appended. */\nfunction scalarKeys(prev: Record<string, unknown>, next: Record<string, unknown>): string[] {\n const isScalarKey = (key: string): boolean =>\n !EXTRACTED_FIELDS.has(key) && key !== REGISTRATION_FIELD;\n const nextKeys = Object.keys(next).filter(isScalarKey);\n const extraPrevKeys = Object.keys(prev).filter(\n (key) => isScalarKey(key) && !nextKeys.includes(key),\n );\n return [...nextKeys, ...extraPrevKeys];\n}\n\nfunction diffSkills(\n prev: Record<string, unknown>,\n next: Record<string, unknown>,\n): GlobalChangeSet[\"skills\"] {\n const before = skillsById(prev);\n const after = skillsById(next);\n\n const added = [...after.keys()].filter((id) => !before.has(id));\n const removed = [...before.keys()].filter((id) => !after.has(id));\n\n const sourceChanged: SkillId[] = [];\n const otherChanged: SkillId[] = [];\n for (const [id, afterEntry] of after) {\n const beforeEntry = before.get(id);\n if (!beforeEntry || isDeepEqual(beforeEntry, afterEntry)) continue;\n if (beforeEntry.source !== afterEntry.source) sourceChanged.push(id);\n else otherChanged.push(id);\n }\n\n return { added, removed, sourceChanged, otherChanged };\n}\n\nfunction diffAgents(\n prev: Record<string, unknown>,\n next: Record<string, unknown>,\n): GlobalChangeSet[\"agents\"] {\n const before = agentsByName(prev);\n const after = agentsByName(next);\n\n return {\n added: [...after.keys()].filter((name) => !before.has(name)),\n removed: [...before.keys()].filter((name) => !after.has(name)),\n changed: [...after.keys()].filter((name) => {\n const beforeEntry = before.get(name);\n return beforeEntry !== undefined && !isDeepEqual(beforeEntry, after.get(name));\n }),\n };\n}\n\n/**\n * Diffs the config on disk against the config about to be written. `prev` is\n * undefined when no global config exists yet, which every field reads as a\n * change from absent.\n */\nexport function classifyGlobalChange(\n prev: ProjectConfig | undefined,\n next: ProjectConfig,\n): GlobalChangeSet {\n const before = prev ? normalize(prev) : {};\n const after = normalize(next);\n\n return {\n skills: diffSkills(before, after),\n agents: diffAgents(before, after),\n stackChanged: !isDeepEqual(field(before, \"stack\"), field(after, \"stack\")),\n domainsChanged: !isDeepEqual(field(before, \"domains\"), field(after, \"domains\")),\n selectedAgentsChanged: !isDeepEqual(\n field(before, \"selectedAgents\"),\n field(after, \"selectedAgents\"),\n ),\n scalarsChanged: scalarKeys(before, after).filter(\n (key) => !isDeepEqual(field(before, key), field(after, key)),\n ),\n projectsChanged: !isDeepEqual(\n field(before, REGISTRATION_FIELD),\n field(after, REGISTRATION_FIELD),\n ),\n };\n}\n\n/** True when something the type unions or the compiled agents derive from moved. */\nfunction movesTypesOrCompiledAgents(changes: GlobalChangeSet): boolean {\n const { skills, agents } = changes;\n return (\n skills.added.length > 0 ||\n skills.removed.length > 0 ||\n skills.sourceChanged.length > 0 ||\n skills.otherChanged.length > 0 ||\n agents.added.length > 0 ||\n agents.removed.length > 0 ||\n agents.changed.length > 0 ||\n changes.stackChanged ||\n changes.domainsChanged ||\n changes.selectedAgentsChanged\n );\n}\n\n/** The work tier a change set obliges. */\nexport function consequenceTier(changes: GlobalChangeSet): ConsequenceTier {\n if (movesTypesOrCompiledAgents(changes)) return \"T1\";\n if (changes.scalarsChanged.length > 0) return \"T2\";\n if (changes.projectsChanged) return \"T3\";\n return \"T4\";\n}\n\n/** True when the tier's consequences need the matrix and agent definitions. */\nexport function tierNeedsDeps(tier: ConsequenceTier): boolean {\n return tier === \"T1\" || tier === \"T2\";\n}\n\n/** True when the tier regenerates the types half and recompiles propagated agents. */\nexport function tierRegeneratesTypes(tier: ConsequenceTier): boolean {\n return tier === \"T1\";\n}\n\n/** True when the tier fans the change out to every registered project. */\nexport function tierPropagates(tier: ConsequenceTier): boolean {\n return tier === \"T1\" || tier === \"T2\";\n}\n","import type { AgentDefinition, AgentName, MergedSkillsMatrix } from \"../../types\";\nimport { tierNeedsDeps, tierRegeneratesTypes, type ConsequenceTier } from \"./classify.js\";\n\n/** The matrix and agent definitions propagation and type generation read. */\nexport type LoadedGateDeps = {\n matrix: MergedSkillsMatrix;\n agents: Record<AgentName, AgentDefinition>;\n};\n\n/**\n * What a gate entry needs to carry out a write's consequences.\n *\n * The lazy form exists so a caller that cannot cheaply produce the matrix — an\n * offline uninstall, a deregistration — hands over loaders instead. Whether they\n * run is decided by classification: a registration-only or no-op write has no\n * consequences to carry out, so nothing is loaded and the write stays offline.\n */\nexport type GateDeps =\n | LoadedGateDeps\n | {\n loadMatrix: () => Promise<MergedSkillsMatrix>;\n loadAgents: () => Promise<Record<AgentName, AgentDefinition>>;\n };\n\nfunction isLoaded(deps: GateDeps): deps is LoadedGateDeps {\n return \"matrix\" in deps;\n}\n\n/**\n * Resolves `deps` only when `tier` has consequences that read them. Returns null\n * otherwise, and the lazy loaders are never called.\n */\nexport async function resolveGateDeps(\n deps: GateDeps,\n tier: ConsequenceTier,\n): Promise<LoadedGateDeps | null> {\n if (!tierNeedsDeps(tier)) return null;\n if (isLoaded(deps)) return deps;\n\n // Agent definitions are read only where the types half is regenerated, so a\n // config-half-only tier never pays for loading them.\n const [matrix, agents] = await Promise.all([\n deps.loadMatrix(),\n tierRegeneratesTypes(tier) ? deps.loadAgents() : NO_AGENTS,\n ]);\n return { matrix, agents };\n}\n\n/** Agent definitions a tier that regenerates no types never reads. */\nconst NO_AGENTS = Promise.resolve({} as Record<AgentName, AgentDefinition>);\n","import os from \"os\";\nimport path from \"path\";\nimport type { AgentDefinition, AgentName, MergedSkillsMatrix, ProjectConfig } from \"../../types\";\nimport { CLAUDE_SRC_DIR, STANDARD_FILES } from \"../../consts\";\nimport { ensureDir, fileExists, readFile, writeFile } from \"../../utils/fs\";\nimport { verbose } from \"../../utils/logger\";\nimport { typedKeys } from \"../../utils/typed-object\";\nimport {\n generateBlankGlobalConfigSource,\n generateBlankGlobalConfigTypesSource,\n generateConfigSource,\n} from \"../configuration/config-writer\";\nimport {\n generateConfigTypesSource,\n type ConfigTypesBackgroundData,\n type ConfigTypesExtras,\n} from \"../configuration/config-types-writer\";\nimport { assertGateToken } from \"./gate-token.js\";\n\n/**\n * Nothing in this module MINTS the write privilege — every function below\n * REQUIRES it, and `writeIfChanged` is where that requirement is asserted. The\n * token is opened by the gate's public entry points in `index.ts`, each of which\n * wraps its whole consequence flow.\n *\n * That split is the point (D-309): a callee that opens the privilege on its own\n * behalf hands it to whoever reached it, so a caller that got past module\n * privacy — a dynamic import, a re-export added for convenience — arrived\n * already authorized and the runtime tripwire in `utils/fs.ts` waved it through.\n * Requiring the token instead makes reaching the private writer useless on its\n * own: the privilege belongs to the entry points, not to the writers.\n */\n\n/** Absolute paths of the two halves of the global config pair. */\nexport type GlobalPairPaths = {\n configPath: string;\n typesPath: string;\n};\n\n/**\n * Resolves the global pair's paths. `os.homedir()` at call time, not the\n * module-load-time `GLOBAL_INSTALL_ROOT`, so the paths agree with every other\n * runtime home-dir reader and with test home mocks.\n */\nexport function globalPairPaths(): GlobalPairPaths {\n const dir = path.join(os.homedir(), CLAUDE_SRC_DIR);\n return {\n configPath: path.join(dir, STANDARD_FILES.CONFIG_TS),\n typesPath: path.join(dir, STANDARD_FILES.CONFIG_TYPES_TS),\n };\n}\n\n/** The types sibling of a config path — the two always share a directory. */\nexport function typesPathFor(configPath: string): string {\n return path.join(path.dirname(configPath), STANDARD_FILES.CONFIG_TYPES_TS);\n}\n\n/**\n * Writes `source` to `filePath` unless the file already holds exactly those\n * bytes. Both halves are derived from the same config on every write, so pair\n * coherence holds by derivation and the comparison only suppresses the mtime\n * churn a projects-only or scalar-only change would otherwise inflict on every\n * consumer watching these files. Returns true when the file was written.\n */\nasync function writeIfChanged(filePath: string, source: string): Promise<boolean> {\n assertGateToken(filePath);\n if ((await fileExists(filePath)) && (await readFile(filePath)) === source) return false;\n await writeFile(filePath, source);\n return true;\n}\n\n/** The union inputs the types writer derives its literals from. */\nfunction typesDataFor(\n matrix: MergedSkillsMatrix,\n agents: Record<AgentName, AgentDefinition>,\n): ConfigTypesBackgroundData {\n const agentNames = typedKeys(agents);\n return {\n matrix,\n agentNames,\n customAgentNames: agentNames.filter((name) => agents[name]?.custom === true),\n };\n}\n\n/**\n * Standalone (non-importing) type unions narrowed to `config`'s own entries,\n * widened by `extras` — the literals a just-created skill or agent needs before\n * it reaches the config.\n */\nfunction renderStandaloneTypes(\n config: ProjectConfig,\n matrix: MergedSkillsMatrix,\n agents: Record<AgentName, AgentDefinition>,\n extras?: ConfigTypesExtras,\n): string {\n const data = typesDataFor(matrix, agents);\n return generateConfigTypesSource(\n data.matrix,\n data.agentNames,\n data.customAgentNames,\n extras,\n config,\n );\n}\n\n/**\n * Writes the config half of the pair at `configPath`. The global config never\n * takes the project writer's import/inline options — it is the file those\n * options resolve against.\n */\nexport async function writeGlobalConfigHalf(\n config: ProjectConfig,\n configPath: string,\n): Promise<boolean> {\n return writeIfChanged(configPath, generateConfigSource(config));\n}\n\n/** Writes the types half of the pair beside `configPath`. */\nexport async function writeGlobalTypesHalf(\n config: ProjectConfig,\n configPath: string,\n matrix: MergedSkillsMatrix,\n agents: Record<AgentName, AgentDefinition>,\n extras?: ConfigTypesExtras,\n): Promise<boolean> {\n return writeIfChanged(\n typesPathFor(configPath),\n renderStandaloneTypes(config, matrix, agents, extras),\n );\n}\n\n/**\n * Writes the types half beside `configPath` from union inputs a caller already\n * loaded in the background, rather than from a matrix plus agent definitions.\n *\n * `config` narrows the unions to what that config installs and is optional\n * because the caller reads it off disk, where it may be absent — a scaffolded\n * marketplace has no config until this run writes one. Absent, the unions cover\n * the whole matrix, which is what the raw writer has always fallen back to.\n */\nexport async function writeGlobalTypesHalfFromData(\n configPath: string,\n data: ConfigTypesBackgroundData,\n config: ProjectConfig | undefined,\n extras?: ConfigTypesExtras,\n): Promise<boolean> {\n return writeIfChanged(\n typesPathFor(configPath),\n generateConfigTypesSource(data.matrix, data.agentNames, data.customAgentNames, extras, config),\n );\n}\n\n/** Writes both halves from one config, so they cannot disagree. */\nexport async function writeGlobalPair(\n config: ProjectConfig,\n configPath: string,\n matrix: MergedSkillsMatrix,\n agents: Record<AgentName, AgentDefinition>,\n): Promise<boolean> {\n const configWritten = await writeIfChanged(configPath, generateConfigSource(config));\n const typesWritten = await writeIfChanged(\n typesPathFor(configPath),\n renderStandaloneTypes(config, matrix, agents),\n );\n return configWritten || typesWritten;\n}\n\n/**\n * Creates a blank global pair at `~/.claude-src/` when none exists: `config.ts`\n * with empty arrays and `config-types.ts` with `never` unions. Returns true when\n * the files were created, false when they already existed.\n */\nexport async function ensureBlankPair(): Promise<boolean> {\n const { configPath, typesPath } = globalPairPaths();\n\n if (await fileExists(configPath)) {\n verbose(\"Global config already exists, skipping blank creation\");\n return false;\n }\n\n await ensureDir(path.dirname(configPath));\n\n await writeIfChanged(configPath, generateBlankGlobalConfigSource());\n await writeIfChanged(typesPath, generateBlankGlobalConfigTypesSource());\n\n verbose(`Created blank global config at ${path.dirname(configPath)}`);\n return true;\n}\n","import fs from \"fs\";\nimport os from \"os\";\nimport { isDeepEqual, unique } from \"remeda\";\nimport type {\n AgentDefinition,\n AgentName,\n Category,\n MergedSkillsMatrix,\n ProjectConfig,\n SkillAssignment,\n SkillId,\n StackAgentConfig,\n} from \"../../types\";\nimport type { AgentScopeConfig, SkillConfig } from \"../../types/config\";\nimport { getProjectConfigPath } from \"../installation/install-base-dir\";\nimport { loadProjectConfigFromDir } from \"../configuration/project-config\";\nimport {\n activeProjectAgentNames,\n isActiveAt,\n isGlobalTombstone,\n type ScopedEntry,\n} from \"../configuration/scope-predicates\";\nimport { generateConfigSource, type ConfigSourceOptions } from \"../configuration/config-writer\";\nimport {\n type ConfigTypesBackgroundData,\n type ConfigTypesExtras,\n deriveCategories,\n deriveDomains,\n regenerateConfigTypes,\n} from \"../configuration/config-types-writer\";\nimport { fileExists, writeFile } from \"../../utils/fs\";\nimport { getErrorMessage } from \"../../utils/errors\";\nimport { verbose } from \"../../utils/logger\";\nimport { typedEntries, typedKeys } from \"../../utils/typed-object\";\nimport { GLOBAL_CONFIG_NAME, LOCAL_PSEUDO_CATEGORY } from \"../../consts\";\n\nexport async function writeConfigFile(\n config: ProjectConfig,\n configPath: string,\n options?: ConfigSourceOptions,\n): Promise<void> {\n const source = generateConfigSource(config, options);\n await writeFile(configPath, source);\n}\n\n/**\n * Deep-additive stack merge: appends any (agent, category, skill) triple present in\n * `incoming` but missing in `existing`. Never removes or overwrites existing entries\n * (including their `preloaded` flags). Returns a fresh stack object — inputs are not\n * mutated. `changed` is true iff at least one new agent, category, or skill assignment\n * was appended.\n */\nfunction additiveMergeStack(\n existing: Partial<Record<AgentName, StackAgentConfig>> | undefined,\n incoming: Partial<Record<AgentName, StackAgentConfig>> | undefined,\n): { stack: Partial<Record<AgentName, StackAgentConfig>>; changed: boolean } {\n const merged: Partial<Record<AgentName, StackAgentConfig>> = existing\n ? structuredClone(existing)\n : {};\n if (!incoming) return { stack: merged, changed: false };\n\n let changed = false;\n for (const [agentName, incomingAgentStack] of typedEntries<AgentName, StackAgentConfig>(\n incoming,\n )) {\n if (!incomingAgentStack) continue;\n\n const existingAgentStack = merged[agentName];\n if (!existingAgentStack) {\n merged[agentName] = structuredClone(incomingAgentStack);\n changed = true;\n continue;\n }\n\n if (mergeAgentCategories(existingAgentStack, incomingAgentStack)) {\n changed = true;\n }\n }\n\n return { stack: merged, changed };\n}\n\n/**\n * Mutates `existingAgentStack` in place by appending any category or skill assignment\n * from `incomingAgentStack` that is not already present. Returns true if anything was\n * appended. Caller must pass a cloned `existingAgentStack` — this function is only\n * called on the merged copy, never on the original input.\n */\nfunction mergeAgentCategories(\n existingAgentStack: StackAgentConfig,\n incomingAgentStack: StackAgentConfig,\n): boolean {\n let changed = false;\n for (const [category, incomingAssignments] of typedEntries<Category, SkillAssignment[]>(\n incomingAgentStack,\n )) {\n if (!incomingAssignments) continue;\n\n const existingAssignments = existingAgentStack[category];\n if (!existingAssignments) {\n existingAgentStack[category] = incomingAssignments.map((a) => ({ ...a }));\n changed = true;\n continue;\n }\n\n const existingIds = new Set(existingAssignments.map((a) => a.id));\n for (const assignment of incomingAssignments) {\n if (!existingIds.has(assignment.id)) {\n existingAssignments.push({ ...assignment });\n existingIds.add(assignment.id);\n changed = true;\n }\n }\n }\n return changed;\n}\n\n/**\n * Merges new global-scoped items into an existing global config.\n * Adds skills/agents that don't already exist. Never removes existing items.\n *\n * Exported for unit testing. See `mergeGlobalConfigs` describe block in\n * `local-installer.test.ts`.\n */\nexport function mergeGlobalConfigs(\n existing: ProjectConfig,\n incoming: ProjectConfig,\n): { config: ProjectConfig; changed: boolean } {\n const existingSkillIds = new Set(existing.skills.map((s) => s.id));\n const existingAgentNames = new Set(existing.agents.map((a) => a.name));\n\n const incomingActiveSkills = incoming.skills.filter((s) => !s.excluded);\n const incomingActiveAgents = incoming.agents.filter((a) => !a.excluded);\n const newSkills = incomingActiveSkills.filter((s) => !existingSkillIds.has(s.id));\n const newAgents = incomingActiveAgents.filter((a) => !existingAgentNames.has(a.name));\n\n const mergedSkills = [...existing.skills, ...newSkills];\n const mergedAgents = [...existing.agents, ...newAgents];\n\n // Per-agent stack merge policy: deep-additive. Project-context edits must NEVER remove\n // or overwrite global state; individual projects express their local view via tombstones\n // in the PROJECT config, not by rewriting the GLOBAL config (see commit 403df46:\n // \"never modify global config from project-level operations\").\n //\n // Merge rule per triple (agent, category, skill):\n // - agent absent in existing -> add from incoming\n // - category absent in existing -> add from incoming\n // - skill id absent in existing -> append from incoming\n // - everything already present -> keep existing as-is (including its preloaded flag)\n // Anything present only in `existing` is left untouched.\n const { stack: mergedStack, changed: stackChanged } = additiveMergeStack(\n existing.stack,\n incoming.stack,\n );\n\n // Merge domains and selectedAgents (union, no duplicates)\n const mergedDomains = [...new Set([...(existing.domains ?? []), ...(incoming.domains ?? [])])];\n const mergedSelectedAgents = [\n ...new Set([...(existing.selectedAgents ?? []), ...(incoming.selectedAgents ?? [])]),\n ];\n\n // Source identity (`marketplace`, `source`) travels on the global partition of\n // `splitConfigByScope` but was previously lost here, leaving the global config with no\n // record of where its plugins came from. `uninstall` reads `config.marketplace` to build\n // the `<id>@<marketplace>` registry key (getCliInstalledPluginKeys) — without it a global\n // uninstall silently owns nothing and leaves registered plugins behind.\n //\n // Precedence is FILL-ONLY: existing wins, incoming is used solely when the global config\n // has no value yet. Both fields are scalar but the merged config is multi-marketplace by\n // construction — this merge never removes skills, so after a second project init from a\n // different marketplace the skills array holds plugins from BOTH, and whichever label is\n // recorded orphans the other's registry key. Repointing is therefore never a strict\n // improvement, and doing it from a project context would silently rewrite global state on\n // behalf of every other registered project (commit 403df46). This also matches\n // `mergeConfigs`, which preserves `existingConfig.marketplace` on the home-root install\n // path. Changing global source identity stays an explicit global-scope operation\n // (`init` run from ~), which writes the global config directly and bypasses this merge.\n const mergedMarketplace = existing.marketplace ?? incoming.marketplace;\n const mergedSource = existing.source ?? incoming.source;\n\n // Newly-filled source identity must mark the merge dirty: `needsGlobalWrite` is gated on\n // this flag, so a run whose only delta is the now-known marketplace would otherwise skip\n // the global write entirely and drop the field again.\n const changed =\n newSkills.length > 0 ||\n newAgents.length > 0 ||\n stackChanged ||\n !isDeepEqual(existing.domains ?? [], mergedDomains) ||\n !isDeepEqual(existing.selectedAgents ?? [], mergedSelectedAgents) ||\n mergedMarketplace !== existing.marketplace ||\n mergedSource !== existing.source;\n\n return {\n config: {\n ...existing,\n skills: mergedSkills,\n agents: mergedAgents,\n stack: mergedStack,\n domains: mergedDomains,\n selectedAgents: mergedSelectedAgents,\n marketplace: mergedMarketplace,\n source: mergedSource,\n },\n changed,\n };\n}\n\n/**\n * The single normalization for every value compared against the global config's\n * `projects` array — the one written by {@link registerProjectPath}, the one\n * filtered by {@link deregisterProjectPath}, and the current-project skip in\n * {@link propagateGlobalChangesToProjects}. Symlinks are resolved, so an entry\n * stored under one of them matches byte-for-byte under the others. The two ends\n * normalizing differently is what left symlinked layouts (macOS `/tmp`, a\n * `~/dev/repo` pointing at `/data/repo`) registered forever after an uninstall.\n *\n * Throws when the directory does not exist. That is deliberate: a path that\n * cannot be resolved is an error, not a cue to fall back to a weaker\n * normalization — a second tier would reintroduce exactly the asymmetry this\n * helper exists to remove. The one caller that must survive it (`uninstall`'s\n * deregistration) already wraps the call in a warn-and-continue guard.\n */\nexport function normalizeProjectPath(projectDir: string): string {\n return fs.realpathSync(projectDir);\n}\n\n/**\n * Registers a project directory in the global config's `projects` array.\n * Paths are normalized via {@link normalizeProjectPath} to resolve symlinks.\n * Filters stale entries (where .claude-src/config.ts no longer exists).\n */\nasync function registerProjectPath(\n globalConfig: ProjectConfig,\n projectDir: string,\n): Promise<{ config: ProjectConfig; changed: boolean }> {\n const normalizedPath = normalizeProjectPath(projectDir);\n const existing = globalConfig.projects ?? [];\n\n // Filter stale entries\n const staleChecks = await Promise.all(\n existing.map(async (p) => ({\n path: p,\n hasConfig: await fileExists(getProjectConfigPath(p)),\n })),\n );\n const valid = staleChecks.filter((c) => c.hasConfig).map((c) => c.path);\n\n if (valid.includes(normalizedPath)) {\n const changed = valid.length !== existing.length;\n return { config: changed ? { ...globalConfig, projects: valid } : globalConfig, changed };\n }\n\n return { config: { ...globalConfig, projects: [...valid, normalizedPath] }, changed: true };\n}\n\n/**\n * Removes a project directory from the global config's `projects` array.\n * Loads global config, removes the path, and writes back if changed.\n * Paths are normalized via {@link normalizeProjectPath} — the same rule\n * {@link registerProjectPath} stored them under, so the filter matches.\n *\n * REQUIRES the gate's write token; it does not mint one (D-309). No production\n * path reaches this — `mutateGlobal`'s `deregister-project` variant replaced it\n * at the only call site — so there is no entry point to move the mint up to, and\n * private code opening the privilege for its own caller is exactly what D-309\n * closed. Its remaining callers are specs, which take the token explicitly the\n * same way they do to seed a global-pair fixture.\n */\nexport async function deregisterProjectPath(projectDir: string): Promise<void> {\n const homeDir = os.homedir();\n const existingGlobal = await loadProjectConfigFromDir(homeDir);\n if (!existingGlobal?.config?.projects?.length) return;\n\n const normalizedPath = normalizeProjectPath(projectDir);\n const filtered = existingGlobal.config.projects.filter((p) => p !== normalizedPath);\n\n if (filtered.length === existingGlobal.config.projects.length) return;\n\n const updatedConfig = { ...existingGlobal.config, projects: filtered };\n const globalConfigPath = getProjectConfigPath(homeDir);\n // The one write in this module that targets the global pair rather than a\n // project's, so the one the caller's token has to cover. Config half only: the\n // registration list is not inlined anywhere, so the types sibling would come\n // out byte-identical.\n await writeConfigFile(updatedConfig, globalConfigPath);\n verbose(`Deregistered project ${normalizedPath} from global config`);\n}\n\nfunction isProjectScopedEntry(entry: ScopedEntry): boolean {\n return entry.scope === \"project\";\n}\n\n/** True when the global config still has an active (non-excluded) skill for this id. */\nfunction globalHasActiveSkill(globalConfig: ProjectConfig, id: SkillId): boolean {\n return globalConfig.skills.some((s) => s.id === id && isActiveAt(s, \"global\"));\n}\n\n/** True when the global config still has an active (non-excluded) agent for this name. */\nfunction globalHasActiveAgent(globalConfig: ProjectConfig, name: AgentName): boolean {\n return globalConfig.agents.some((a) => a.name === name && isActiveAt(a, \"global\"));\n}\n\n/**\n * Keeps a project's own skill entries when re-inlining fresh global data, dropping\n * tombstones that no longer correspond to a real global install.\n *\n * A tombstone (`scope === \"global\" && excluded`) only has meaning while the global entry\n * it masks still exists. Once the skill has been removed from the global config, the\n * tombstone is stale — carrying it forward would leave the project showing a masked\n * global item that no longer exists. Project-scoped entries are always retained.\n */\nfunction retainProjectOwnedSkills(\n skills: SkillConfig[],\n globalConfig: ProjectConfig,\n): SkillConfig[] {\n return skills.filter(\n (entry) =>\n isProjectScopedEntry(entry) ||\n (isGlobalTombstone(entry) && globalHasActiveSkill(globalConfig, entry.id)),\n );\n}\n\n/** Agent mirror of {@link retainProjectOwnedSkills}. */\nfunction retainProjectOwnedAgents(\n agents: AgentScopeConfig[],\n globalConfig: ProjectConfig,\n): AgentScopeConfig[] {\n return agents.filter(\n (entry) =>\n isProjectScopedEntry(entry) ||\n (isGlobalTombstone(entry) && globalHasActiveAgent(globalConfig, entry.name)),\n );\n}\n\n/**\n * Category a skill belongs to according to the MERGED matrix. `undefined` when the\n * matrix has no entry for the id (a user-authored local skill carries no matrix\n * record) or when the entry sits in the `local` pseudo-category — neither\n * participates in category rules, and neither may throw.\n */\nfunction categoryOfSkill(id: SkillId, matrix: MergedSkillsMatrix): Category | undefined {\n const category = matrix.skills[id]?.category;\n if (category === undefined || category === LOCAL_PSEUDO_CATEGORY) return undefined;\n return category;\n}\n\n/**\n * True when the merged matrix DECLARES this category as holding at most one skill.\n * Read from the matrix passed in rather than `defaultCategories` so a source repo's\n * category overrides are honoured.\n *\n * A category the matrix does not declare is deliberately NOT treated as exclusive.\n * The wizard's renderer defaults an undeclared category to exclusive\n * (`build-step-logic.ts` uses `cat.exclusive ?? true`), but a rule that MASKS\n * persisted entries must only fire on a flag the data actually carries.\n */\nfunction isExclusiveCategory(category: Category, matrix: MergedSkillsMatrix): boolean {\n return matrix.categories[category]?.exclusive === true;\n}\n\n/** Categories occupied by an active project-scoped skill, per the merged matrix. */\nfunction activeProjectCategories(\n projectOwnedSkills: SkillConfig[],\n matrix: MergedSkillsMatrix,\n): Set<Category> {\n return new Set(\n projectOwnedSkills\n .filter((s) => isActiveAt(s, \"project\"))\n .map((s) => categoryOfSkill(s.id, matrix))\n .filter((category): category is Category => category !== undefined),\n );\n}\n\n/**\n * The collision that justifies masking a live global skill. Two kinds, both read from the\n * project's OWN entries: IDENTITY — the project owns the same id at project scope; CATEGORY —\n * the project owns a different active skill in the same category and the matrix declares that\n * category exclusive.\n *\n * Shared by the mask producer ({@link maskCollidingGlobalSkills}) and the self-heal that\n * removes a mask once its collision clears ({@link dropOrphanedDerivedMasks}), so the two can\n * never disagree about what a mask means.\n */\nfunction buildProjectCollisionTest(\n projectOwnedSkills: SkillConfig[],\n matrix: MergedSkillsMatrix,\n): (id: SkillId) => boolean {\n const ownedIds = new Set(\n projectOwnedSkills.filter((s) => isActiveAt(s, \"project\")).map((s) => s.id),\n );\n const occupiedExclusiveCategories = new Set(\n [...activeProjectCategories(projectOwnedSkills, matrix)].filter((category) =>\n isExclusiveCategory(category, matrix),\n ),\n );\n\n return (id) => {\n if (ownedIds.has(id)) return true;\n const category = categoryOfSkill(id, matrix);\n return category !== undefined && occupiedExclusiveCategories.has(category);\n };\n}\n\n/**\n * Drops a derived mask that no longer masks anything, so the global install becomes\n * visible again once the collision that produced it is gone.\n *\n * A derived mask and a user-authored tombstone are BYTE-IDENTICAL in config.ts — both are\n * `{ id, scope: \"global\", excluded: true }` — but since D-277 the wizard can no longer mint\n * the second kind on its own: a project-scope deselect of a globally-installed skill is\n * refused, and a domain deselect only drops what the project owns. The one user route to a\n * global tombstone is the `s` scope toggle (G→P), which always pairs the tombstone with an\n * active project entry for the same id — an IDENTITY collision. So every bare mask is\n * machine-derived, and a single retention test suffices: keep it iff the collision that\n * would re-derive it is still there, in `required` and optional categories alike.\n */\nfunction dropOrphanedDerivedMasks(\n projectOwnedSkills: SkillConfig[],\n matrix: MergedSkillsMatrix,\n): SkillConfig[] {\n const collidesWithProjectOwnership = buildProjectCollisionTest(projectOwnedSkills, matrix);\n return projectOwnedSkills.filter(\n (entry) => !isGlobalTombstone(entry) || collidesWithProjectOwnership(entry.id),\n );\n}\n\n/**\n * Agent mirror of {@link dropOrphanedDerivedMasks}, identity collisions only (D-277): agents\n * have no categories, so the project-scoped sibling with the same name is the only thing a\n * mask can be justified by.\n */\nfunction dropOrphanedDerivedAgentMasks(projectOwnedAgents: AgentScopeConfig[]): AgentScopeConfig[] {\n const ownedNames = new Set(activeProjectAgentNames(projectOwnedAgents));\n return projectOwnedAgents.filter(\n (entry) => !isGlobalTombstone(entry) || ownedNames.has(entry.name),\n );\n}\n\n/**\n * Builds the tombstones that mask live global skills this project cannot show\n * alongside what it already owns at project scope. Two collision kinds, both keyed\n * against the SAME live global config:\n *\n * 1. IDENTITY — the project owns the same id at project scope (D-268). Without the\n * mask, `partitionInlinedConfigEntries` re-inlines the global copy as a SECOND\n * active entry, leaving one id active at BOTH scopes instead of rendering the\n * dual-scope `[P][G]` pair.\n * 2. CATEGORY — the project owns a DIFFERENT active skill in the same category and\n * the matrix declares that category exclusive. Reconciliation keyed on identity\n * alone cannot see this, so a project owning Vue plus a global install of React\n * ends up with two active skills in a category that permits one.\n *\n * The project-owned skill wins locally. This is DELIBERATELY ASYMMETRIC with D-260,\n * where a user-initiated radio swap in `toggleTechnology` refuses to displace a\n * globally-locked skill: there the user is actively trying to drop a shared install,\n * whereas here the collision is PUSHED IN by a global install landing on pre-existing\n * project state. Letting global win would silently uninstall the user's own skill.\n *\n * Tombstones are spread from the global entry so they carry the global install's\n * `source`. A skill the project merely inherits (no active project-scope entry, no\n * exclusive-category collision) is skipped — it stays a single active global entry.\n * A skill the project already tombstones is skipped so re-running is idempotent.\n */\nfunction maskCollidingGlobalSkills(\n projectOwnedSkills: SkillConfig[],\n globalConfig: ProjectConfig,\n matrix: MergedSkillsMatrix,\n): SkillConfig[] {\n const collidesWithProjectOwnership = buildProjectCollisionTest(projectOwnedSkills, matrix);\n const alreadyTombstoned = new Set(projectOwnedSkills.filter(isGlobalTombstone).map((s) => s.id));\n\n return globalConfig.skills\n .filter(\n (globalEntry) =>\n isActiveAt(globalEntry, \"global\") &&\n collidesWithProjectOwnership(globalEntry.id) &&\n !alreadyTombstoned.has(globalEntry.id),\n )\n .map((globalEntry) => ({ ...globalEntry, excluded: true }));\n}\n\n/**\n * Agent mirror of {@link maskCollidingGlobalSkills}, identity collisions only (D-259).\n * Agents have no categories, so there is no grouping dimension to reconcile.\n */\nfunction maskCollidingGlobalAgents(\n projectOwnedAgents: AgentScopeConfig[],\n globalConfig: ProjectConfig,\n): AgentScopeConfig[] {\n const ownedNames = new Set(activeProjectAgentNames(projectOwnedAgents));\n const alreadyTombstoned = new Set(\n projectOwnedAgents.filter(isGlobalTombstone).map((a) => a.name),\n );\n\n return globalConfig.agents\n .filter(\n (globalEntry) =>\n isActiveAt(globalEntry, \"global\") &&\n ownedNames.has(globalEntry.name) &&\n !alreadyTombstoned.has(globalEntry.name),\n )\n .map((globalEntry) => ({ ...globalEntry, excluded: true }));\n}\n\n/**\n * Reconciles a project's OWN entries against the live global config, immediately\n * before the inlining writer merges the two.\n *\n * Applied at BOTH sites that write a project `config.ts` with `globalConfig` inlined:\n * `propagateGlobalChangesToProjects` (a global change fanning out to registered\n * projects) and the project-scope save branch of `writeScopedConfigs` (an ordinary\n * project `init`/`edit` performed while the colliding skill is already active\n * globally). Either site alone can produce the malformed shape, so both must run it.\n *\n * Self-heal runs BEFORE masking on BOTH axes so a mask whose collision has cleared is\n * removed rather than immediately re-derived, and so masking's `alreadyTombstoned` guard\n * only sees tombstones that are still warranted.\n *\n * Masking is PROJECT-LOCAL: it is applied to the project split only. The global\n * config passed in is read, never rewritten — tombstones never belong in\n * `~/.claude-src/config.ts`.\n */\nexport function reconcileProjectSplitAgainstGlobal(\n projectSplit: ProjectConfig,\n globalConfig: ProjectConfig,\n matrix: MergedSkillsMatrix,\n): ProjectConfig {\n const healedSkills = dropOrphanedDerivedMasks(projectSplit.skills, matrix);\n const healedAgents = dropOrphanedDerivedAgentMasks(projectSplit.agents);\n return {\n ...projectSplit,\n skills: [...healedSkills, ...maskCollidingGlobalSkills(healedSkills, globalConfig, matrix)],\n agents: [...healedAgents, ...maskCollidingGlobalAgents(healedAgents, globalConfig)],\n };\n}\n\n/**\n * Prunes a project's inlined `selectedAgents[]` symmetrically with `retainProjectOwnedAgents`.\n *\n * A registered project's stored `selectedAgents` is a flat name union that legitimately\n * contains global agent names — the inlined writer emits `union(global, project)`. Carried\n * forward verbatim, a global agent removed at global scope survives the writer's next union\n * and lingers in `selectedAgents[]` while being absent from `agents[]` — an internal drift\n * that never self-heals across propagation cycles. A name is retained only when it is backed\n * by a real active agent: either a project-scoped agent the project owns, or an agent still\n * active in the current global config. Project ownership is read from the already-reconciled\n * `agents[]` (project-scoped entries are always retained), so a name the project owns at\n * project scope survives even when a same-named global agent is removed.\n */\nfunction retainReconciledSelectedAgents(\n selectedAgents: AgentName[] | undefined,\n reconciledAgents: AgentScopeConfig[],\n globalConfig: ProjectConfig,\n): AgentName[] | undefined {\n if (!selectedAgents) return selectedAgents;\n const projectOwnedNames = new Set(\n reconciledAgents.filter((a) => isActiveAt(a, \"project\")).map((a) => a.name),\n );\n return selectedAgents.filter(\n (name) => projectOwnedNames.has(name) || globalHasActiveAgent(globalConfig, name),\n );\n}\n\n/**\n * Computes the skill ids that this project inherited from global scope but that are\n * no longer active at global scope after the change being propagated — and that the\n * project does not own at project scope. These are the only ids that should be pruned\n * from the project's stack: a project-scoped agent may legitimately reference a\n * globally-installed skill, and once that skill is removed at global scope the\n * reference becomes dangling.\n *\n * `priorProjectSkills` is the project's pre-reconciliation (on-disk, inlined) skills.\n * A global skill that was just removed still appears here as a `scope: \"global\"`,\n * non-excluded entry, which is the signal we key on. Project-scoped skills and\n * user-authored local skills (which carry no SkillConfig entry at all) are never in\n * this set, so they are always preserved.\n */\nfunction computeRemovedGlobalSkillIds(\n priorProjectSkills: SkillConfig[],\n globalConfig: ProjectConfig,\n): Set<SkillId> {\n const activeGlobalIds = new Set(\n globalConfig.skills.filter((s) => isActiveAt(s, \"global\")).map((s) => s.id),\n );\n const projectOwnedIds = new Set(\n priorProjectSkills.filter((s) => isActiveAt(s, \"project\")).map((s) => s.id),\n );\n return new Set(\n priorProjectSkills\n .filter(\n (s) =>\n s.scope === \"global\" &&\n !s.excluded &&\n !activeGlobalIds.has(s.id) &&\n !projectOwnedIds.has(s.id),\n )\n .map((s) => s.id),\n );\n}\n\n/**\n * Prunes stack references to global skills that were just removed at global scope,\n * so a project-scoped agent stops referencing a skill that no longer exists anywhere.\n * Only ids in `removedGlobalSkillIds` are dropped — every other assignment is kept\n * verbatim, in order, with its `preloaded` flag untouched. Categories and agents left\n * empty by the pruning are removed. When nothing was removed, the stack is returned\n * unchanged so unaffected projects produce byte-identical config output.\n */\nfunction retainReconciledStack(\n stack: Record<string, StackAgentConfig> | undefined,\n removedGlobalSkillIds: Set<SkillId>,\n): Record<string, StackAgentConfig> | undefined {\n if (!stack || removedGlobalSkillIds.size === 0) return stack;\n\n const reconciled: Record<string, StackAgentConfig> = {};\n for (const [agent, agentStack] of Object.entries(stack)) {\n const reconciledAgentStack: StackAgentConfig = {};\n for (const [category, assignments] of typedEntries<Category, SkillAssignment[]>(agentStack)) {\n if (!assignments) continue;\n const kept = assignments.filter((assignment) => !removedGlobalSkillIds.has(assignment.id));\n if (kept.length > 0) reconciledAgentStack[category] = kept;\n }\n if (typedKeys<Category>(reconciledAgentStack).length > 0) {\n reconciled[agent] = reconciledAgentStack;\n }\n }\n return reconciled;\n}\n\n/** The registered projects one fan-out rewrote, and the ones it could not reach. */\nexport type PropagationResult = {\n updated: string[];\n skipped: string[];\n};\n\nexport type PropagationOptions = {\n /**\n * Whether each project's config-types.ts is rewritten alongside its config.ts.\n * False for a change that moves no type union — a project inlines the global\n * scalars into its config half, but no union is derived from them.\n */\n regenerateTypes?: boolean;\n};\n\n/**\n * The single writer for a project's config pair, used by BOTH sites that emit\n * one: the per-project propagation step below and the project branch of the\n * wizard write.\n *\n * `buildProjectTypesExtras` is fed the EFFECTIVE config — the project's own\n * reconciled rows plus the active global rows the writer is about to inline —\n * at both sites. The emitted config.ts names every one of those rows, so extras\n * derived from the project split alone declare fewer literals than the sibling\n * config.ts uses, and the pair stops type-checking against itself.\n */\nexport async function writeProjectConfigPair(\n projectDir: string,\n reconciledSplit: ProjectConfig,\n effectiveGlobal: ProjectConfig,\n matrix: MergedSkillsMatrix,\n agents: Record<AgentName, AgentDefinition>,\n options: PropagationOptions = {},\n): Promise<void> {\n // Reconcile-before-both-writes: the two halves are derived from the same\n // reconciled data in the same call, so neither can describe a config the other\n // does not.\n await writeConfigFile(reconciledSplit, getProjectConfigPath(projectDir), {\n isProjectConfig: true,\n globalConfig: effectiveGlobal,\n });\n\n if (options.regenerateTypes === false) return;\n\n // Uses the same global-aware path for project types — emits\n // `import type { SkillId as GlobalSkillId, ... }` and extends with any\n // project-scoped items the project owns. Without this, a global-scope install\n // would overwrite the project's import-form types with the standalone/inlined\n // form (D-216 Regression #1 / D-228).\n await regenerateConfigTypes(\n projectDir,\n Promise.resolve(buildConfigTypesBackgroundData(matrix, agents)),\n buildProjectTypesExtras(inlinedProjectView(reconciledSplit, effectiveGlobal), matrix),\n );\n}\n\n/**\n * The rows the inlining writer draws a project's config.ts from: the project's\n * own reconciled entries plus everything the global config contributes. Union\n * membership is decided downstream by `buildProjectTypesExtras`, which reads the\n * active entries — a tombstone's id always arrives via the live global row it\n * masks.\n */\nfunction inlinedProjectView(\n reconciledSplit: ProjectConfig,\n effectiveGlobal: ProjectConfig,\n): ProjectConfig {\n return {\n ...reconciledSplit,\n skills: [...effectiveGlobal.skills, ...reconciledSplit.skills],\n agents: [...effectiveGlobal.agents, ...reconciledSplit.agents],\n domains: unique([...(effectiveGlobal.domains ?? []), ...(reconciledSplit.domains ?? [])]),\n stack: { ...(effectiveGlobal.stack ?? {}), ...(reconciledSplit.stack ?? {}) },\n };\n}\n\n/**\n * Propagates global config changes to all registered project configs.\n * Updates each project's config-types.ts (type unions) and config.ts (inlined global data).\n * Skips stale project paths and the current project being installed.\n */\nexport async function propagateGlobalChangesToProjects(\n globalConfig: ProjectConfig,\n matrix: MergedSkillsMatrix,\n agents: Record<AgentName, AgentDefinition>,\n currentProjectDir?: string,\n options: PropagationOptions = {},\n): Promise<PropagationResult> {\n const projects = globalConfig.projects ?? [];\n if (projects.length === 0) return { updated: [], skipped: [] };\n\n const currentNormalized = currentProjectDir ? normalizeProjectPath(currentProjectDir) : null;\n const updated: string[] = [];\n const skipped: string[] = [];\n\n for (const projectPath of projects) {\n // Skip the project currently being installed (it's already being written)\n if (currentNormalized && projectPath === currentNormalized) continue;\n\n const projectConfigPath = getProjectConfigPath(projectPath);\n if (!(await fileExists(projectConfigPath))) {\n skipped.push(projectPath);\n verbose(`Skipped propagation to ${projectPath} (config not found)`);\n continue;\n }\n\n try {\n const existingProject = await loadProjectConfigFromDir(projectPath);\n if (!existingProject?.config) {\n skipped.push(projectPath);\n continue;\n }\n\n const projectConfig = existingProject.config;\n\n // Derive project split: project-scoped entries plus tombstones that still\n // correspond to a live global install. Tombstones whose global entry has been\n // removed are dropped here so the project stops referencing a global item that\n // no longer exists (D-233 Scenario C). The stack is reconciled against the same\n // now-current global data so a project-scoped agent stops referencing a global\n // skill that was just removed at global scope. `projectConfig.skills` (pre-\n // reconciliation) is used to detect removed globals because the removed entry\n // is still present here as a `scope: \"global\"` reference.\n const removedGlobalSkillIds = computeRemovedGlobalSkillIds(\n projectConfig.skills,\n globalConfig,\n );\n const retainedAgents = retainProjectOwnedAgents(projectConfig.agents, globalConfig);\n const projectSplit = reconcileProjectSplitAgainstGlobal(\n {\n ...projectConfig,\n skills: retainProjectOwnedSkills(projectConfig.skills, globalConfig),\n agents: retainedAgents,\n stack: retainReconciledStack(projectConfig.stack, removedGlobalSkillIds),\n selectedAgents: retainReconciledSelectedAgents(\n projectConfig.selectedAgents,\n retainedAgents,\n globalConfig,\n ),\n },\n globalConfig,\n matrix,\n );\n\n await writeProjectConfigPair(projectPath, projectSplit, globalConfig, matrix, agents, {\n regenerateTypes: options.regenerateTypes ?? true,\n });\n\n updated.push(projectPath);\n verbose(`Propagated global changes to ${projectPath}`);\n } catch (error) {\n skipped.push(projectPath);\n verbose(`Failed to propagate to ${projectPath}: ${getErrorMessage(error)}`);\n }\n }\n\n return { updated, skipped };\n}\n\n/**\n * Prunes CLI-inlined global-scoped entries from every registered project after a\n * GLOBAL uninstall. Reuses {@link propagateGlobalChangesToProjects} with an\n * emptied global config so every global skill/agent reads as removed: project-\n * scoped entries are retained verbatim, inlined global rows and tombstones are\n * dropped, `selectedAgents` and per-agent stack refs lose their global-only\n * names/ids, and each project's config-types.ts is regenerated. `selectedAgents`\n * is emptied alongside `skills`/`agents` because the project config writer\n * re-unions the global `selectedAgents` into the project's — carrying it forward\n * would resurrect the names the reconciliation just pruned.\n *\n * Call AFTER the global .claude-src manifest has been removed so the regenerated\n * project types fall back to the standalone form instead of importing from the\n * now-deleted global config-types.ts. Unreachable project dirs are reported in\n * `skipped`, never thrown.\n */\nexport async function pruneGlobalEntriesFromRegisteredProjects(\n globalConfig: ProjectConfig,\n matrix: MergedSkillsMatrix,\n agents: Record<AgentName, AgentDefinition>,\n): Promise<{ updated: string[]; skipped: string[] }> {\n const emptiedGlobal: ProjectConfig = {\n ...globalConfig,\n skills: [],\n agents: [],\n selectedAgents: [],\n };\n return propagateGlobalChangesToProjects(emptiedGlobal, matrix, agents);\n}\n\n/**\n * Resolves the global config a project install should write: merges new\n * global-scoped items into the existing global config (existing items are\n * never removed during project init) and registers this project's path.\n * `globalDataChanged` gates propagation; `changed` gates the write itself.\n */\nexport async function resolveEffectiveGlobalConfig(\n globalSplit: ProjectConfig,\n existingGlobalConfig: ProjectConfig | undefined,\n projectDir: string,\n): Promise<{ config: ProjectConfig; globalDataChanged: boolean; changed: boolean }> {\n const hasGlobalItems = globalSplit.skills.length > 0 || globalSplit.agents.length > 0;\n\n const merged = !hasGlobalItems\n ? {\n config: existingGlobalConfig ?? { name: GLOBAL_CONFIG_NAME, skills: [], agents: [] },\n changed: false,\n }\n : existingGlobalConfig\n ? mergeGlobalConfigs(existingGlobalConfig, globalSplit)\n : { config: globalSplit, changed: true };\n\n const registration = await registerProjectPath(merged.config, projectDir);\n return {\n config: registration.config,\n globalDataChanged: merged.changed,\n changed: merged.changed || registration.changed,\n };\n}\n\nexport function buildConfigTypesBackgroundData(\n matrix: MergedSkillsMatrix,\n agents: Record<AgentName, AgentDefinition>,\n): ConfigTypesBackgroundData {\n const agentNames = typedKeys(agents);\n const customAgentNames = agentNames.filter((name) => agents[name]?.custom === true);\n return { matrix, agentNames, customAgentNames };\n}\n\n/** Category keys the emitted stack holds, across every agent it configures. */\nfunction stackCategories(stack: ProjectConfig[\"stack\"]): Category[] {\n return Object.values(stack ?? {}).flatMap((agentStack) => typedKeys<Category>(agentStack ?? {}));\n}\n\n/**\n * Derives the extras for regenerateConfigTypes so a project's config-types.ts declares every\n * literal its sibling config.ts holds — the two are written from the same config and must not\n * be able to disagree.\n *\n * ALL active (non-excluded) entries, not just project-scoped ones:\n * generateProjectConfigWithInlinedGlobal writes the active global rows into the project's own\n * config.ts verbatim, and the imported Global* unions cover those rows only for as long as the\n * global config still happens to contain them. A later global-scope run narrows those unions\n * and a project nobody touched stops type-checking (TS2322 on a skill id or domain, TS2353 on a\n * stack's category key).\n *\n * Domains and stack categories are read off the config's own arrays as well as derived from its\n * skill rows: `domains` is a wizard preference no skill row has to back, and neither it nor a\n * stack entry is pruned when the last skill that would derive it leaves.\n */\nexport function buildProjectTypesExtras(\n finalConfig: ProjectConfig,\n matrix: MergedSkillsMatrix,\n): Required<ConfigTypesExtras> {\n const activeSkills = finalConfig.skills.filter((s) => !s.excluded);\n const activeAgents = finalConfig.agents.filter((a) => !a.excluded);\n\n const extraSkillIds = unique(activeSkills.map((s) => s.id));\n const extraAgentNames = unique(activeAgents.map((a) => a.name));\n\n const extraCategories = unique([\n ...deriveCategories(extraSkillIds, matrix),\n ...stackCategories(finalConfig.stack),\n ]);\n const extraDomains = unique([\n ...deriveDomains(extraCategories, matrix),\n ...(finalConfig.domains ?? []),\n ]);\n\n return { extraSkillIds, extraAgentNames, extraDomains, extraCategories };\n}\n","import type { PropagatedRecompileSummary } from \"../operations/project/recompile-project-agents.js\";\n\n/** The summary of a fan-out that recompiled nothing, so callers render one shape. */\nexport const NOTHING_RECOMPILED: PropagatedRecompileSummary = {\n recompiledCount: 0,\n failedCount: 0,\n warnings: [],\n};\n\n/**\n * Recompiles the agents of every project a global write propagated into.\n *\n * Imported lazily: `recompile-project-agents` lives in the operations layer,\n * which imports back into `installation`, so a static import here would form a\n * load-time cycle (same rule as `installEject`'s `copyLocalSkills` import).\n * Per-project failure isolation lives in `recompilePropagatedProjectAgents` and\n * is unchanged by running it from inside the write.\n */\nexport async function recompilePropagated(\n projectDirs: string[],\n): Promise<PropagatedRecompileSummary> {\n if (projectDirs.length === 0) return NOTHING_RECOMPILED;\n\n const { recompilePropagatedProjectAgents } =\n await import(\"../operations/project/recompile-project-agents.js\");\n return recompilePropagatedProjectAgents(projectDirs);\n}\n","import { createHash } from \"crypto\";\nimport { isRecord } from \"../../utils/type-guards.js\";\nimport { downloadTemplate } from \"giget\";\nimport os from \"os\";\nimport path from \"path\";\n\nimport {\n CACHE_DIR,\n CACHE_HASH_LENGTH,\n CACHE_READABLE_PREFIX_LENGTH,\n MAX_MARKETPLACE_FILE_SIZE,\n MAX_JSON_NESTING_DEPTH,\n MAX_MARKETPLACE_PLUGINS,\n MARKETPLACE_JSON,\n marketplaceManifestPath,\n} from \"../../consts\";\nimport { getErrorMessage } from \"../../utils/errors\";\nimport { ensureDir, directoryExists, readFileSafe, remove } from \"../../utils/fs\";\nimport { verbose, warn } from \"../../utils/logger\";\nimport { isLocalSource } from \"../configuration\";\nimport {\n formatZodIssues,\n marketplaceSchema,\n validateNestingDepth,\n warnUnknownFields,\n} from \"../schemas\";\nimport type { MarketplaceFetchResult } from \"../../types\";\n\n/** Safe name pattern: alphanumeric, hyphens, underscores, dots, spaces, @, / (no shell metacharacters) */\nconst SAFE_NAME_PATTERN = /^[a-zA-Z0-9@._/ -]+$/;\nconst MAX_NAME_LENGTH = 200;\n\n/** Matches giget's source protocol regex to extract provider name */\nconst SOURCE_PROTO_RE = /^([\\w-.]+):/;\n\n/**\n * Matches giget's input regex for git URI parsing.\n * Groups: repo (org/name), subdir (optional path), ref (optional #branch)\n */\nconst GIT_URI_RE = /^(?<repo>[\\w.-]+\\/[\\w.-]+)(?<subdir>[^#]+)?(?<ref>#[\\w./@-]+)?/;\n\nexport type FetchOptions = {\n forceRefresh?: boolean;\n subdir?: string;\n};\n\nexport type FetchResult = {\n path: string;\n fromCache: boolean;\n source: string;\n};\n\nexport function sanitizeSourceForCache(source: string): string {\n const hash = createHash(\"sha256\").update(source).digest(\"hex\").slice(0, CACHE_HASH_LENGTH);\n\n const readable = source\n .replace(/[^a-zA-Z0-9]/g, \"-\")\n .replace(/--+/g, \"-\")\n .replace(/^-|-$/g, \"\")\n .slice(0, CACHE_READABLE_PREFIX_LENGTH);\n\n return readable ? `${readable}-${hash}` : hash;\n}\n\nfunction getCacheDir(source: string): string {\n const sanitized = sanitizeSourceForCache(source) || \"unknown\";\n return path.join(CACHE_DIR, \"sources\", sanitized);\n}\n\nexport async function fetchFromSource(\n source: string,\n options: FetchOptions = {},\n): Promise<FetchResult> {\n const { forceRefresh = false, subdir } = options;\n\n if (isLocalSource(source)) {\n return fetchFromLocalSource(source, subdir);\n }\n\n return fetchFromRemoteSource(source, { forceRefresh, subdir });\n}\n\nasync function fetchFromLocalSource(source: string, subdir?: string): Promise<FetchResult> {\n const fullPath = subdir ? path.join(source, subdir) : source;\n const absolutePath = path.isAbsolute(fullPath) ? fullPath : path.resolve(process.cwd(), fullPath);\n\n if (!(await directoryExists(absolutePath))) {\n throw new Error(`Local source not found: '${absolutePath}'`);\n }\n\n verbose(`Using local source: ${absolutePath}`);\n\n return {\n path: absolutePath,\n fromCache: false,\n source,\n };\n}\n\n/**\n * Compute the giget tarball cache directory for a source.\n *\n * Replicates giget's internal cache path logic:\n * `{cacheRoot}/{providerName}/{templateName}`\n *\n * where templateName is `repo.replace(\"/\", \"-\")` sanitized to `[a-zA-Z0-9-]`.\n * Returns undefined if the source format doesn't match giget's git URI pattern.\n */\nexport function getGigetCacheDir(source: string): string | undefined {\n const protoMatch = source.match(SOURCE_PROTO_RE);\n\n // http/https providers use the full URL, not parseable as git URI\n if (protoMatch && (protoMatch[1] === \"http\" || protoMatch[1] === \"https\")) {\n return undefined;\n }\n\n const providerName = protoMatch?.[1] ?? \"github\";\n const rawSource = protoMatch ? source.slice(protoMatch[0].length) : source;\n\n const uriMatch = rawSource.match(GIT_URI_RE);\n if (!uriMatch?.groups?.repo) {\n return undefined;\n }\n\n // Replicate giget's template.name sanitization\n const templateName = uriMatch.groups.repo.replace(\"/\", \"-\").replace(/[^\\da-z-]/gi, \"-\");\n\n const gigetCacheRoot = process.env.XDG_CACHE_HOME\n ? path.resolve(process.env.XDG_CACHE_HOME, \"giget\")\n : path.resolve(os.homedir(), \".cache\", \"giget\");\n\n return path.join(gigetCacheRoot, providerName, templateName);\n}\n\n/**\n * Clear giget's tarball/ETag cache for a source so downloadTemplate()\n * performs a fresh fetch instead of short-circuiting with a stale ETag.\n */\nasync function clearGigetCache(source: string): Promise<void> {\n const gigetDir = getGigetCacheDir(source);\n if (!gigetDir) return;\n\n if (await directoryExists(gigetDir)) {\n verbose(`Clearing giget cache: ${gigetDir}`);\n await remove(gigetDir);\n }\n}\n\nasync function fetchFromRemoteSource(source: string, options: FetchOptions): Promise<FetchResult> {\n const { forceRefresh = false, subdir } = options;\n const cacheDir = getCacheDir(source);\n\n const fullSource = subdir ? `${source}/${subdir}` : source;\n\n verbose(`Fetching from remote: ${fullSource}`);\n verbose(`Cache directory: ${cacheDir}`);\n\n if (!forceRefresh && (await directoryExists(cacheDir))) {\n verbose(`Using cached source: ${cacheDir}`);\n return {\n path: cacheDir,\n fromCache: true,\n source: fullSource,\n };\n }\n\n if (forceRefresh) {\n await clearGigetCache(source);\n await remove(cacheDir);\n }\n\n await ensureDir(path.dirname(cacheDir));\n\n try {\n const result = await downloadTemplate(fullSource, {\n dir: cacheDir,\n force: true, // Always force when downloading to avoid \"already exists\" error\n offline: false,\n });\n\n verbose(`Downloaded to: ${result.dir}`);\n\n return {\n path: result.dir,\n fromCache: false,\n source: fullSource,\n };\n } catch (error) {\n throw createDetailedFetchError(error, source);\n }\n}\n\nfunction createDetailedFetchError(error: unknown, source: string): Error {\n const message = getErrorMessage(error);\n\n if (message.includes(\"404\") || message.includes(\"Not Found\")) {\n return new Error(\n `Repository not found: ${source}\\n\\n` +\n `This could mean:\\n` +\n ` - The repository doesn't exist\\n` +\n ` - The repository is private and you need to set authentication\\n` +\n ` - There's a typo in the URL\\n\\n` +\n `For private repositories, set the GIGET_AUTH environment variable:\\n` +\n ` export GIGET_AUTH=ghp_your_github_token`,\n );\n }\n\n if (message.includes(\"401\") || message.includes(\"Unauthorized\")) {\n return new Error(\n `Authentication required for: ${source}\\n\\n` +\n `Set the GIGET_AUTH environment variable with a GitHub token:\\n` +\n ` export GIGET_AUTH=ghp_your_github_token\\n\\n` +\n `Create a token at: https://github.com/settings/tokens\\n` +\n `Required scope: repo (for private repos) or public_repo (for public)`,\n );\n }\n\n if (message.includes(\"403\") || message.includes(\"Forbidden\")) {\n return new Error(\n `Access denied to: ${source}\\n\\n` +\n `Your token may not have sufficient permissions.\\n` +\n `Ensure your GIGET_AUTH token has the 'repo' scope for private repositories.`,\n );\n }\n\n if (\n message.includes(\"ENOTFOUND\") ||\n message.includes(\"ETIMEDOUT\") ||\n message.includes(\"network\")\n ) {\n return new Error(\n `Network error fetching: ${source}\\n\\n` +\n `Please check your internet connection.\\n` +\n `If you're behind a corporate proxy, you may need to set:\\n` +\n ` export HTTPS_PROXY=http://your-proxy:port\\n` +\n ` export FORCE_NODE_FETCH=true # Required for Node 20+`,\n );\n }\n\n return new Error(`Failed to fetch ${source}: ${message}`);\n}\n\nexport async function fetchMarketplace(\n source: string,\n options: FetchOptions = {},\n): Promise<MarketplaceFetchResult> {\n const result = await fetchFromSource(source, {\n forceRefresh: options.forceRefresh,\n subdir: \"\", // Root of repo\n });\n\n const marketplacePath = marketplaceManifestPath(result.path);\n\n if (!(await directoryExists(path.dirname(marketplacePath)))) {\n throw new Error(\n `Marketplace not found for source: ${source}\\n\\n` +\n `The .claude-plugin/marketplace.json file is missing from this repository.\\n\\n` +\n `Possible causes:\\n` +\n \" - The source URL may be incorrect\\n\" +\n \" - The repository may not have a marketplace configured\\n\\n\" +\n \"To create a marketplace, add a .claude-plugin/marketplace.json file to your source repository.\",\n );\n }\n\n const content = await readFileSafe(marketplacePath, MAX_MARKETPLACE_FILE_SIZE);\n const parsed = JSON.parse(content);\n\n if (!validateNestingDepth(parsed, MAX_JSON_NESTING_DEPTH)) {\n throw new Error(\n `Invalid marketplace.json at: ${marketplacePath}\\n\\n` +\n `JSON structure exceeds maximum nesting depth of ${MAX_JSON_NESTING_DEPTH}.`,\n );\n }\n\n const validation = marketplaceSchema.safeParse(parsed);\n\n if (!validation.success) {\n throw new Error(\n `Invalid marketplace.json at: ${marketplacePath}\\n\\n` +\n `Validation errors: ${formatZodIssues(validation.error.issues)}`,\n );\n }\n\n const marketplace = validation.data;\n\n const EXPECTED_MARKETPLACE_KEYS = [\n \"$schema\",\n \"name\",\n \"version\",\n \"description\",\n \"owner\",\n \"metadata\",\n \"plugins\",\n ] as const;\n if (isRecord(parsed)) {\n warnUnknownFields(parsed, EXPECTED_MARKETPLACE_KEYS, MARKETPLACE_JSON);\n }\n\n if (marketplace.plugins.length > MAX_MARKETPLACE_PLUGINS) {\n throw new Error(\n `Invalid marketplace.json at: ${marketplacePath}\\n\\n` +\n `Too many plugins: ${marketplace.plugins.length} (limit: ${MAX_MARKETPLACE_PLUGINS}).`,\n );\n }\n\n for (const plugin of marketplace.plugins) {\n if (plugin.name.length > MAX_NAME_LENGTH) {\n warn(\n `Marketplace plugin name too long (${plugin.name.length} chars): '${plugin.name.slice(0, 50)}...'`,\n );\n }\n if (!SAFE_NAME_PATTERN.test(plugin.name)) {\n warn(`Marketplace plugin name contains unsafe characters: '${plugin.name.slice(0, 50)}'`);\n }\n }\n\n verbose(`Loaded marketplace: ${marketplace.name} v${marketplace.version}`);\n\n return {\n marketplace,\n sourcePath: result.path,\n fromCache: result.fromCache ?? false,\n };\n}\n","import { parse as parseYaml } from \"yaml\";\nimport path from \"path\";\nimport { directoryExists, listDirectories, fileExists, readFile } from \"../../utils/fs\";\nimport { getErrorMessage } from \"../../utils/errors\";\nimport { verbose, warn } from \"../../utils/logger\";\nimport { LOCAL_SKILLS_PATH, STANDARD_FILES } from \"../../consts\";\nimport { parseFrontmatter } from \"../loading\";\nimport type { CategoryPath, Domain, ExtractedSkillMetadata, SkillSlug } from \"../../types\";\nimport { formatZodIssues, localRawMetadataSchema } from \"../schemas\";\nimport { LOCAL_DEFAULTS } from \"../metadata-keys\";\n\nexport type LocalRawMetadata = {\n displayName: string;\n /** Kebab-case short key for alias resolution */\n slug: SkillSlug;\n cliDescription?: string;\n /** Skill category (e.g., \"web-framework\", \"web-styling\", \"api-api\") */\n category: CategoryPath;\n usageGuidance?: string;\n tags?: string[];\n /** Domain this skill belongs to (e.g., \"web\", \"api\", \"cli\") */\n domain: Domain;\n /** True if this skill was created outside the CLI's built-in vocabulary */\n custom?: boolean;\n};\n\nexport type LocalSkillDiscoveryResult = {\n skills: ExtractedSkillMetadata[];\n localSkillsPath: string;\n};\n\nexport async function discoverLocalSkills(\n projectDir: string,\n): Promise<LocalSkillDiscoveryResult | null> {\n const localSkillsPath = path.join(projectDir, LOCAL_SKILLS_PATH);\n\n if (!(await directoryExists(localSkillsPath))) {\n verbose(`Local skills directory not found: ${localSkillsPath}`);\n return null;\n }\n\n const skillDirs = await listDirectories(localSkillsPath);\n const extracted = await Promise.all(\n skillDirs.map((skillDirName) => extractLocalSkill(localSkillsPath, skillDirName)),\n );\n const skills = extracted.filter((skill) => skill !== null);\n\n verbose(`Discovered ${skills.length} local skills from ${localSkillsPath}`);\n\n return {\n skills,\n localSkillsPath,\n };\n}\n\nasync function extractLocalSkill(\n localSkillsPath: string,\n skillDirName: string,\n): Promise<ExtractedSkillMetadata | null> {\n const skillDir = path.join(localSkillsPath, skillDirName);\n const metadataPath = path.join(skillDir, STANDARD_FILES.METADATA_YAML);\n const skillMdPath = path.join(skillDir, STANDARD_FILES.SKILL_MD);\n\n if (!(await fileExists(metadataPath))) {\n verbose(`Skipping local skill '${skillDirName}': No metadata.yaml found`);\n return null;\n }\n\n if (!(await fileExists(skillMdPath))) {\n verbose(`Skipping local skill '${skillDirName}': No SKILL.md found`);\n return null;\n }\n\n const metadataContent = await readFile(metadataPath);\n\n // parseYaml throws on syntactically invalid YAML. One corrupt file must skip\n // its own skill, not abort discovery for every command that loads the catalog.\n let rawMetadata: unknown;\n try {\n rawMetadata = parseYaml(metadataContent);\n } catch (error) {\n warn(\n `Skipping local skill '${skillDirName}': unparseable ${STANDARD_FILES.METADATA_YAML} at ${metadataPath} — ${getErrorMessage(error)}`,\n );\n return null;\n }\n\n const parsed = localRawMetadataSchema.safeParse(rawMetadata);\n\n if (!parsed.success) {\n verbose(\n `Skipping local skill '${skillDirName}': invalid metadata.yaml — ${formatZodIssues(parsed.error.issues)}`,\n );\n return null;\n }\n\n const metadata = parsed.data;\n\n const skillMdContent = await readFile(skillMdPath);\n const frontmatter = parseFrontmatter(skillMdContent, skillMdPath);\n\n if (!frontmatter) {\n verbose(`Skipping local skill '${skillDirName}': invalid SKILL.md frontmatter`);\n return null;\n }\n\n const relativePath = `${LOCAL_SKILLS_PATH}/${skillDirName}/`;\n const absolutePath = path.join(localSkillsPath, skillDirName) + path.sep;\n const skillId = frontmatter.name;\n\n const extracted: ExtractedSkillMetadata = {\n id: skillId,\n directoryPath: skillDirName,\n description: metadata.cliDescription || frontmatter.description,\n usageGuidance: metadata.usageGuidance,\n category: metadata.category,\n author: LOCAL_DEFAULTS.AUTHOR,\n path: relativePath,\n local: true,\n localPath: absolutePath,\n domain: metadata.domain,\n custom: metadata.custom,\n slug: metadata.slug,\n displayName: metadata.displayName,\n };\n\n verbose(`Extracted local skill: ${skillId}`);\n return extracted;\n}\n","import os from \"os\";\nimport path from \"path\";\n\nimport { isHomeDirectory } from \"../installation/is-home-directory\";\nimport { DEFAULT_PUBLIC_SOURCE_NAME, EJECT_SOURCE, SKILLS_DIR_PATH } from \"../../consts\";\nimport type {\n BoundSkillCandidate,\n MergedSkillsMatrix,\n SkillAlias,\n SkillId,\n SkillSource,\n SkillSourceType,\n} from \"../../types\";\nimport { getErrorMessage } from \"../../utils/errors\";\nimport { verbose, warn } from \"../../utils/logger\";\nimport { typedEntries, typedKeys } from \"../../utils/typed-object\";\nimport {\n DEFAULT_SOURCE,\n resolveAllSources,\n type ResolvedConfig,\n type SourceEntry,\n} from \"../configuration\";\nimport { extractAllSkills } from \"../matrix\";\nimport { discoverAllPluginSkills } from \"../plugins\";\nimport { fetchFromSource, fetchMarketplace } from \"./source-fetcher\";\n\n/**\n * Appends a source to the skill's availableSources, initializing the array on\n * first tag. In-place mutation is this module's documented tagging contract.\n */\nfunction addAvailableSource(\n skill: { availableSources?: SkillSource[] },\n source: SkillSource,\n): void {\n skill.availableSources = skill.availableSources ?? [];\n skill.availableSources.push(source);\n}\n\n/** Fetches a source (cached unless forceRefresh) and extracts its skills. */\nasync function fetchSourceSkills(url: string, forceRefresh: boolean) {\n const fetchResult = await fetchFromSource(url, { forceRefresh });\n return extractAllSkills(path.join(fetchResult.path, SKILLS_DIR_PATH));\n}\n\n/**\n * Annotates every skill in the matrix with multi-source availability metadata.\n *\n * Runs a six-phase tagging pipeline that mutates `primaryMatrix.skills` in place:\n * 1. **Primary** -- tags all skills with the primary source (public or private marketplace)\n * 2. **Local** -- tags skills with `local: true` as installed via local source\n * 3. **Plugin** -- detects plugin-installed skills via `settings.json` and global cache\n * 4. **Public fallback** -- when primary is a private marketplace, fetches the default\n * public source and tags matching skills so users can switch between sources\n * 5. **Extra sources** -- fetches each configured extra source and tags matching skills\n * 6. **Active source** -- sets `activeSource` to the installed variant, or first available\n *\n * After this function completes, each skill in the matrix has `availableSources` (all\n * known sources) and `activeSource` (the one currently in use) populated.\n *\n * @param primaryMatrix - The merged skills matrix to annotate. Mutated in place --\n * `availableSources` and `activeSource` are set on each skill.\n * @param sourceConfig - Resolved source configuration, used to determine whether the\n * primary source is a private marketplace or the default public source\n * @param projectDir - Absolute path to the project root, used to locate plugin directories\n * and resolve extra source configurations\n * @param forceRefresh - Whether to bypass cached source data\n * @param marketplace - Optional marketplace name resolved from the source's marketplace.json.\n * Takes precedence over `sourceConfig.marketplace` when provided.\n *\n * @remarks\n * **Side effects:** Mutates `primaryMatrix` in place. May perform network requests\n * to fetch extra source repositories (via giget). Errors from individual extra sources\n * are warned and skipped -- the function never throws.\n */\nexport async function loadSkillsFromAllSources(\n primaryMatrix: MergedSkillsMatrix,\n sourceConfig: ResolvedConfig,\n projectDir: string,\n forceRefresh = false,\n marketplace?: string,\n): Promise<void> {\n const resolvedMarketplace = marketplace ?? sourceConfig.marketplace;\n const isDefaultPublicSource = sourceConfig.source === DEFAULT_SOURCE;\n\n const primarySourceName = resolvedMarketplace ?? DEFAULT_PUBLIC_SOURCE_NAME;\n const primarySourceType: SkillSourceType = isDefaultPublicSource ? \"public\" : \"private\";\n\n tagPrimarySourceSkills(primaryMatrix, primarySourceName, primarySourceType);\n tagLocalSkills(primaryMatrix);\n await tagPluginSkills(primaryMatrix, projectDir, primarySourceName, primarySourceType);\n\n if (!isDefaultPublicSource) {\n await tagPublicSourceSkills(primaryMatrix, primarySourceName, forceRefresh);\n }\n\n await tagExtraSources(primaryMatrix, projectDir, forceRefresh);\n setActiveSources(primaryMatrix);\n}\n\nfunction tagPrimarySourceSkills(\n matrix: MergedSkillsMatrix,\n sourceName: string,\n sourceType: SkillSourceType,\n): void {\n for (const [, skill] of typedEntries(matrix.skills)) {\n if (!skill) continue;\n\n const source: SkillSource = {\n name: sourceName,\n type: sourceType,\n installed: false,\n primary: true,\n };\n\n addAvailableSource(skill, source);\n }\n}\n\nfunction tagLocalSkills(matrix: MergedSkillsMatrix): void {\n let count = 0;\n for (const [, skill] of typedEntries(matrix.skills)) {\n if (!skill) continue;\n if (!skill.local) continue;\n\n const source: SkillSource = {\n name: EJECT_SOURCE,\n type: \"local\",\n installed: true,\n installMode: \"eject\",\n };\n\n addAvailableSource(skill, source);\n count++;\n }\n\n verbose(`Tagged ${count} local skills with local source`);\n}\n\nasync function tagPluginSkills(\n matrix: MergedSkillsMatrix,\n projectDir: string,\n primarySourceName: string,\n primarySourceType: SkillSourceType,\n): Promise<void> {\n const allPluginSkillIds = await collectPluginSkillIds(projectDir);\n\n if (allPluginSkillIds.length === 0) {\n return;\n }\n\n for (const skillId of allPluginSkillIds) {\n const skill = matrix.skills[skillId];\n if (!skill) continue;\n\n skill.availableSources = skill.availableSources ?? [];\n\n const existingSource = skill.availableSources.find((s) => s.name === primarySourceName);\n if (existingSource && !existingSource.installMode) {\n existingSource.installed = true;\n existingSource.installMode = \"plugin\";\n } else if (!skill.availableSources.some((s) => s.installMode === \"plugin\")) {\n skill.availableSources.push({\n name: primarySourceName,\n type: primarySourceType,\n installed: true,\n installMode: \"plugin\",\n primary: true,\n });\n }\n }\n\n verbose(`Tagged ${allPluginSkillIds.length} plugin-installed skills`);\n}\n\n/**\n * Collects skill IDs from all enabled plugins via settings.json and global cache.\n * Uses {@link discoverAllPluginSkills} to find skills from the plugin registry.\n */\nasync function collectPluginSkillIds(projectDir: string): Promise<SkillId[]> {\n const pluginSkills = await discoverAllPluginSkills(projectDir);\n const skillIds = typedKeys<SkillId>(pluginSkills);\n\n // D-160: Also discover global plugins when editing from a project directory.\n // Follows the same global+project merge pattern as local skills in source-loader.ts.\n const homeDir = os.homedir();\n if (!isHomeDirectory(projectDir)) {\n const globalPluginSkills = await discoverAllPluginSkills(homeDir);\n const globalSkillIds = typedKeys<SkillId>(globalPluginSkills);\n if (globalSkillIds.length > 0) {\n verbose(`Found ${globalSkillIds.length} global plugin skill(s)`);\n const merged = new Set([...skillIds, ...globalSkillIds]);\n return [...merged];\n }\n }\n\n if (skillIds.length === 0) {\n verbose(\"No plugin skills discovered from settings.json\");\n }\n\n return skillIds;\n}\n\n/**\n * When the primary source is a private marketplace, fetch the default public source\n * and tag matching skills so the user can switch between private and public sources\n * in the Sources step.\n *\n * The URL check at the call site is not sufficient: a custom source that resolves\n * to the same marketplace NAME as the public one (both fall back to\n * {@link DEFAULT_PUBLIC_SOURCE_NAME}) would otherwise be tagged twice, offering the\n * user two indistinguishable columns that write the same value.\n */\nasync function tagPublicSourceSkills(\n matrix: MergedSkillsMatrix,\n primarySourceName: string,\n forceRefresh: boolean,\n): Promise<void> {\n let publicSourceName = DEFAULT_PUBLIC_SOURCE_NAME;\n\n try {\n const marketplaceResult = await fetchMarketplace(DEFAULT_SOURCE, { forceRefresh });\n publicSourceName = marketplaceResult.marketplace.name;\n verbose(`Public marketplace name from marketplace.json: ${publicSourceName}`);\n } catch {\n verbose(\"Public source has no marketplace.json -- using default label\");\n }\n\n if (publicSourceName === primarySourceName) {\n verbose(\n `Public source resolves to the same name as the primary source ('${primarySourceName}') -- skipping duplicate tagging`,\n );\n return;\n }\n\n try {\n const publicSkills = await fetchSourceSkills(DEFAULT_SOURCE, forceRefresh);\n\n const matched = publicSkills\n .map((publicSkill) => matrix.skills[publicSkill.id])\n .filter((matrixSkill) => matrixSkill !== undefined);\n for (const matrixSkill of matched) {\n addAvailableSource(matrixSkill, { name: publicSourceName, type: \"public\", installed: false });\n }\n\n verbose(\n `Public source: ${publicSkills.length} skills found, ${matched.length} matching primary matrix`,\n );\n } catch (error) {\n warn(`Failed to load public source for alternative tagging: ${getErrorMessage(error)}`);\n }\n}\n\nasync function tagExtraSources(\n matrix: MergedSkillsMatrix,\n projectDir: string,\n forceRefresh: boolean,\n): Promise<void> {\n let allSources;\n try {\n allSources = await resolveAllSources(projectDir);\n } catch (error) {\n verbose(`Failed to resolve extra sources: ${getErrorMessage(error)}`);\n return;\n }\n\n if (allSources.extras.length === 0) {\n verbose(\"No extra sources configured\");\n return;\n }\n\n for (const extraSource of allSources.extras) {\n verbose(`Loading extra source: ${extraSource.name} (${extraSource.url})`);\n\n try {\n const skills = await fetchSourceSkills(extraSource.url, forceRefresh);\n\n const matched = skills\n .map((extractedSkill) => matrix.skills[extractedSkill.id])\n .filter((matrixSkill) => matrixSkill !== undefined);\n for (const matrixSkill of matched) {\n addAvailableSource(matrixSkill, {\n name: extraSource.name,\n type: \"private\",\n url: extraSource.url,\n installed: false,\n });\n }\n\n verbose(\n `Extra source '${extraSource.name}': ${skills.length} skills found, ${matched.length} matching`,\n );\n } catch (error) {\n warn(\n `Failed to load extra source '${extraSource.name}' ('${extraSource.url}'): ${getErrorMessage(error)}`,\n );\n }\n }\n}\n\n/** Prefers installed source so the wizard shows current state; falls back to first available */\nfunction setActiveSources(matrix: MergedSkillsMatrix): void {\n for (const [, skill] of typedEntries(matrix.skills)) {\n if (!skill) continue;\n if (!skill.availableSources || skill.availableSources.length === 0) continue;\n\n // Prefer installed source, then fall back to first available\n const installedSource = skill.availableSources.find((s) => s.installed);\n skill.activeSource = installedSource ?? skill.availableSources[0];\n }\n}\n\n/**\n * Searches configured extra sources for skills matching a given alias.\n *\n * For each configured source, fetches the repository (using cached data when available),\n * extracts all skill metadata, and matches by the last segment of the skill's directory\n * path against the provided alias (case-insensitive). Used by the wizard's skill search\n * modal to find foreign skills that can be bound to a category.\n *\n * @param alias - Skill alias to search for (e.g., \"react\", \"zustand\"). Matched\n * case-insensitively against the last path segment of each skill's\n * directory path in the source repository.\n * @param configuredSources - Array of extra source entries from project/global config.\n * Each entry has `name` (display name) and `url` (giget-compatible\n * source URL like \"github:org/repo\").\n * @returns Array of matching candidates with skill ID, source URL, source name, alias,\n * and description. Returns an empty array if no sources are configured or no\n * matches are found. Never throws -- errors per-source are warned and skipped.\n *\n * @remarks\n * **Side effects:** May perform network requests to fetch source repositories via giget.\n * Uses cached source data when available (controlled by `forceRefresh: false`).\n */\nexport async function searchExtraSources(\n alias: SkillAlias,\n configuredSources: SourceEntry[],\n): Promise<BoundSkillCandidate[]> {\n const candidates: BoundSkillCandidate[] = [];\n\n if (configuredSources.length === 0) {\n return candidates;\n }\n\n const lowerAlias = alias.toLowerCase();\n\n for (const source of configuredSources) {\n try {\n const skills = await fetchSourceSkills(source.url, false);\n\n // Match by last segment of directory path (the alias/display-name convention)\n candidates.push(\n ...skills\n .filter((skill) => path.basename(skill.directoryPath).toLowerCase() === lowerAlias)\n .map((skill) => ({\n id: skill.id,\n sourceUrl: source.url,\n sourceName: source.name,\n alias,\n description: skill.description,\n })),\n );\n } catch (error) {\n warn(\n `Failed to search extra source '${source.name}' ('${source.url}'): ${getErrorMessage(error)}`,\n );\n }\n }\n\n return candidates;\n}\n","import { parse as parseYaml } from \"yaml\";\nimport path from \"path\";\nimport { glob, readFile, fileExists } from \"../../utils/fs\";\nimport { verbose, warn } from \"../../utils/logger\";\nimport { DIRS, STANDARD_FILES } from \"../../consts\";\nimport { loadConfig } from \"../configuration/config-loader\";\nimport { METADATA_KEYS } from \"../metadata-keys\";\nimport { parseFrontmatter } from \"../loading\";\nimport {\n skillCategoriesFileSchema,\n skillRulesFileSchema,\n formatZodIssues,\n matrixRawMetadataSchema,\n} from \"../schemas\";\nimport { mergeMatrixWithSkills } from \"./skill-resolution\";\nimport type {\n CategoryMap,\n ExtractedSkillMetadata,\n MergedSkillsMatrix,\n SkillRulesConfig,\n} from \"../../types\";\n\n/**\n * Loads and validates a skill-categories.ts configuration file.\n *\n * @param configPath - Absolute path to the skill-categories.ts file\n * @returns Parsed and validated categories map\n * @throws When the file cannot be read or fails Zod schema validation\n */\nexport async function loadSkillCategories(configPath: string): Promise<CategoryMap> {\n const data = await loadConfig(configPath, skillCategoriesFileSchema);\n\n if (!data) {\n throw new Error(`Invalid skill categories at '${configPath}': failed to load or validate`);\n }\n\n verbose(`Loaded skill categories: ${configPath}`);\n return data.categories;\n}\n\n/**\n * Loads and validates a skill-rules.ts configuration file.\n *\n * @param configPath - Absolute path to the skill-rules.ts file\n * @returns Parsed and validated skill rules config\n * @throws When the file cannot be read or fails Zod schema validation\n */\nexport async function loadSkillRules(configPath: string): Promise<SkillRulesConfig> {\n const data = await loadConfig(configPath, skillRulesFileSchema);\n\n if (!data) {\n throw new Error(`Invalid skill rules at '${configPath}': failed to load or validate`);\n }\n\n const config: SkillRulesConfig = {\n version: data.version,\n relationships: data.relationships ?? {\n conflicts: [],\n discourages: [],\n recommends: [],\n requires: [],\n alternatives: [],\n },\n };\n\n verbose(`Loaded skill rules: ${configPath}`);\n return config;\n}\n\n/**\n * Scans a skills directory and extracts metadata from all valid skills.\n *\n * Discovers skills by globbing for `metadata.yaml` files, then for each:\n * 1. Validates a corresponding SKILL.md exists (skips if missing)\n * 2. Parses and validates metadata.yaml against the raw metadata schema\n * 3. Parses SKILL.md frontmatter for the canonical skill ID\n * 4. Merges metadata fields into an ExtractedSkillMetadata object\n *\n * Skills with invalid metadata are warned and skipped. Skills missing\n * the required `displayName` field in metadata.yaml cause a hard error.\n *\n * @param skillsDir - Absolute path to the skills root directory (e.g., `{root}/src/skills`)\n * @returns Array of extracted skill metadata, one per valid skill found\n * @throws When a skill's metadata.yaml is missing the required `displayName` field\n */\nexport async function extractAllSkills(skillsDir: string): Promise<ExtractedSkillMetadata[]> {\n const skills: ExtractedSkillMetadata[] = [];\n const metadataFiles = await glob(`**/${STANDARD_FILES.METADATA_YAML}`, skillsDir);\n\n for (const metadataFile of metadataFiles) {\n const skillDir = path.dirname(metadataFile);\n const skillMdPath = path.join(skillsDir, skillDir, STANDARD_FILES.SKILL_MD);\n const metadataPath = path.join(skillsDir, metadataFile);\n\n if (!(await fileExists(skillMdPath))) {\n verbose(`Skipping ${metadataFile}: No ${STANDARD_FILES.SKILL_MD} found`);\n continue;\n }\n\n const metadataContent = await readFile(metadataPath);\n const rawMetadata = parseYaml(metadataContent);\n const metadataResult = matrixRawMetadataSchema.safeParse(rawMetadata);\n\n if (!metadataResult.success) {\n warn(\n `Skipping '${metadataFile}': invalid metadata.yaml — ${formatZodIssues(metadataResult.error.issues)}`,\n );\n continue;\n }\n\n const metadata = metadataResult.data;\n const skillMdContent = await readFile(skillMdPath);\n const frontmatter = parseFrontmatter(skillMdContent, skillMdPath);\n\n if (!frontmatter) {\n verbose(`Skipping ${metadataFile}: Invalid SKILL.md frontmatter`);\n continue;\n }\n\n if (!metadata.displayName) {\n throw new Error(\n `Skill at ${metadataFile} is missing required '${METADATA_KEYS.DISPLAY_NAME}' field in metadata.yaml`,\n );\n }\n\n const skillId = frontmatter.name;\n\n const extracted: ExtractedSkillMetadata = {\n id: skillId,\n directoryPath: skillDir,\n description: metadata.cliDescription || frontmatter.description,\n usageGuidance: metadata.usageGuidance,\n category: metadata.category,\n author: metadata.author,\n path: `skills/${skillDir}/`,\n domain: metadata.domain,\n displayName: metadata.displayName,\n slug: metadata.slug,\n ...(metadata.custom === true ? { custom: true } : {}),\n };\n\n skills.push(extracted);\n verbose(`Extracted skill: ${skillId}`);\n }\n\n return skills;\n}\n\n/**\n * Convenience function that loads categories and rules from standalone files,\n * extracts all skills from the project's skills directory, and merges them\n * into a MergedSkillsMatrix.\n *\n * @param categoriesPath - Path to the skill-categories.ts config file\n * @param rulesPath - Path to the skill-rules.ts config file\n * @param projectRoot - Project root directory (skills are scanned from `{root}/src/skills`)\n * @returns Fully resolved and merged skills matrix\n */\nexport async function loadAndMergeSkillsMatrix(\n categoriesPath: string,\n rulesPath: string,\n projectRoot: string,\n): Promise<MergedSkillsMatrix> {\n const skillsDir = path.join(projectRoot, DIRS.skills);\n const [categories, rules, skills] = await Promise.all([\n loadSkillCategories(categoriesPath),\n loadSkillRules(rulesPath),\n extractAllSkills(skillsDir),\n ]);\n return mergeMatrixWithSkills(categories, rules.relationships, skills);\n}\n","import { verbose, warn } from \"../../utils/logger\";\nimport { uniqueBy } from \"remeda\";\nimport { toTitleCase } from \"../../utils/string\";\nimport { DEFAULT_VERSION, LOCAL_PSEUDO_CATEGORY } from \"../../consts\";\nimport type {\n CategoryDefinition,\n CategoryMap,\n Domain,\n ExtractedSkillMetadata,\n MergedSkillsMatrix,\n RelationshipDefinitions,\n ResolvedSkill,\n SkillAlternative,\n SkillId,\n SkillRelation,\n SkillRequirement,\n SkillSlug,\n SkillSlugMap,\n Category,\n} from \"../../types\";\n\n/** Resolves a slug to a canonical SkillId, or null if unresolvable */\ntype ResolveId = (slug: SkillSlug, context?: string) => SkillId | null;\n\nconst AUTO_SYNTH_ORDER = 999;\n\n/**\n * Synthesizes a basic CategoryDefinition for a category not defined in any\n * skill-categories.ts. This is a safety net — the preferred path is for\n * skill authors to maintain proper skill-categories.ts entries.\n */\nexport function synthesizeCategory(category: Category, domain: Domain): CategoryDefinition {\n verbose(\n `Category '${category}' has no definition in skill-categories.ts — using auto-generated placeholder`,\n );\n const displayName = toTitleCase(category);\n\n return {\n id: category,\n displayName,\n description: `Auto-generated category for ${category}`,\n domain,\n exclusive: false,\n required: false,\n order: AUTO_SYNTH_ORDER,\n };\n}\n\n/**\n * Builds a bidirectional slug <-> ID map from extracted skill metadata.\n * Warns on duplicate slugs (first one wins).\n */\nfunction buildSlugMap(skills: ExtractedSkillMetadata[]): SkillSlugMap {\n const slugToId: Partial<Record<SkillSlug, SkillId>> = {};\n const idToSlug: Partial<Record<SkillId, SkillSlug>> = {};\n\n for (const skill of skills) {\n const existingId = slugToId[skill.slug];\n if (existingId) {\n warn(\n `Duplicate slug '${skill.slug}': already mapped to '${existingId}', ignoring '${skill.id}'`,\n );\n continue;\n }\n\n slugToId[skill.slug] = skill.id;\n idToSlug[skill.id] = skill.slug;\n }\n\n return { slugToId, idToSlug };\n}\n\nfunction resolveToCanonicalId(\n slug: SkillSlug,\n slugToId: SkillSlugMap[\"slugToId\"],\n context?: string,\n): SkillId | null {\n const slugResult = slugToId[slug];\n if (slugResult) {\n return slugResult;\n }\n const location = context ? ` in ${context}` : \"\";\n warn(`Unresolved slug '${slug}'${location} — skipping`);\n return null;\n}\n\n/**\n * Merges category definitions, relationship rules, and extracted skill metadata\n * into a fully resolved MergedSkillsMatrix.\n *\n * This is the core resolution step that combines:\n * - Category definitions from skill-categories.ts\n * - Slug-based alias maps derived from metadata\n * - Relationship rules from skill-rules.ts\n * - Extracted skill metadata (from scanning skill directories)\n *\n * Each skill's raw relationship references are resolved to canonical SkillIds.\n * The result is the complete data structure consumed by the wizard UI and validation logic.\n */\nexport function mergeMatrixWithSkills(\n categories: CategoryMap,\n relationships: RelationshipDefinitions,\n skills: ExtractedSkillMetadata[],\n): MergedSkillsMatrix {\n const slugMap = buildSlugMap(skills);\n const resolvedSkills: Partial<Record<SkillId, ResolvedSkill>> = {};\n\n for (const skill of skills) {\n const resolved = buildResolvedSkill(skill, categories, relationships, slugMap);\n resolvedSkills[skill.id] = resolved;\n }\n\n // Auto-synthesize missing categories for skills that reference undefined categories\n const synthesizedCategories = { ...categories };\n for (const skill of skills) {\n // Skip \"local\" pseudo-category — it's not a real Category union member\n if (skill.category === LOCAL_PSEUDO_CATEGORY) continue;\n if (!synthesizedCategories[skill.category]) {\n const synthesized = synthesizeCategory(skill.category, skill.domain);\n synthesizedCategories[skill.category] = synthesized;\n verbose(`Auto-synthesized category '${skill.category}' for skill '${skill.id}'`);\n }\n }\n\n const merged: MergedSkillsMatrix = {\n version: DEFAULT_VERSION,\n categories: synthesizedCategories,\n skills: resolvedSkills,\n suggestedStacks: [],\n slugMap,\n generatedAt: new Date().toISOString(),\n };\n\n return merged;\n}\n\n/** All resolved relationship data for a single skill */\ntype ResolvedRelationships = {\n conflictsWith: SkillRelation[];\n discourages: SkillRelation[];\n compatibleWith: SkillId[];\n requires: SkillRequirement[];\n alternatives: SkillAlternative[];\n};\n\n/** Resolves a rule's slugs to canonical ids, warning and skipping any that don't resolve. */\nfunction resolveSlugsOrSkip(slugs: SkillSlug[], resolve: ResolveId, context: string): SkillId[] {\n return slugs.map((slug) => resolve(slug, context)).filter((id): id is SkillId => id !== null);\n}\n\n/**\n * Members of the symmetric groups containing `skillId` (excluding itself),\n * deduplicated on first occurrence, each paired with its group's rule so the\n * caller can lift the annotation (reason/purpose).\n */\nfunction collectSymmetricGroupMembers<Rule extends { skills: SkillSlug[] }>(\n rules: readonly Rule[],\n skillId: SkillId,\n resolve: ResolveId,\n context: string,\n): Array<{ memberId: SkillId; rule: Rule }> {\n const members = rules.flatMap((rule) => {\n const resolved = resolveSlugsOrSkip(rule.skills, resolve, context);\n if (!resolved.includes(skillId)) return [];\n return resolved.filter((id) => id !== skillId).map((memberId) => ({ memberId, rule }));\n });\n return uniqueBy(members, (m) => m.memberId);\n}\n\n/**\n * Resolves all relationship data for a single skill in one pass across all\n * relationship rule types (conflicts, discourages, compatibility, requirements, alternatives).\n */\nfunction resolveRelationships(\n skillId: SkillId,\n relationships: RelationshipDefinitions,\n resolve: ResolveId,\n): ResolvedRelationships {\n // Symmetric groups: members of every group containing this skill, first-occurrence deduped\n const conflictsWith: SkillRelation[] = collectSymmetricGroupMembers(\n relationships.conflicts,\n skillId,\n resolve,\n \"conflicts\",\n ).map(({ memberId, rule }) => ({ skillId: memberId, reason: rule.reason }));\n\n const discourages: SkillRelation[] = collectSymmetricGroupMembers(\n relationships.discourages ?? [],\n skillId,\n resolve,\n \"discourages\",\n ).map(({ memberId, rule }) => ({ skillId: memberId, reason: rule.reason }));\n\n const compatibleWith: SkillId[] = collectSymmetricGroupMembers(\n relationships.compatibleWith ?? [],\n skillId,\n resolve,\n \"compatibleWith\",\n ).map(({ memberId }) => memberId);\n\n const alternatives: SkillAlternative[] = collectSymmetricGroupMembers(\n relationships.alternatives,\n skillId,\n resolve,\n \"alternatives\",\n ).map(({ memberId, rule }) => ({ skillId: memberId, purpose: rule.purpose }));\n\n // Requirements — directional, skill field identifies the dependent\n const requires: SkillRequirement[] = [];\n for (const rule of relationships.requires) {\n const ruleSkillId = resolve(rule.skill, \"requires.skill\");\n if (ruleSkillId !== skillId) continue;\n const resolvedNeeds = resolveSlugsOrSkip(rule.needs, resolve, \"requires.needs\");\n if (resolvedNeeds.length === 0) continue;\n requires.push({\n skillIds: resolvedNeeds,\n needsAny: rule.needsAny ?? false,\n reason: rule.reason,\n });\n }\n\n return {\n conflictsWith,\n discourages,\n compatibleWith,\n requires,\n alternatives,\n };\n}\n\nfunction buildResolvedSkill(\n skill: ExtractedSkillMetadata,\n _categories: CategoryMap,\n relationships: RelationshipDefinitions,\n slugMap: SkillSlugMap,\n): ResolvedSkill {\n const resolve: ResolveId = (slug, context) =>\n resolveToCanonicalId(slug, slugMap.slugToId, context ? `${skill.id} ${context}` : undefined);\n\n const slug = skill.slug;\n\n // Look up isRecommended/recommendedReason from flat recommends list (now slug-based)\n const recommendation = relationships.recommends.find((r) => r.skill === skill.slug);\n\n const resolved = resolveRelationships(skill.id, relationships, resolve);\n\n return {\n id: skill.id,\n slug,\n displayName: skill.displayName,\n description: skill.description,\n usageGuidance: skill.usageGuidance,\n category: skill.category,\n author: skill.author,\n ...resolved,\n isRecommended: recommendation != null,\n recommendedReason: recommendation?.reason,\n path: skill.path,\n ...(skill.custom === true ? { custom: true } : {}),\n };\n}\n","export function truncateText(text: string, maxLength: number): string {\n if (text.length <= maxLength) return text;\n return text.slice(0, maxLength - 1) + \"\\u2026\";\n}\n\n/** Converts a kebab-case string to a space-separated Title Case string. */\nexport function toTitleCase(kebabCase: string): string {\n return kebabCase\n .split(\"-\")\n .map((word) => word.charAt(0).toUpperCase() + word.slice(1))\n .join(\" \");\n}\n","import { groupBy } from \"remeda\";\nimport { LOCAL_PSEUDO_CATEGORY } from \"../../consts\";\nimport type {\n CategoryPath,\n OptionState,\n ResolvedSkill,\n SelectionValidation,\n SkillId,\n SkillOption,\n ValidationError,\n ValidationWarning,\n} from \"../../types\";\nimport { typedEntries } from \"../../utils/typed-object\";\nimport { mergeValidationResults } from \"../validation-result\";\nimport { matrix, getSkillById, allSkills } from \"./matrix-provider\";\n\nfunction getLabel(skill: Pick<ResolvedSkill, \"displayName\">): string {\n return skill.displayName;\n}\n\nfunction joinWithConjunction(items: string[], conjunction: \"or\" | \"and\"): string {\n if (items.length <= 1) return items[0] ?? \"\";\n if (items.length === 2) return `${items[0]} ${conjunction} ${items[1]}`;\n return `${items.slice(0, -1).join(\", \")} ${conjunction} ${items[items.length - 1]}`;\n}\n\ntype SelectionContext = {\n resolvedSelections: SkillId[];\n selectedSet: Set<SkillId>;\n};\n\nfunction initializeSelectionContext(currentSelections: SkillId[]): SelectionContext {\n const resolvedSelections = currentSelections.map((s) => getSkillById(s).id);\n const selectedSet = new Set<SkillId>(resolvedSelections);\n return { resolvedSelections, selectedSet };\n}\n\n/**\n * Finds all currently selected skills that depend on the given skill.\n *\n * A skill is considered dependent if it has a requirement that would become\n * unsatisfied by removing `skillId`. For `needsAny` requirements, the skill\n * is only dependent if `skillId` is the sole remaining option satisfying\n * that requirement.\n *\n * @param skillId - The skill to check dependents for (resolved via alias lookup)\n * @param currentSelections - Currently selected skill IDs in the wizard\n * @returns Skill IDs that would lose a required dependency if `skillId` were removed\n */\nexport function getDependentSkills(skillId: SkillId, currentSelections: SkillId[]): SkillId[] {\n getSkillById(skillId); // assert the id exists in the matrix\n\n const { resolvedSelections, selectedSet } = initializeSelectionContext(currentSelections);\n return resolvedSelections.filter(\n (selectedId) =>\n selectedId !== skillId &&\n getSkillById(selectedId).requires.some((req) =>\n wouldLoseRequirement(req, skillId, selectedSet),\n ),\n );\n}\n\ntype SkillRequirement = ResolvedSkill[\"requires\"][number];\n\n/** OR (`needsAny`): met when ANY option is selected. AND: met when EVERY id is selected. */\nfunction isRequirementMet(req: SkillRequirement, selectedSet: ReadonlySet<SkillId>): boolean {\n return req.needsAny\n ? req.skillIds.some((id) => selectedSet.has(id))\n : req.skillIds.every((id) => selectedSet.has(id));\n}\n\n/** Ids blocking the requirement: every option for an unmet OR, the absent ids for an AND. */\nfunction missingRequirementIds(\n req: SkillRequirement,\n selectedSet: ReadonlySet<SkillId>,\n): SkillId[] {\n if (isRequirementMet(req, selectedSet)) return [];\n return req.needsAny ? [...req.skillIds] : req.skillIds.filter((id) => !selectedSet.has(id));\n}\n\n/**\n * True when removing `removedId` would leave this requirement unsatisfied:\n * for OR it must be the sole remaining satisfier; for AND, any required id.\n */\nfunction wouldLoseRequirement(\n req: SkillRequirement,\n removedId: SkillId,\n selectedSet: ReadonlySet<SkillId>,\n): boolean {\n if (req.needsAny) {\n const satisfied = req.skillIds.filter((id) => selectedSet.has(id));\n return satisfied.length === 1 && satisfied[0] === removedId;\n }\n return req.skillIds.includes(removedId);\n}\n\n/**\n * For an unselected skill, finds the first selected skill that needs it\n * and whose requirement is currently unmet. Returns the dependent's display name,\n * or undefined if no selected skill has an unmet need for this skill.\n */\nexport function getUnmetRequiredBy(\n skillId: SkillId,\n currentSelections: SkillId[],\n): string | undefined {\n getSkillById(skillId); // assert the id exists in the matrix\n const { resolvedSelections, selectedSet } = initializeSelectionContext(currentSelections);\n\n if (selectedSet.has(skillId)) return undefined;\n\n for (const selectedId of resolvedSelections) {\n const selectedSkill = matrix.skills[selectedId];\n if (!selectedSkill) continue;\n\n for (const req of selectedSkill.requires) {\n if (!req.skillIds.includes(skillId)) continue;\n\n if (req.needsAny) {\n // OR: unmet only if NONE of the options are selected\n if (!req.skillIds.some((id) => selectedSet.has(id))) {\n return selectedSkill.displayName;\n }\n } else {\n // AND: unmet if this specific skill isn't selected\n return selectedSkill.displayName;\n }\n }\n }\n\n return undefined;\n}\n\n/**\n * Determines whether a skill should be discouraged (shown with yellow warning)\n * in the wizard given the current selection state.\n *\n * A skill is discouraged when it has a `discourages` relationship with a\n * currently selected skill (bidirectional check).\n *\n * @param skillId - The skill to check (resolved via alias lookup)\n * @param currentSelections - Currently selected skill IDs\n * @returns true if the skill should show a discouraged warning\n */\nexport function isDiscouraged(skillId: SkillId, currentSelections: SkillId[]): boolean {\n return getDiscourageReason(skillId, currentSelections) !== undefined;\n}\n\n/**\n * Determines whether a skill is incompatible with the current selection state\n * (shown with red warning). Checks conflictsWith relationships and also\n * detects unsatisfiable requires (all required dependencies conflict with selections).\n *\n * @param skillId - The skill to check (resolved via alias lookup)\n * @param currentSelections - Currently selected skill IDs\n * @returns true if the skill has conflicts with current selections\n */\nexport function isIncompatible(skillId: SkillId, currentSelections: SkillId[]): boolean {\n return getIncompatibleReason(skillId, currentSelections) !== undefined;\n}\n\n/** True if the skill directly conflicts with any selected skill (bidirectional). */\nfunction hasDirectConflict(skill: ResolvedSkill, selections: SkillId[]): boolean {\n return selections.some(\n (selectedId) =>\n skill.conflictsWith.some((c) => c.skillId === selectedId) ||\n matrix.skills[selectedId]?.conflictsWith.some((c) => c.skillId === skill.id),\n );\n}\n\n/** True if a dependency skill directly conflicts with any selected skill. */\nfunction isDepBlockedByConflict(depId: SkillId, selections: SkillId[]): boolean {\n const depSkill = matrix.skills[depId];\n return depSkill ? hasDirectConflict(depSkill, selections) : false;\n}\n\n/**\n * True when the skill has no compatibleWith constraints (universal) or shares\n * one with the current selections.\n */\nexport function isCompatibleWithSelections(skill: ResolvedSkill, selectedIds: SkillId[]): boolean {\n return (\n skill.compatibleWith.length === 0 || selectedIds.some((id) => skill.compatibleWith.includes(id))\n );\n}\n\n/**\n * True if the skill declares compatibleWith frameworks and none of\n * them are in the current selections. Empty compatibleWith = universal.\n * e.g. Zustand is compatible with [react, nextjs, remix] — incompatible when Svelte is selected.\n */\nfunction isIncompatibleByFramework(skill: ResolvedSkill, selections: SkillId[]): boolean {\n return selections.length > 0 && !isCompatibleWithSelections(skill, selections);\n}\n\n/**\n * Checks if a selected skill has unmet dependency requirements.\n * Only meaningful for skills that are currently selected.\n */\nexport function hasUnmetRequirements(skillId: SkillId, currentSelections: SkillId[]): boolean {\n return getUnmetRequirementsReason(skillId, currentSelections) !== undefined;\n}\n\n/**\n * Returns a human-readable reason why a skill is discouraged, or undefined if it is not.\n *\n * Checks discourages relationships (bidirectional), returning the first matching reason.\n *\n * @param skillId - The skill to get the discourage reason for\n * @param currentSelections - Currently selected skill IDs\n * @returns Formatted reason string or undefined\n */\nexport function getDiscourageReason(\n skillId: SkillId,\n currentSelections: SkillId[],\n): string | undefined {\n const skill = getSkillById(skillId);\n\n const { resolvedSelections } = initializeSelectionContext(currentSelections);\n\n // Check discourages relationships (bidirectional)\n for (const selectedId of resolvedSelections) {\n const selectedSkill = matrix.skills[selectedId];\n if (selectedSkill) {\n const discourage = selectedSkill.discourages.find((d) => d.skillId === skillId);\n if (discourage) {\n return discourage.reason;\n }\n }\n\n const reverseDiscourage = skill.discourages.find((d) => d.skillId === selectedId);\n if (reverseDiscourage) {\n return reverseDiscourage.reason;\n }\n }\n\n return undefined;\n}\n\n/**\n * Returns a human-readable reason why a skill is incompatible, or undefined if it is not.\n *\n * Only checks conflicts (bidirectional), returning the first matching reason.\n *\n * @param skillId - The skill to get the incompatible reason for\n * @param currentSelections - Currently selected skill IDs\n * @returns Formatted reason string or undefined\n */\nexport function getIncompatibleReason(\n skillId: SkillId,\n currentSelections: SkillId[],\n): string | undefined {\n const skill = getSkillById(skillId);\n\n const { resolvedSelections } = initializeSelectionContext(currentSelections);\n\n // Direct conflict (bidirectional)\n const directReason = findDirectConflictReason(skill, skillId, resolvedSelections);\n if (directReason) return directReason;\n\n // Unsatisfiable requires — dependency blocked by conflict\n const reqReason = findUnsatisfiableRequiresReason(skill, resolvedSelections);\n if (reqReason) return reqReason;\n\n // Framework compatibility mismatch\n if (isIncompatibleByFramework(skill, resolvedSelections)) {\n const compatLabels = skill.compatibleWith.map((id) => getLabel(getSkillById(id))).join(\", \");\n return `only compatible with ${compatLabels}`;\n }\n\n return undefined;\n}\n\nfunction findDirectConflictReason(\n skill: ResolvedSkill,\n skillId: SkillId,\n selections: SkillId[],\n): string | undefined {\n for (const selectedId of selections) {\n if (skill.conflictsWith.some((c) => c.skillId === selectedId)) {\n return `conflicts with ${getLabel(getSkillById(selectedId))}`;\n }\n const selectedSkill = matrix.skills[selectedId];\n if (selectedSkill?.conflictsWith.some((c) => c.skillId === skillId)) {\n return `conflicts with ${getLabel(selectedSkill)}`;\n }\n }\n return undefined;\n}\n\nfunction findUnsatisfiableRequiresReason(\n skill: ResolvedSkill,\n selections: SkillId[],\n): string | undefined {\n for (const req of skill.requires) {\n if (req.needsAny) {\n const allBlocked = req.skillIds.every((depId) => isDepBlockedByConflict(depId, selections));\n if (allBlocked) {\n const labels = joinWithConjunction(\n req.skillIds.map((id) => getLabel(getSkillById(id))),\n \"or\",\n );\n return `requires ${labels} (all conflict with current selection)`;\n }\n } else {\n const blockedDep = req.skillIds.find((depId) => isDepBlockedByConflict(depId, selections));\n if (blockedDep) {\n return `requires ${getLabel(getSkillById(blockedDep))} which conflicts with current selection`;\n }\n }\n }\n return undefined;\n}\n\n/**\n * Returns a human-readable reason for unmet requirements, or undefined if all are met.\n */\nexport function getUnmetRequirementsReason(\n skillId: SkillId,\n currentSelections: SkillId[],\n): string | undefined {\n const skill = getSkillById(skillId);\n\n const { selectedSet } = initializeSelectionContext(currentSelections);\n\n for (const requirement of skill.requires) {\n const missing = missingRequirementIds(requirement, selectedSet);\n if (missing.length === 0) continue;\n const names = missing.map((id) => {\n const s = matrix.skills[id];\n return s ? getLabel(s) : id;\n });\n return requirement.needsAny\n ? `requires ${joinWithConjunction(names, \"or\")}`\n : `requires ${joinWithConjunction(names, \"and\")}`;\n }\n\n return undefined;\n}\n\n/**\n * Checks if a skill is recommended based on the flat recommends list\n * and compatibility with current selections.\n *\n * A skill is recommended when:\n * 1. It appears in the flat recommends list (isRecommended === true), AND\n * 2. It is compatible with the user's current selections (shares a compatibleWith\n * group with at least one selected skill, or has no compatibility constraints)\n */\nexport function isRecommended(skillId: SkillId, currentSelections: SkillId[]): boolean {\n const skill = getSkillById(skillId);\n\n if (!skill.isRecommended) {\n return false;\n }\n\n // If no selections yet, isRecommended alone is sufficient\n if (currentSelections.length === 0) {\n return true;\n }\n\n const { resolvedSelections } = initializeSelectionContext(currentSelections);\n return isCompatibleWithSelections(skill, resolvedSelections);\n}\n\n/** Returns the reason from the flat recommends entry */\nexport function getRecommendReason(\n skillId: SkillId,\n _currentSelections: SkillId[],\n): string | undefined {\n const skill = getSkillById(skillId);\n\n return skill.recommendedReason;\n}\n\nexport type ValidationPartial = Pick<SelectionValidation, \"errors\" | \"warnings\">;\n\nexport function validateConflicts(resolvedSelections: SkillId[]): ValidationPartial {\n const errors: ValidationError[] = [];\n\n for (let i = 0; i < resolvedSelections.length; i++) {\n const skillA = matrix.skills[resolvedSelections[i]];\n if (!skillA) continue;\n\n for (let j = i + 1; j < resolvedSelections.length; j++) {\n const skillBId = resolvedSelections[j];\n const conflict = skillA.conflictsWith.find((c) => c.skillId === skillBId);\n if (conflict) {\n errors.push({\n type: \"conflict\",\n message: `${getLabel(skillA)} conflicts with ${getLabel(getSkillById(skillBId))}: ${conflict.reason}`,\n skills: [skillA.id, skillBId],\n });\n }\n }\n }\n\n return { errors, warnings: [] };\n}\n\nexport function validateRequirements(\n resolvedSelections: SkillId[],\n selectedSet: Set<SkillId>,\n): ValidationPartial {\n const errors: ValidationError[] = [];\n\n for (const skillId of resolvedSelections) {\n const skill = matrix.skills[skillId];\n if (!skill) continue;\n\n for (const requirement of skill.requires) {\n if (requirement.needsAny) {\n const hasAny = requirement.skillIds.some((reqId) => selectedSet.has(reqId));\n if (!hasAny) {\n errors.push({\n type: \"missingRequirement\",\n message: `${getLabel(skill)} requires one of: ${requirement.skillIds.map((id) => getLabel(getSkillById(id))).join(\", \")}`,\n skills: [skillId, ...requirement.skillIds],\n });\n }\n } else {\n const missingIds = requirement.skillIds.filter((reqId) => !selectedSet.has(reqId));\n if (missingIds.length > 0) {\n errors.push({\n type: \"missingRequirement\",\n message: `${getLabel(skill)} requires: ${missingIds.map((id) => getLabel(getSkillById(id))).join(\", \")}`,\n skills: [skillId, ...missingIds],\n });\n }\n }\n }\n }\n\n return { errors, warnings: [] };\n}\n\nexport function validateExclusivity(resolvedSelections: SkillId[]): ValidationPartial {\n const errors: ValidationError[] = [];\n\n const validSkills = resolvedSelections\n .map((skillId) => ({ skillId, skill: matrix.skills[skillId] }))\n .filter((entry): entry is { skillId: SkillId; skill: ResolvedSkill } => entry.skill != null);\n const categorySelections = groupBy(validSkills, (entry) => entry.skill.category);\n\n for (const [categoryId, entries] of typedEntries(categorySelections)) {\n if (entries.length > 1) {\n const skillIds = entries.map((e) => e.skillId);\n // \"local\" is a pseudo-category without exclusivity rules\n if (categoryId === LOCAL_PSEUDO_CATEGORY) continue;\n const category = matrix.categories[categoryId];\n if (category?.exclusive) {\n errors.push({\n type: \"categoryExclusive\",\n message: `Category \"${category.displayName}\" only allows one selection, but multiple selected: ${skillIds.map((id) => getLabel(getSkillById(id))).join(\", \")}`,\n skills: skillIds,\n });\n }\n }\n }\n\n return { errors, warnings: [] };\n}\n\n/**\n * Validates recommendations: for each recommended skill that is NOT selected\n * but IS compatible with current selections, produce a missing_recommendation warning.\n */\nexport function validateRecommendations(\n resolvedSelections: SkillId[],\n selectedSet: Set<SkillId>,\n): ValidationPartial {\n const warnings: ValidationWarning[] = [];\n\n // Iterate the flat recommends list from relationships\n for (const skill of allSkills()) {\n if (!skill.isRecommended) continue;\n if (selectedSet.has(skill.id)) continue;\n\n if (!isCompatibleWithSelections(skill, resolvedSelections)) continue;\n\n // Check no conflict with current selections\n const hasConflict = skill.conflictsWith.some((c) => selectedSet.has(c.skillId));\n if (hasConflict) continue;\n\n warnings.push({\n type: \"missing_recommendation\",\n message: `${getLabel(skill)} is recommended: ${skill.recommendedReason ?? \"Recommended for this stack\"}`,\n skills: [skill.id],\n });\n }\n\n return { errors: [], warnings };\n}\n\n/**\n * Validates a complete set of skill selections against all matrix constraints.\n *\n * Runs four validation passes:\n * 1. **Conflicts** - Checks for mutually exclusive skill pairs (errors)\n * 2. **Requirements** - Checks that all required dependencies are selected (errors)\n * 3. **Exclusivity** - Checks that exclusive categories have at most one selection (errors)\n * 4. **Recommendations** - Checks for missing recommended companion skills (warnings)\n *\n * @param selections - Complete list of selected skill IDs to validate\n * @returns Validation result with `valid` flag, error list, and warning list\n */\nexport function validateSelection(selections: SkillId[]): SelectionValidation {\n const { resolvedSelections, selectedSet } = initializeSelectionContext(selections);\n\n const { errors, warnings } = mergeValidationResults([\n validateConflicts(resolvedSelections),\n validateRequirements(resolvedSelections, selectedSet),\n validateExclusivity(resolvedSelections),\n validateRecommendations(resolvedSelections, selectedSet),\n ]);\n\n return {\n valid: true,\n errors,\n warnings,\n };\n}\n\nfunction computeAdvisoryState(skillId: SkillId, currentSelections: SkillId[]): OptionState {\n // Priority: incompatible > discouraged > recommended > normal\n const incompatibleReason = getIncompatibleReason(skillId, currentSelections);\n if (incompatibleReason !== undefined) {\n return { status: \"incompatible\", reason: incompatibleReason };\n }\n const discourageReason = getDiscourageReason(skillId, currentSelections);\n if (discourageReason !== undefined) {\n return { status: \"discouraged\", reason: discourageReason };\n }\n if (isRecommended(skillId, currentSelections)) {\n return {\n status: \"recommended\",\n reason: getRecommendReason(skillId, currentSelections) ?? \"Recommended\",\n };\n }\n return { status: \"normal\" };\n}\n\n/**\n * Builds a list of skill options for a category, annotated with their current\n * advisory state relative to the wizard's selection state.\n *\n * Each skill is checked against the current selections to determine its visual\n * state in the wizard UI. States are prioritized:\n * incompatible > discouraged > recommended > normal.\n *\n * @param categoryId - Category path to filter skills by\n * @param currentSelections - Currently selected skill IDs\n * @returns Array of skill options with advisory state annotations\n */\nexport function getAvailableSkills(\n categoryId: CategoryPath,\n currentSelections: SkillId[],\n): SkillOption[] {\n const { selectedSet } = initializeSelectionContext(currentSelections);\n\n return getSkillsByCategory(categoryId).map((skill) => {\n const isSelected = selectedSet.has(skill.id);\n return {\n id: skill.id,\n advisoryState: computeAdvisoryState(skill.id, currentSelections),\n selected: isSelected,\n hasUnmetRequirements: isSelected && hasUnmetRequirements(skill.id, currentSelections),\n unmetRequirementsReason: isSelected\n ? getUnmetRequirementsReason(skill.id, currentSelections)\n : undefined,\n alternatives: skill.alternatives.map((a) => a.skillId),\n };\n });\n}\n\n/** Returns all resolved skills belonging to the given category. */\nexport function getSkillsByCategory(categoryId: CategoryPath): ResolvedSkill[] {\n return allSkills().filter((skill) => skill.category === categoryId);\n}\n","import type { ValidationResult } from \"../types\";\n\n/**\n * A passing validation result with no errors or warnings. A factory rather than a\n * shared constant so each caller owns its arrays — callers merge and prefix results,\n * and a shared instance would let one mutation leak into every other holder.\n */\nexport function validResult(): ValidationResult {\n return { valid: true, errors: [], warnings: [] };\n}\n\n/** A failing validation result carrying a single error message. */\nexport function invalidResult(message: string): ValidationResult {\n return { valid: false, errors: [message], warnings: [] };\n}\n\n/**\n * Flattens several validation partials into one result. `valid` is derived from\n * whether any errors were collected. Generic over the error/warning element type\n * so it serves both the string-based ValidationResult and object-based\n * SelectionValidation partials.\n */\nexport function mergeValidationResults<E, W>(\n results: ReadonlyArray<{ errors: E[]; warnings: W[] }>,\n): { valid: boolean; errors: E[]; warnings: W[] } {\n const errors = results.flatMap((r) => r.errors);\n const warnings = results.flatMap((r) => r.warnings);\n return { valid: errors.length === 0, errors, warnings };\n}\n","import { warn } from \"../../utils/logger\";\nimport { LOCAL_PSEUDO_CATEGORY } from \"../../consts\";\nimport type {\n CategoryDefinition,\n MergedSkillsMatrix,\n ResolvedSkill,\n SkillId,\n Category,\n} from \"../../types\";\nimport { typedEntries } from \"../../utils/typed-object\";\n\nexport type MatrixHealthIssue = {\n severity: \"warning\" | \"error\";\n finding: string;\n details: string;\n};\n\nexport function checkMatrixHealth(matrix: MergedSkillsMatrix): MatrixHealthIssue[] {\n const issues = [\n ...checkCategoryDomains(matrix),\n ...checkSkillCategories(matrix),\n ...checkSkillRelationRefs(matrix),\n ];\n\n for (const issue of issues) {\n warn(`[matrix] ${issue.details}`);\n }\n\n return issues;\n}\n\n// Categories without a domain won't appear in any wizard domain view\nfunction checkCategoryDomains(matrix: MergedSkillsMatrix): MatrixHealthIssue[] {\n return typedEntries<Category, CategoryDefinition>(matrix.categories)\n .filter(([, cat]) => cat !== undefined && !cat.domain)\n .map(([catId]) => ({\n severity: \"warning\" as const,\n finding: \"category-missing-domain\",\n details: `Category '${catId}' has no domain — it won't appear in any wizard domain view`,\n }));\n}\n\nfunction checkSkillCategories(matrix: MergedSkillsMatrix): MatrixHealthIssue[] {\n return typedEntries<SkillId, ResolvedSkill>(matrix.skills)\n .filter(\n ([, skill]) =>\n skill !== undefined &&\n // \"local\" is a pseudo-category that won't exist in matrix.categories — skip it\n skill.category !== LOCAL_PSEUDO_CATEGORY &&\n !matrix.categories[skill.category],\n )\n .map(([skillId, skill]) => ({\n severity: \"warning\" as const,\n finding: \"skill-unknown-category\",\n details: `Skill '${skillId}' references category '${skill.category}' which does not exist in the matrix`,\n }));\n}\n\n/** Every outgoing relation reference on a skill, tagged with the field it came from. */\nfunction relationRefs(skill: ResolvedSkill): Array<{ field: string; ref: SkillId }> {\n return [\n ...skill.compatibleWith.map((ref) => ({ field: \"compatibleWith\", ref })),\n ...skill.conflictsWith.map((relation) => ({ field: \"conflictsWith\", ref: relation.skillId })),\n ...skill.requires.flatMap((requirement) =>\n requirement.skillIds.map((ref) => ({ field: \"requires\", ref })),\n ),\n ];\n}\n\nfunction checkSkillRelationRefs(matrix: MergedSkillsMatrix): MatrixHealthIssue[] {\n return typedEntries<SkillId, ResolvedSkill>(matrix.skills).flatMap(([skillId, skill]) =>\n skill === undefined\n ? []\n : relationRefs(skill)\n .filter(({ ref }) => !matrix.skills[ref])\n .map(({ field, ref }) => ({\n severity: \"warning\" as const,\n finding: \"skill-unresolved-relation-ref\",\n details: `Skill '${skillId}' has unresolved reference '${ref}' in '${field}'`,\n })),\n );\n}\n","import path from \"path\";\n\nimport { ensureDir, writeFile } from \"../../utils/fs\";\nimport { DEFAULT_VERSION, PLUGIN_MANIFEST_DIR, STANDARD_FILES } from \"../../consts\";\nimport type { PluginAuthor, PluginManifest } from \"../../types\";\n\nconst PLUGIN_DIR_NAME = PLUGIN_MANIFEST_DIR;\nconst PLUGIN_MANIFEST_FILE = STANDARD_FILES.PLUGIN_JSON;\nconst SKILL_PLUGIN_PREFIX = \"\";\nconst AGENT_PLUGIN_PREFIX = \"agent-\";\n\nexport type SkillManifestOptions = {\n skillName: string;\n description?: string;\n author?: string;\n authorEmail?: string;\n version?: string;\n keywords?: string[];\n};\n\nexport type AgentManifestOptions = {\n agentName: string;\n description?: string;\n version?: string;\n};\n\nexport type StackManifestOptions = {\n stackName: string;\n description?: string;\n author?: string;\n authorEmail?: string;\n version?: string;\n keywords?: string[];\n hasSkills?: boolean;\n hasAgents?: boolean;\n hasHooks?: boolean;\n};\n\nfunction buildAuthor(name?: string, email?: string): PluginAuthor | undefined {\n if (!name) {\n return undefined;\n }\n return { name, ...(email ? { email } : {}) };\n}\n\nexport function generateSkillPluginManifest(options: SkillManifestOptions): PluginManifest {\n const author = buildAuthor(options.author, options.authorEmail);\n return {\n name: `${SKILL_PLUGIN_PREFIX}${options.skillName}`,\n version: options.version ?? DEFAULT_VERSION,\n skills: \"./skills/\",\n ...(options.description ? { description: options.description } : {}),\n ...(author ? { author } : {}),\n ...(options.keywords?.length ? { keywords: options.keywords } : {}),\n };\n}\n\nexport function generateAgentPluginManifest(options: AgentManifestOptions): PluginManifest {\n return {\n name: `${AGENT_PLUGIN_PREFIX}${options.agentName}`,\n version: options.version ?? DEFAULT_VERSION,\n agents: \"./agents/\",\n ...(options.description ? { description: options.description } : {}),\n };\n}\n\n// Note: Claude Code plugins don't support an agents field in the stack manifest —\n// agents are discovered from the ./agents/ directory automatically.\nexport function generateStackPluginManifest(options: StackManifestOptions): PluginManifest {\n const author = buildAuthor(options.author, options.authorEmail);\n return {\n name: options.stackName,\n version: options.version ?? DEFAULT_VERSION,\n ...(options.hasSkills ? { skills: \"./skills/\" } : {}),\n ...(options.description ? { description: options.description } : {}),\n ...(author ? { author } : {}),\n ...(options.keywords?.length ? { keywords: options.keywords } : {}),\n ...(options.hasHooks ? { hooks: \"./hooks/hooks.json\" } : {}),\n };\n}\n\nexport async function writePluginManifest(\n outputDir: string,\n manifest: PluginManifest,\n): Promise<string> {\n const pluginDir = path.join(outputDir, PLUGIN_DIR_NAME);\n const manifestPath = path.join(pluginDir, PLUGIN_MANIFEST_FILE);\n\n await ensureDir(pluginDir);\n\n const content = JSON.stringify(manifest, null, 2);\n await writeFile(manifestPath, content);\n\n return manifestPath;\n}\n\nexport function getPluginDir(outputDir: string): string {\n return path.join(outputDir, PLUGIN_DIR_NAME);\n}\n","import os from \"os\";\nimport path from \"path\";\n\nimport { zip } from \"remeda\";\n\nimport { fileExists, readFileSafe, readFile, glob } from \"../../utils/fs\";\nimport { verbose, warn } from \"../../utils/logger\";\nimport {\n CLAUDE_DIR,\n DEFAULT_PLUGIN_NAME,\n MAX_PLUGIN_FILE_SIZE,\n PLUGINS_SUBDIR,\n PLUGIN_MANIFEST_DIR,\n PLUGIN_MANIFEST_FILE,\n STANDARD_FILES,\n} from \"../../consts\";\nimport type { PluginManifest, SkillId } from \"../../types\";\nimport { matrix } from \"../matrix/matrix-provider\";\nimport { pluginManifestSchema } from \"../schemas\";\nimport { parseFrontmatter } from \"../loading/loader\";\n\nconst MAX_SKILL_NAME_LENGTH = 100;\n\nexport function getUserPluginsDir(): string {\n return path.join(os.homedir(), CLAUDE_DIR, PLUGINS_SUBDIR);\n}\n\nexport function getCollectivePluginDir(projectDir?: string): string {\n const dir = projectDir ?? process.cwd();\n return path.join(dir, CLAUDE_DIR, PLUGINS_SUBDIR, DEFAULT_PLUGIN_NAME);\n}\n\nexport function getProjectPluginsDir(projectDir?: string): string {\n const dir = projectDir ?? process.cwd();\n return path.join(dir, CLAUDE_DIR, PLUGINS_SUBDIR);\n}\n\nexport function getPluginSkillsDir(pluginDir: string): string {\n return path.join(pluginDir, \"skills\");\n}\n\nexport function getPluginAgentsDir(pluginDir: string): string {\n return path.join(pluginDir, \"agents\");\n}\n\nexport function getPluginManifestPath(pluginDir: string): string {\n return path.join(pluginDir, PLUGIN_MANIFEST_DIR, PLUGIN_MANIFEST_FILE);\n}\n\nexport async function readPluginManifest(pluginDir: string): Promise<PluginManifest | null> {\n const manifestPath = getPluginManifestPath(pluginDir);\n\n if (!(await fileExists(manifestPath))) {\n verbose(` No manifest at ${manifestPath}`);\n return null;\n }\n\n try {\n const content = await readFileSafe(manifestPath, MAX_PLUGIN_FILE_SIZE);\n const manifest = pluginManifestSchema.parse(JSON.parse(content));\n\n if (!manifest.name || typeof manifest.name !== \"string\") {\n verbose(` Invalid manifest at ${manifestPath}: missing name`);\n return null;\n }\n\n return manifest;\n } catch (error) {\n verbose(` Failed to parse manifest at ${manifestPath}: ${error}`);\n return null;\n }\n}\n\nexport async function getPluginSkillIds(pluginSkillsDir: string): Promise<SkillId[]> {\n const skillFiles = await glob(`**/${STANDARD_FILES.SKILL_MD}`, pluginSkillsDir);\n const skillIds: SkillId[] = [];\n\n const fileContents = await Promise.all(\n skillFiles.map((skillFile) => readFile(path.join(pluginSkillsDir, skillFile))),\n );\n\n for (const [skillFile, content] of zip(skillFiles, fileContents)) {\n const fullPath = path.join(pluginSkillsDir, skillFile);\n const frontmatter = parseFrontmatter(content, fullPath);\n\n if (!frontmatter?.name) {\n warn(`Skipping plugin skill '${skillFile}': missing or invalid frontmatter name`);\n continue;\n }\n\n const skillName = frontmatter.name;\n\n if (skillName.length > MAX_SKILL_NAME_LENGTH) {\n warn(\n `Skipping plugin skill '${skillFile}': name exceeds ${MAX_SKILL_NAME_LENGTH} characters`,\n );\n continue;\n }\n\n if (matrix.skills[skillName]) {\n skillIds.push(skillName);\n } else {\n warn(`Skipping plugin skill '${skillFile}': '${skillName}' not found in skills matrix`);\n }\n }\n\n return skillIds;\n}\n","import type { ClaudePluginScope, SkillScope } from \"../../types/config.js\";\n\n/**\n * Marketplace-qualified plugin reference (`{id}@{marketplace}`) — the form the\n * Claude CLI plugin registry expects. Bare ids do not match registry entries.\n */\nexport function buildMarketplacePluginRef(id: string, marketplace: string): string {\n return `${id}@${marketplace}`;\n}\n\n/**\n * Inverse of buildMarketplacePluginRef: extracts the skill id from a\n * `{id}@{marketplace}` reference. Returns the whole string when no `@` is present.\n */\nexport function parseMarketplacePluginRef(ref: string): string {\n return ref.split(\"@\")[0];\n}\n\n/**\n * Maps a cc scope to the Claude CLI plugin scope: `\"global\"` installs are\n * user-scoped in Claude (registered in `~/.claude/settings.json`); anything\n * else — including an absent scope — is project-scoped.\n */\nexport function toClaudePluginScope(scope: SkillScope | undefined): ClaudePluginScope {\n return scope === \"global\" ? \"user\" : \"project\";\n}\n","import { readdir } from \"fs/promises\";\nimport type { Dirent } from \"fs\";\n\nimport { DEFAULT_DISPLAY_VERSION, DEFAULT_PLUGIN_NAME } from \"../../consts\";\nimport { verbose } from \"../../utils/logger\";\nimport { loadProjectConfig } from \"../configuration\";\nimport {\n detectInstallation,\n isHomeDirectory,\n resolveInstallPaths,\n INSTALL_MODE_LABELS,\n type Installation,\n type InstallMode,\n} from \"../installation\";\nimport type { SkillScope } from \"../../types/config\";\nimport { getProjectPluginsDir } from \"./plugin-finder\";\nimport { discoverAllPluginSkills, listPluginNames } from \"./plugin-discovery\";\n\nconst AGENT_FILE_EXTENSION = \".md\";\n\nexport type PluginInfo = {\n name: string;\n version: string;\n skillCount: number;\n agentCount: number;\n path: string;\n};\n\nexport type InstallationInfo = {\n mode: InstallMode;\n name: string;\n skillCount: number;\n agentCount: number;\n configPath: string;\n /** Every directory that actually holds compiled agents; empty when no scope has any. */\n agentDirs: string[];\n skillsDir: string;\n};\n\nexport async function getPluginInfo(projectDir?: string): Promise<PluginInfo | null> {\n const dir = projectDir ?? process.cwd();\n\n try {\n const pluginNames = await listPluginNames(dir);\n if (pluginNames.length > 0) {\n return {\n name: DEFAULT_PLUGIN_NAME,\n version: DEFAULT_DISPLAY_VERSION,\n skillCount: pluginNames.length,\n agentCount: 0,\n path: getProjectPluginsDir(dir),\n };\n }\n } catch {\n verbose(\"Failed to list plugins for plugin info\");\n }\n\n return null;\n}\n\nexport function formatPluginDisplay(info: PluginInfo): string {\n return `Plugin: ${info.name} v${info.version}\n Skills: ${info.skillCount}\n Agents: ${info.agentCount}\n Path: ${info.path}`;\n}\n\nexport async function getInstallationInfo(): Promise<InstallationInfo | null> {\n const installation = await detectInstallation();\n if (!installation) return null;\n\n const scopes = installedScopes(installation);\n const skillCount = await countInstalledSkills(installation, scopes);\n const agentDirCounts = await countCompiledAgentsPerScope(installation, scopes);\n\n const loaded = await loadProjectConfig(installation.projectDir);\n const name = loaded?.config?.name || DEFAULT_PLUGIN_NAME;\n\n return {\n mode: installation.mode,\n name,\n skillCount,\n agentCount: sumCounts(agentDirCounts),\n configPath: installation.configPath,\n agentDirs: agentDirCounts.filter(hasEntries).map((scopeCount) => scopeCount.dir),\n skillsDir: installation.skillsDir,\n };\n}\n\n/**\n * Scopes whose artifacts belong to this installation, in report order (global\n * first, mirroring the init success report). A project context also owns\n * everything installed globally under HOME, so both roots are counted; at the\n * home root the two resolve to the same directory and only one pass runs so\n * nothing is counted twice.\n */\nfunction installedScopes(installation: Installation): SkillScope[] {\n return isHomeDirectory(installation.projectDir) ? [\"project\"] : [\"global\", \"project\"];\n}\n\ntype ScopeCount = {\n dir: string;\n count: number;\n};\n\nfunction hasEntries(scopeCount: ScopeCount): boolean {\n return scopeCount.count > 0;\n}\n\nfunction sumCounts(scopeCounts: ScopeCount[]): number {\n return scopeCounts.reduce((total, scopeCount) => total + scopeCount.count, 0);\n}\n\nasync function sumOverScopes(\n scopes: SkillScope[],\n count: (scope: SkillScope) => Promise<number>,\n): Promise<number> {\n const counts = await Promise.all(scopes.map(count));\n return counts.reduce((total, current) => total + current, 0);\n}\n\n/** Plugin-mode skills live in the plugin registry, not under a scope's skills dir. */\nasync function countInstalledSkills(\n installation: Installation,\n scopes: SkillScope[],\n): Promise<number> {\n if (installation.mode === \"plugin\") return countPluginSkills(installation.projectDir);\n\n return sumOverScopes(scopes, (scope) =>\n countDirEntries(resolveInstallPaths(installation.projectDir, scope).skillsDir, (entry) =>\n entry.isDirectory(),\n ),\n );\n}\n\n/**\n * Compiled-agent count per scope, keyed by the directory it was read from, so\n * callers can both total the counts and name the directories the agents are\n * actually in — a default install driven from a project directory compiles\n * every agent under HOME, and naming the project directory there names a\n * directory that was never written.\n */\nasync function countCompiledAgentsPerScope(\n installation: Installation,\n scopes: SkillScope[],\n): Promise<ScopeCount[]> {\n return Promise.all(\n scopes.map(async (scope) => {\n const dir = resolveInstallPaths(installation.projectDir, scope).agentsDir;\n return { dir, count: await countDirEntries(dir, isCompiledAgentFile) };\n }),\n );\n}\n\nfunction isCompiledAgentFile(entry: Dirent): boolean {\n return entry.isFile() && entry.name.endsWith(AGENT_FILE_EXTENSION);\n}\n\n/** Counts entries in `dir` matching `pred`; 0 when the directory is missing or unreadable. */\nasync function countDirEntries(dir: string, pred: (entry: Dirent) => boolean): Promise<number> {\n try {\n const entries = await readdir(dir, { withFileTypes: true });\n return entries.filter(pred).length;\n } catch {\n return 0;\n }\n}\n\n/** Counts skills discoverable via settings.json and the global plugin cache; 0 on failure. */\nasync function countPluginSkills(projectDir: string): Promise<number> {\n try {\n return Object.keys(await discoverAllPluginSkills(projectDir)).length;\n } catch {\n return 0;\n }\n}\n\nexport function formatInstallationDisplay(info: InstallationInfo): string {\n const agentDirLines = info.agentDirs.map((dir) => `\\n Agents: ${dir}`).join(\"\");\n\n return `Installation: ${info.name}\n Mode: ${INSTALL_MODE_LABELS[info.mode]}\n Skills: ${info.skillCount}\n Agents: ${info.agentCount}\n Config: ${info.configPath}${agentDirLines}`;\n}\n","import os from \"os\";\nimport path from \"path\";\nimport { fileExists } from \"../../utils/fs\";\nimport { loadProjectConfigFromDir } from \"../configuration/project-config\";\nimport {\n CLAUDE_DIR,\n CLI_INVOKE_COMMAND,\n DEFAULT_BRANDING,\n PLUGINS_SUBDIR,\n STANDARD_DIRS,\n EJECT_SOURCE,\n} from \"../../consts\";\nimport { getProjectConfigPath } from \"./install-base-dir\";\nimport type { SkillConfig } from \"../../types/config\";\nimport type { InstallMode } from \"../../types/matrix\";\n\n// Re-exported from types/matrix.ts for existing importers of the installation barrel\nexport type { InstallMode };\n\nexport const INSTALL_MODE_LABELS = {\n plugin: \"Plugin\",\n mixed: \"Mixed\",\n eject: \"Eject\",\n} as const satisfies Record<InstallMode, string>;\n\nexport type Installation = {\n mode: InstallMode;\n configPath: string;\n agentsDir: string;\n skillsDir: string;\n projectDir: string;\n};\n\n/** Derive install mode from skills array at runtime */\nexport function deriveInstallMode(skills: SkillConfig[]): InstallMode {\n if (skills.length === 0) return \"eject\";\n const hasEject = skills.some((s) => s.source === EJECT_SOURCE);\n const hasPlugin = skills.some((s) => s.source !== EJECT_SOURCE);\n if (hasEject && hasPlugin) return \"mixed\";\n return hasEject ? \"eject\" : \"plugin\";\n}\n\n// Use loadProjectConfigFromDir directly (not detectInstallation) to avoid the\n// project→global fallback recursing back into this detection.\nasync function detectInstallationInDir(dir: string): Promise<Installation | null> {\n const configPath = getProjectConfigPath(dir);\n\n if (!(await fileExists(configPath))) {\n return null;\n }\n\n // The config file exists. loadProjectConfigFromDir throws ConfigLoadError for a\n // corrupt config, so a returned value is always a usable config — a corrupt\n // config surfaces to the caller (compile reports it) instead of silently\n // becoming a phantom eject installation that resurrects every built-in agent.\n const loaded = await loadProjectConfigFromDir(dir);\n if (!loaded) {\n // The file vanished between the fileExists check and the load.\n return null;\n }\n\n // A successfully-loaded config that declares neither skills nor agents is\n // content-less and does not count as an installation — init must route to the\n // setup wizard, not the dashboard. This is the shared detection function, so\n // returning null here covers both the project-config and global-config\n // manifestations.\n //\n // skills is asserted directly: loadProjectConfigFromDir defaults it to [].\n // agents is not defaulted by the loader, so it is guarded with `?? []` — the\n // same treatment agents gets elsewhere (see doctor.ts, config-writer.ts).\n if (loaded.config.skills.length === 0 && (loaded.config.agents ?? []).length === 0) {\n return null;\n }\n\n const mode: InstallMode = deriveInstallMode(loaded.config.skills);\n\n return {\n mode,\n configPath,\n agentsDir: path.join(dir, CLAUDE_DIR, STANDARD_DIRS.AGENTS),\n // Mixed mode has local skills in .claude/skills/ and plugins in cache;\n // use .claude/skills/ as the primary skillsDir (same as eject mode)\n skillsDir: path.join(dir, CLAUDE_DIR, mode === \"plugin\" ? PLUGINS_SUBDIR : \"skills\"),\n projectDir: dir,\n };\n}\n\n/** Detect installation in a specific directory only (no global fallback). */\nexport async function detectProjectInstallation(projectDir: string): Promise<Installation | null> {\n return detectInstallationInDir(projectDir);\n}\n\n/** Detect installation in the home directory (global scope). */\nexport async function detectGlobalInstallation(): Promise<Installation | null> {\n return detectInstallationInDir(os.homedir());\n}\n\n/**\n * Detect installation: checks project-level first, then falls back to global (home directory).\n * Project fully overrides global (no merging).\n */\nexport async function detectInstallation(\n projectDir: string = process.cwd(),\n): Promise<Installation | null> {\n // 1. Check project-level first\n const projectInstallation = await detectProjectInstallation(projectDir);\n if (projectInstallation) return projectInstallation;\n\n // 2. Fall back to global (home directory)\n return detectGlobalInstallation();\n}\n\nexport async function getInstallationOrThrow(\n projectDir: string = process.cwd(),\n): Promise<Installation> {\n const installation = await detectInstallation(projectDir);\n\n if (!installation) {\n throw new Error(\n `No ${DEFAULT_BRANDING.NAME} installation found.\\nRun '${CLI_INVOKE_COMMAND} init' to create one.`,\n );\n }\n\n return installation;\n}\n","import path from \"path\";\nimport { unique } from \"remeda\";\nimport type {\n AgentDefinition,\n AgentName,\n CompileAgentConfig,\n CompileConfig,\n ProjectConfig,\n SkillDefinition,\n SkillId,\n Stack,\n StackAgentConfig,\n} from \"../../types\";\nimport { isHomeDirectory } from \"./is-home-directory\";\nimport { resolveInstallPaths, type InstallPaths } from \"./install-base-dir\";\nimport { matrix } from \"../matrix/matrix-provider\";\nimport type { AgentScopeConfig, SkillConfig, SkillScope } from \"../../types/config\";\nimport type { WizardResultV2 } from \"../../components/wizard/wizard\";\nimport { type CopiedSkill } from \"../skills\";\nimport {\n type MergeResult,\n type AuthoritativeScope,\n mergeWithExistingConfig,\n loadProjectConfig,\n} from \"../configuration\";\nimport { loadMergedAgents, loadSkillsByIds, type SourceLoadResult } from \"../loading\";\nimport { loadStackById, getStackSkillIds } from \"../stacks\";\nimport { resolveAgents, buildSkillRefsFromConfig } from \"../resolver\";\nimport { createLiquidEngine } from \"../compiler\";\nimport { writeCompiledAgentsByScope } from \"../agents/write-compiled-agents\";\nimport { generateProjectConfigFromSkills, buildStackProperty } from \"../configuration\";\nimport { scopeEligibilityKey, isScopePairCompatible } from \"../configuration/config-generator\";\nimport {\n isActiveAt,\n activeSkillScopeMap,\n activeAgentScopeMap,\n effectivelyExcludedSkillIds,\n} from \"../configuration/scope-predicates\";\nimport { writeScopedFromWizard } from \"../config-gate/index.js\";\nimport { ensureDir } from \"../../utils/fs\";\nimport { verbose } from \"../../utils/logger\";\nimport { typedFromEntries } from \"../../utils/typed-object\";\nimport { DEFAULT_PLUGIN_NAME } from \"../../consts\";\n\ntype LocalResolvedSkill = SkillDefinition & {\n content: string;\n};\n\n/**\n * Options for the eject skill installation pipeline.\n *\n * Passed to {@link installEject} to drive the full installation flow:\n * skill copying, config generation, agent compilation, and file writing.\n */\nexport type EjectInstallOptions = {\n /** Wizard output containing selected skills, stack, install mode, and source selections */\n wizardResult: WizardResultV2;\n /** Loaded source data including the skills matrix, source path, and source configuration */\n sourceResult: SourceLoadResult;\n /** Absolute path to the project root where `.claude/` artifacts will be written */\n projectDir: string;\n /** Optional `--source` flag override (e.g., \"github:org/repo\"). Takes precedence over\n * source from config when writing the `source` field in config.ts */\n sourceFlag?: string;\n};\n\n/**\n * Result of a completed eject skill installation.\n *\n * Returned by {@link installEject} with details about what was written to disk,\n * enabling the caller to display a summary to the user.\n */\nexport type EjectInstallResult = {\n /** Skills that were copied to `.claude/skills/`, with source and destination paths */\n copiedSkills: CopiedSkill[];\n /** Final project configuration (may be merged with existing config.ts) */\n config: ProjectConfig;\n /** Absolute path to the written config.ts file */\n configPath: string;\n /** Agent names that were compiled and written to `.claude/agents/` */\n compiledAgents: AgentName[];\n /** Whether the config was merged with an existing config.ts (true) or freshly created (false) */\n wasMerged: boolean;\n /** Absolute path to the pre-existing config.ts that was merged, if any */\n mergedConfigPath?: string;\n /** Absolute path to the `.claude/skills/` directory */\n skillsDir: string;\n /** Absolute path to the `.claude/agents/` directory */\n agentsDir: string;\n};\n\nasync function prepareDirectories(paths: InstallPaths): Promise<void> {\n await ensureDir(paths.skillsDir);\n await ensureDir(paths.agentsDir);\n await ensureDir(path.dirname(paths.configPath));\n}\n\nexport function buildEjectSkillsMap(\n copiedSkills: CopiedSkill[],\n): Partial<Record<SkillId, LocalResolvedSkill>> {\n return typedFromEntries(\n copiedSkills.flatMap((cs) => {\n const skill = matrix.skills[cs.skillId];\n if (!skill) return [];\n return [\n [\n cs.skillId,\n {\n id: cs.skillId,\n description: skill.description,\n path: cs.destPath,\n content: \"\", // Content not needed for skill references\n },\n ],\n ];\n }),\n );\n}\n\n/**\n * Returns the ids of skills active in the CURRENT wizard selection that were\n * NOT active in the persisted PRIOR config. Filters `excluded: true` on both\n * sides — excluded entries don't participate in stack membership, so flipping\n * a skill from excluded back to active counts as \"newly added\".\n *\n * `priorSkills === undefined` (first init) collapses the prior active set to\n * empty — every current skill is new this session. The generator's seeding\n * branch is what actually produces useful output in that case, so treating\n * every skill as \"new\" is safe.\n */\nfunction computeNewlyAddedSkillIds(\n currentSkills: readonly SkillConfig[],\n priorSkills: readonly SkillConfig[] | undefined,\n): readonly SkillId[] {\n const priorActiveIds = new Set((priorSkills ?? []).filter((s) => !s.excluded).map((s) => s.id));\n const currentActiveIds = currentSkills.filter((s) => !s.excluded).map((s) => s.id);\n return unique(currentActiveIds.filter((id) => !priorActiveIds.has(id)));\n}\n\n/**\n * Returns `(agent, skillId)` keys whose scope-compatibility was GAINED this\n * session — the pair is scope-compatible now but was NOT scope-compatible (or\n * was absent entirely) in the persisted config. Admits pure scope-flip cases\n * that `computeNewlyAddedSkillIds` (keyed by id only) cannot express.\n *\n * Scope rule: `isScopePairCompatible` from config-generator — the single\n * definition shared with the generator's own compatibility filter.\n *\n * Keys are produced by `scopeEligibilityKey` so lookup membership matches the\n * generator's internal set-membership check.\n */\nfunction computeScopeEligibilityGained(\n currentSkills: readonly SkillConfig[],\n currentAgents: readonly AgentScopeConfig[],\n priorSkills: readonly SkillConfig[] | undefined,\n priorAgents: readonly AgentScopeConfig[] | undefined,\n): ReadonlySet<string> {\n const priorSkillScope = activeSkillScopeMap(priorSkills);\n const priorAgentScope = activeAgentScopeMap(priorAgents);\n\n const gained = new Set<string>();\n const activeCurrentSkills = currentSkills.filter((s) => !s.excluded);\n const activeCurrentAgents = currentAgents.filter((a) => !a.excluded);\n\n for (const agent of activeCurrentAgents) {\n for (const skill of activeCurrentSkills) {\n if (!isScopePairCompatible(skill.scope, agent.scope)) continue;\n\n const priorSkillScopeValue = priorSkillScope.get(skill.id);\n const priorAgentScopeValue = priorAgentScope.get(agent.name);\n const wasCompatiblePreviously =\n priorSkillScopeValue !== undefined &&\n priorAgentScopeValue !== undefined &&\n isScopePairCompatible(priorSkillScopeValue, priorAgentScopeValue);\n\n if (!wasCompatiblePreviously) {\n gained.add(scopeEligibilityKey(agent.name, skill.id));\n }\n }\n }\n return gained;\n}\n\n/**\n * The stack the written config carries.\n *\n * A producer that knows per-`(skill, agent)` assignments has already decided what every sub-agent\n * holds and what preloads, so its stack REPLACES the ownership-derived one rather than merging\n * with it. Ownership rules hand every scope-compatible skill to every selected agent — exactly the\n * curation a shared configuration exists to carry — and inherit `preloaded` from a prior or\n * stack-YAML entry, which is silent about what the sharer chose. A stack id in such a payload\n * still names the config's description, but its own expansion is not overlaid for the same reason:\n * it would add back the skills and agents the assignments left out.\n *\n * Only a stack the generator itself built is replaced. With no agents selected there is nothing to\n * own, and the absent key is what tells the merger to leave the stack already on disk alone.\n */\nfunction resolveStackProperty(\n generated: ProjectConfig[\"stack\"],\n assigned: WizardResultV2[\"assignedStack\"],\n): ProjectConfig[\"stack\"] {\n return generated && assigned ? assigned : generated;\n}\n\nasync function buildEjectConfig(\n wizardResult: WizardResultV2,\n sourceResult: SourceLoadResult,\n projectDir: string,\n): Promise<{ config: ProjectConfig; loadedStack: Stack | null }> {\n const skillIds = unique(wizardResult.skills.map((s) => s.id));\n verbose(\n `buildEjectConfig: selectedStackId='${wizardResult.selectedStackId}', ` +\n `skills=[${skillIds.join(\", \")}], ` +\n `selectedAgents=[${wizardResult.selectedAgents.join(\", \")}]`,\n );\n\n const loadedStack = wizardResult.selectedStackId\n ? await loadStackById(wizardResult.selectedStackId, sourceResult.sourcePath)\n : null;\n if (wizardResult.selectedStackId) {\n verbose(\n `buildEjectConfig: loadedStack=${loadedStack ? `found (id='${loadedStack.id}')` : \"NOT FOUND\"}`,\n );\n if (!loadedStack) {\n throw new Error(\n `Stack '${wizardResult.selectedStackId}' not found in config/stacks.ts. ` +\n `Available stacks are defined in the CLI's config/stacks.ts file.`,\n );\n }\n }\n\n const existing = await loadProjectConfig(projectDir);\n // Boundary cast: ProjectConfig.stack types agents as Record<string, StackAgentConfig>\n // (it comes from parsed TS/JSON); narrow to typed AgentName keys at the load boundary.\n // The `?? {}` is a first-init fallback when no prior config exists — not a silent\n // fallback on data that must exist.\n const existingStack = (existing?.config.stack ?? {}) as Partial<\n Record<AgentName, StackAgentConfig>\n >;\n\n // D-220 delta: skills that are new to this session's top-level selection\n // relative to the persisted config. The diff is filtered to active (non-excluded)\n // skills on BOTH sides — excluded entries are not \"present\" from the perspective\n // of stack membership, so flipping an exclusion back to active should register\n // as a newly-added skill. `existing === null` (first init) collapses to \"every\n // skill is new this session\", which the generator's seeding branch tolerates.\n const newlyAddedSkillIds = computeNewlyAddedSkillIds(\n wizardResult.skills,\n existing?.config.skills,\n );\n\n // D-220 scope-eligibility delta: `(agent, skillId)` pairs that are scope-compatible\n // NOW but were not scope-compatible in the persisted config (either the skill's\n // scope was flipped, the agent's scope was flipped, or one of them was absent\n // before). Admits the scope-flip case that a skill-id-only diff would miss.\n const scopeEligibilityGained = computeScopeEligibilityGained(\n wizardResult.skills,\n wizardResult.agentConfigs,\n existing?.config.skills,\n existing?.config.agents,\n );\n\n // Pass user's agent selection and skill configs to config generator.\n // Both skillConfigs and agentConfigs are always passed when selectedAgents is\n // set — the config generator enforces that invariant to prevent silent\n // \"project\" scope defaults on missing lookups.\n const agentOptions: {\n selectedAgents?: AgentName[];\n skillConfigs: SkillConfig[];\n agentConfigs: AgentScopeConfig[];\n existingStack: Partial<Record<AgentName, StackAgentConfig>>;\n newlyAddedSkillIds: readonly SkillId[];\n scopeEligibilityGained: ReadonlySet<string>;\n } = {\n skillConfigs: wizardResult.skills,\n agentConfigs: wizardResult.agentConfigs,\n existingStack,\n newlyAddedSkillIds,\n scopeEligibilityGained,\n ...(wizardResult.selectedAgents.length > 0 && {\n selectedAgents: wizardResult.selectedAgents,\n }),\n };\n\n // With a stack: overlay the YAML stack as `existingStack` so the ownership-based\n // builder inherits preloaded flags for (agent, category, skill) triples the stack\n // author marked. Ownership rules still govern which agents and categories land in\n // the final stack, so Phase A (init) and Phase B (edit) produce equivalent stacks\n // for the same selection.\n const effectiveOptions = loadedStack\n ? { ...agentOptions, existingStack: { ...buildStackProperty(loadedStack), ...existingStack } }\n : agentOptions;\n const generated = generateProjectConfigFromSkills(\n DEFAULT_PLUGIN_NAME,\n skillIds,\n effectiveOptions,\n );\n const stack = resolveStackProperty(generated.stack, wizardResult.assignedStack);\n const localConfig: ProjectConfig = {\n ...generated,\n ...(stack && { stack }),\n ...(loadedStack ? { description: loadedStack.description } : {}),\n };\n\n verbose(\n `buildEjectConfig result: stack=${localConfig.stack ? Object.keys(localConfig.stack).length + \" agents\" : \"UNDEFINED\"}, ` +\n `agents=[${localConfig.agents.map((a) => a.name).join(\", \")}], skills=${localConfig.skills.length}`,\n );\n\n return { config: localConfig, loadedStack };\n}\n\nexport function setConfigMetadata(\n config: ProjectConfig,\n wizardResult: WizardResultV2,\n sourceResult: SourceLoadResult,\n sourceFlag?: string,\n): ProjectConfig {\n const result = { ...config };\n\n // Only persist domains when non-empty (sparse output)\n if (wizardResult.selectedDomains && wizardResult.selectedDomains.length > 0) {\n result.domains = wizardResult.selectedDomains;\n }\n\n // Only persist selectedAgents when non-empty (sparse output)\n if (wizardResult.selectedAgents && wizardResult.selectedAgents.length > 0) {\n result.selectedAgents = wizardResult.selectedAgents;\n }\n\n if (sourceFlag) {\n result.source = sourceFlag;\n } else if (sourceResult.sourceConfig.source) {\n result.source = sourceResult.sourceConfig.source;\n }\n\n if (sourceResult.marketplace) {\n result.marketplace = sourceResult.marketplace;\n }\n\n return result;\n}\n\nexport async function buildAndMergeConfig(\n wizardResult: WizardResultV2,\n sourceResult: SourceLoadResult,\n projectDir: string,\n sourceFlag?: string,\n authoritativeScope?: AuthoritativeScope,\n): Promise<MergeResult> {\n const { config } = await buildEjectConfig(wizardResult, sourceResult, projectDir);\n verbose(\n `buildAndMergeConfig: before merge — stack=${config.stack ? Object.keys(config.stack).length + \" agents\" : \"UNDEFINED\"}`,\n );\n const configWithMetadata = setConfigMetadata(config, wizardResult, sourceResult, sourceFlag);\n const result = await mergeWithExistingConfig(configWithMetadata, {\n projectDir,\n authoritativeScope,\n // Skills the wizard could not resolve from the loaded source this session must survive an\n // authoritative edit — their absence from the wizard result is a resolution gap, not a\n // deselection (D-233 Scenario C data-loss guard).\n unresolvableSkillIds: wizardResult.unresolvableSkillIds,\n });\n verbose(\n `buildAndMergeConfig: after merge — stack=${result.config.stack ? Object.keys(result.config.stack).length + \" agents\" : \"UNDEFINED\"}, merged=${result.merged}`,\n );\n return result;\n}\n\nexport function buildCompileAgents(\n config: ProjectConfig,\n agents: Record<AgentName, AgentDefinition>,\n): Record<string, CompileAgentConfig> {\n const activeAgents = config.agents.filter((a) => !a.excluded);\n const excludedSkillIds = effectivelyExcludedSkillIds(config.skills);\n\n // D7 cross-scope safety net: build set of global skill IDs so global agents only see global skills\n const globalSkillIds = new Set(\n config.skills.filter((s) => isActiveAt(s, \"global\")).map((s) => s.id),\n );\n\n // D-217: attach per-skill `source` to each SkillReference so the compiler can\n // decide between `${id}:${id}` (plugin) and bare id (eject) on a per-skill\n // basis. Missing entries are intentional — user-authored local skills have no\n // SkillConfig and legitimately carry no source.\n const sourceById = new Map<SkillId, string>(config.skills.map((s) => [s.id, s.source]));\n\n const buildAgentCompileEntry = (agentConfig: AgentScopeConfig): CompileAgentConfig => {\n // Model/effort are the agent's own settings, not its skills' — a bare agent with no stack\n // entry still carries them, so they are resolved before the skill-less early-out.\n const tuning: CompileAgentConfig = {\n ...(agentConfig.model !== undefined && { model: agentConfig.model }),\n ...(agentConfig.effort !== undefined && { effort: agentConfig.effort }),\n };\n\n const agentStack = config.stack?.[agentConfig.name];\n if (!agentStack) return tuning;\n // Filter out excluded skills; global agents only see global skills (cross-scope safety net)\n const filteredRefs = buildSkillRefsFromConfig(agentStack)\n .filter(\n (ref) =>\n !excludedSkillIds.has(ref.id) &&\n (agentConfig.scope !== \"global\" || globalSkillIds.has(ref.id)),\n )\n .map((ref) => ({ ...ref, source: sourceById.get(ref.id) }));\n return { ...tuning, skills: filteredRefs };\n };\n\n return Object.fromEntries(\n activeAgents\n .filter((agentConfig) => agents[agentConfig.name])\n .map((agentConfig) => [agentConfig.name, buildAgentCompileEntry(agentConfig)]),\n );\n}\n\nexport function buildAgentScopeMap(config: ProjectConfig): Map<AgentName, SkillScope> {\n return activeAgentScopeMap(config.agents);\n}\n\n/**\n * Shared install tail: writes scoped configs, then compiles and writes agents.\n * Both install modes call this after building their merged config — only the\n * skills used for compilation and the plugin description differ.\n */\nasync function writeConfigAndCompileAgents(params: {\n finalConfig: ProjectConfig;\n agents: Record<AgentName, AgentDefinition>;\n localSkills: Partial<Record<SkillId, LocalResolvedSkill>>;\n sourceResult: SourceLoadResult;\n projectDir: string;\n paths: InstallPaths;\n isProjectInstall: boolean;\n description: string;\n}): Promise<AgentName[]> {\n const { finalConfig, agents, localSkills, sourceResult, projectDir, paths } = params;\n\n await writeScopedFromWizard({\n finalConfig,\n matrix: sourceResult.matrix,\n agents,\n projectDir,\n projectConfigPath: paths.configPath,\n // During init, the project installation is being created — it exists if we're in a project context\n projectInstallationExists: params.isProjectInstall,\n });\n\n const compileConfig: CompileConfig = {\n name: DEFAULT_PLUGIN_NAME,\n description: params.description,\n agents: buildCompileAgents(finalConfig, agents),\n };\n return compileAndWriteAgents(\n compileConfig,\n agents,\n localSkills,\n sourceResult,\n projectDir,\n paths.agentsDir,\n buildAgentScopeMap(finalConfig),\n );\n}\n\nasync function compileAndWriteAgents(\n compileConfig: CompileConfig,\n agents: Record<AgentName, AgentDefinition>,\n localSkills: Partial<Record<SkillId, LocalResolvedSkill>>,\n sourceResult: SourceLoadResult,\n projectDir: string,\n agentsDir: string,\n agentScopeMap?: Map<AgentName, SkillScope>,\n): Promise<AgentName[]> {\n const engine = await createLiquidEngine(projectDir);\n const resolvedAgents = await resolveAgents(\n agents,\n localSkills,\n compileConfig,\n sourceResult.sourcePath,\n );\n\n const outcomes = await writeCompiledAgentsByScope({\n resolvedAgents,\n sourcePath: sourceResult.sourcePath,\n engine,\n projectAgentsDir: agentsDir,\n agentScopeMap,\n });\n\n // Install treats any compile failure as fatal — surface the first one.\n const failure = outcomes.find((outcome) => !outcome.ok);\n if (failure && !failure.ok) throw failure.error;\n\n return outcomes.map((outcome) => outcome.name);\n}\n\n/** Result of plugin-mode config installation — same as EjectInstallResult without copied skills or skillsDir */\nexport type PluginConfigResult = Omit<EjectInstallResult, \"copiedSkills\" | \"skillsDir\">;\n\n/**\n * Generates config and compiles agents for plugin mode (without copying skills).\n *\n * Used when skills are installed as native plugins and should NOT be copied\n * to `.claude/skills/`. This function performs only:\n * 1. Creates `.claude/agents/` and `.claude-src/` directories\n * 2. Loads agent definitions from both the CLI and source repository\n * 3. Generates project config.ts from the wizard selections, merging with any\n * existing config\n * 4. Writes config.ts\n * 5. Compiles agent markdown files using Liquid templates and writes them to\n * `.claude/agents/`\n *\n * @param options - Installation options containing wizard result, source data,\n * project directory, and optional source flag override\n * @returns Result containing config and agent artifacts (no skills)\n * @throws {Error} If the selected stack ID is not found in config/stacks.ts\n */\nexport async function installPluginConfig(\n options: EjectInstallOptions,\n): Promise<PluginConfigResult> {\n const { wizardResult, sourceResult, projectDir, sourceFlag } = options;\n\n const projectPaths = resolveInstallPaths(projectDir, \"project\");\n\n // Create directories based on installation context, not data content.\n // ensureDir is idempotent (mkdir -p), so calling it when dirs already exist is safe.\n const isProjectInstall = !isHomeDirectory(projectDir);\n if (isProjectInstall) {\n await ensureDir(projectPaths.agentsDir);\n }\n await ensureDir(path.dirname(projectPaths.configPath));\n\n const agents = await loadMergedAgents(sourceResult.sourcePath);\n const mergeResult = await buildAndMergeConfig(wizardResult, sourceResult, projectDir, sourceFlag);\n const finalConfig = mergeResult.config;\n\n // Load skill metadata from source for compilation\n // (actual skill content will be loaded from plugins at runtime)\n const stackSkillIds = finalConfig.stack ? getStackSkillIds(finalConfig.stack) : [];\n // Boundary cast: loadSkillsByIds returns SkillDefinitionMap, LocalResolvedSkill extends SkillDefinition\n const skillsForCompilation = (await loadSkillsByIds(\n stackSkillIds.map((id) => ({ id })),\n sourceResult.sourcePath,\n )) as Partial<Record<SkillId, LocalResolvedSkill>>;\n\n const compiledAgentNames = await writeConfigAndCompileAgents({\n finalConfig,\n agents,\n localSkills: skillsForCompilation,\n sourceResult,\n projectDir,\n paths: projectPaths,\n isProjectInstall,\n description:\n finalConfig.description || `Plugin setup with ${wizardResult.skills.length} skills`,\n });\n\n return {\n config: finalConfig,\n configPath: projectPaths.configPath,\n compiledAgents: compiledAgentNames,\n wasMerged: mergeResult.merged,\n mergedConfigPath: mergeResult.existingConfigPath,\n agentsDir: projectPaths.agentsDir,\n };\n}\n\n/**\n * Executes the full eject skill installation pipeline.\n *\n * This is the main entry point for the \"eject\" install mode (as opposed to plugin mode).\n * It performs the following steps in order:\n * 1. Creates `.claude/skills/` and `.claude/agents/` directories\n * 2. Deletes local skills switching to alternate sources, then copies selected\n * skills from the source repository into `.claude/skills/` (flattened layout)\n * 3. Loads agent definitions from both the CLI and source repository\n * 4. Generates project config.ts from the wizard selections, merging with any\n * existing config\n * 5. Writes config.ts\n * 6. Compiles agent markdown files using Liquid templates and writes them to\n * `.claude/agents/`\n *\n * @param options - Installation options containing wizard result, source data,\n * project directory, and optional source flag override\n * @returns Result containing all written artifacts (skills, config, agents) and\n * metadata about the installation (merge status, paths)\n * @throws {Error} If the selected stack ID is not found in config/stacks.ts\n *\n * @remarks\n * **Side effects:** Creates directories and writes files under `{projectDir}/.claude/`.\n */\nexport async function installEject(options: EjectInstallOptions): Promise<EjectInstallResult> {\n const { wizardResult, sourceResult, projectDir, sourceFlag } = options;\n\n const projectPaths = resolveInstallPaths(projectDir, \"project\");\n const globalPaths = resolveInstallPaths(projectDir, \"global\");\n\n // Create directories based on installation context, not data content.\n // ensureDir is idempotent (mkdir -p), so calling it when dirs already exist is safe.\n const isProjectInstall = !isHomeDirectory(projectDir);\n if (isProjectInstall) {\n await prepareDirectories(projectPaths);\n } else {\n // Always ensure .claude-src/ exists for config (even when installing from ~/)\n await ensureDir(path.dirname(projectPaths.configPath));\n }\n // Always ensure global skills directory exists when there is a global installation context\n await ensureDir(globalPaths.skillsDir);\n\n // Copy skills to their scope-appropriate directories, replacing any stale\n // ejected copies of skills now sourced from a marketplace. Imported lazily:\n // copyLocalSkills lives in the operations layer (which imports back into\n // installation), so a static import here would form a load-time cycle.\n const { copyLocalSkills } = await import(\"../operations/skills/copy-local-skills\");\n const { projectCopied, globalCopied } = await copyLocalSkills(\n wizardResult.skills,\n projectDir,\n sourceResult,\n { deleteAlternateSourceSkills: true },\n );\n const copiedSkills = [...projectCopied, ...globalCopied];\n\n const ejectSkillsForResolution = buildEjectSkillsMap(copiedSkills);\n\n const agents = await loadMergedAgents(sourceResult.sourcePath);\n const mergeResult = await buildAndMergeConfig(wizardResult, sourceResult, projectDir, sourceFlag);\n const finalConfig = mergeResult.config;\n\n const compiledAgentNames = await writeConfigAndCompileAgents({\n finalConfig,\n agents,\n localSkills: ejectSkillsForResolution,\n sourceResult,\n projectDir,\n paths: projectPaths,\n isProjectInstall,\n description: finalConfig.description || `Eject setup with ${wizardResult.skills.length} skills`,\n });\n\n return {\n copiedSkills,\n config: finalConfig,\n configPath: projectPaths.configPath,\n compiledAgents: compiledAgentNames,\n wasMerged: mergeResult.merged,\n mergedConfigPath: mergeResult.existingConfigPath,\n skillsDir: projectPaths.skillsDir,\n agentsDir: projectPaths.agentsDir,\n };\n}\n","import { Liquid } from \"liquidjs\";\nimport path from \"path\";\nimport { pipe, flatMap, filter, uniqueBy } from \"remeda\";\nimport {\n readFile,\n readFileOptional,\n writeFile,\n ensureDir,\n remove,\n copy,\n glob,\n fileExists,\n directoryExists,\n} from \"../utils/fs\";\nimport { getErrorMessage } from \"../utils/errors\";\nimport { log, verbose, warn } from \"../utils/logger\";\nimport {\n CLAUDE_DIR,\n CLAUDE_SRC_DIR,\n DIRS,\n EJECT_SOURCE,\n PROJECT_ROOT,\n STANDARD_FILES,\n STANDARD_DIRS,\n} from \"../consts\";\nimport { resolveClaudeMd } from \"./resolver\";\nimport { validateCompiledAgent, printOutputValidationResult } from \"./output-validator\";\nimport type {\n AgentConfig,\n AgentName,\n CompiledAgentData,\n CompileContext,\n PluginSkillRef,\n Skill,\n} from \"../types\";\nimport { typedEntries } from \"../utils/typed-object\";\n\n/** Pattern matching Liquid template delimiters that could enable template injection */\nconst LIQUID_SYNTAX_PATTERN = /\\{\\{|\\}\\}|\\{%|%\\}/g;\n\n/**\n * Strips Liquid template syntax (`{{`, `}}`, `{%`, `%}`) from a string value.\n * Prevents template injection when user-controlled data is passed to the Liquid engine.\n *\n * @param value - Input string that may contain Liquid syntax\n * @param fieldName - Name of the field (for warning messages)\n * @returns Sanitized string with Liquid delimiters removed\n */\nexport function sanitizeLiquidSyntax<T extends string>(value: T, fieldName: string): T {\n if (!LIQUID_SYNTAX_PATTERN.test(value)) return value;\n LIQUID_SYNTAX_PATTERN.lastIndex = 0;\n const sanitized = value.replace(LIQUID_SYNTAX_PATTERN, \"\");\n warn(`Stripped Liquid template syntax from '${fieldName}' — possible template injection attempt`);\n // Boundary cast: .replace() widens the branded string T; stripping characters keeps it in T's domain\n return sanitized as T;\n}\n\nfunction sanitizeString<T extends string>(value: T | undefined, fieldName: string): T | undefined {\n if (value === undefined) return undefined;\n return sanitizeLiquidSyntax(value, fieldName);\n}\n\nfunction sanitizeStringArray(\n values: string[] | undefined,\n fieldName: string,\n): string[] | undefined {\n if (!values) return values;\n return values.map((v) => sanitizeLiquidSyntax(v, fieldName));\n}\n\nfunction sanitizeSkills(skills: Skill[]): Skill[] {\n return skills.map((s) => ({\n ...s,\n id: sanitizeLiquidSyntax(s.id, \"skill.id\"),\n description: sanitizeLiquidSyntax(s.description, \"skill.description\"),\n usage: sanitizeLiquidSyntax(s.usage, \"skill.usage\"),\n pluginRef: sanitizeString(s.pluginRef, \"skill.pluginRef\"),\n }));\n}\n\n/**\n * Sanitizes user-controlled metadata fields in compiled agent data to prevent\n * Liquid template injection. Strips `{{`, `}}`, `{%`, `%}` from agent\n * metadata and skill metadata before template rendering.\n *\n * Content fields (identity, playbook, output, criticalRequirementsTop,\n * criticalReminders) are passed through unchanged — LiquidJS does not\n * re-evaluate template syntax inside variable values, so double-curlies\n * in content (e.g. GitHub Actions `${{ secrets.X }}`) are safe.\n */\nexport function sanitizeCompiledAgentData(data: CompiledAgentData): CompiledAgentData {\n const sanitizedAgent: AgentConfig = {\n ...data.agent,\n name: sanitizeLiquidSyntax(data.agent.name, \"agent.name\"),\n title: sanitizeLiquidSyntax(data.agent.title, \"agent.title\"),\n description: sanitizeLiquidSyntax(data.agent.description, \"agent.description\"),\n tools: sanitizeStringArray(data.agent.tools, \"agent.tools\") ?? data.agent.tools,\n disallowedTools: sanitizeStringArray(data.agent.disallowedTools, \"agent.disallowedTools\"),\n model: sanitizeString(data.agent.model, \"agent.model\"),\n effort: sanitizeString(data.agent.effort, \"agent.effort\"),\n permissionMode: sanitizeString(data.agent.permissionMode, \"agent.permissionMode\"),\n };\n\n const sanitizedSkills = sanitizeSkills(data.skills);\n const sanitizedPreloaded = sanitizeSkills(data.preloadedSkills);\n const sanitizedDynamic = sanitizeSkills(data.dynamicSkills);\n const sanitizedPreloadedIds = data.preloadedSkillIds.map((id) =>\n sanitizeLiquidSyntax(id, \"preloadedSkillId\"),\n );\n\n return {\n agent: sanitizedAgent,\n identity: data.identity,\n playbook: data.playbook,\n output: data.output,\n criticalRequirementsTop: data.criticalRequirementsTop,\n criticalReminders: data.criticalReminders,\n skills: sanitizedSkills,\n preloadedSkills: sanitizedPreloaded,\n dynamicSkills: sanitizedDynamic,\n preloadedSkillIds: sanitizedPreloadedIds,\n };\n}\n\ntype AgentFiles = Pick<\n CompiledAgentData,\n \"identity\" | \"playbook\" | \"output\" | \"criticalRequirementsTop\" | \"criticalReminders\"\n>;\n\nasync function readAgentFiles(\n name: AgentName,\n agent: AgentConfig,\n projectRoot: string,\n): Promise<AgentFiles> {\n const agentSourceRoot = agent.sourceRoot || projectRoot;\n const agentBaseDir = agent.agentBaseDir || DIRS.agents;\n const agentDir = path.join(agentSourceRoot, agentBaseDir, agent.path || name);\n\n const identity = await readFile(path.join(agentDir, STANDARD_FILES.IDENTITY_MD));\n const playbook = await readFile(path.join(agentDir, STANDARD_FILES.PLAYBOOK_MD));\n const criticalRequirementsTop = await readFileOptional(\n path.join(agentDir, STANDARD_FILES.CRITICAL_REQUIREMENTS_MD),\n \"\",\n );\n const criticalReminders = await readFileOptional(\n path.join(agentDir, STANDARD_FILES.CRITICAL_REMINDERS_MD),\n \"\",\n );\n\n const agentPath = agent.path || name;\n const parts = agentPath.split(\"/\");\n const category = parts[0] || name;\n const categoryDir = path.join(agentSourceRoot, agentBaseDir, category);\n\n let output = await readFileOptional(path.join(agentDir, STANDARD_FILES.OUTPUT_MD), \"\");\n if (!output) {\n output = await readFileOptional(path.join(categoryDir, STANDARD_FILES.OUTPUT_MD), \"\");\n }\n\n return { identity, playbook, output, criticalRequirementsTop, criticalReminders };\n}\n\nexport function buildAgentTemplateContext(\n name: AgentName,\n agent: AgentConfig,\n files: AgentFiles,\n mapSkill: (skill: Skill) => Skill = (skill) => skill,\n): CompiledAgentData {\n const skills = agent.skills.map(mapSkill);\n const preloadedSkills = skills.filter((s) => s.preloaded);\n const dynamicSkills = skills.filter((s) => !s.preloaded);\n const preloadedSkillIds = preloadedSkills.map((s) => s.pluginRef ?? s.id);\n\n verbose(\n `Skills for ${name}: ${preloadedSkills.length} preloaded, ${dynamicSkills.length} dynamic`,\n );\n\n return {\n agent,\n ...files,\n skills,\n preloadedSkills,\n dynamicSkills,\n preloadedSkillIds,\n };\n}\n\n/**\n * Compiles a single agent into a rendered Markdown prompt by reading its\n * constituent files (identity, playbook, output, critical requirements/reminders)\n * and rendering them through a Liquid template.\n *\n * Skills are split into preloaded (content embedded in the compiled agent) and\n * dynamic (loaded via Skill tool at runtime). Output resolution falls back\n * from the agent-specific directory to the parent category directory.\n *\n * @param name - Agent identifier used for logging and as a directory name fallback\n * @param agent - Fully resolved agent config including skills, paths, and optional sourceRoot\n * @param projectRoot - Root directory of the project (used as base for agent file resolution)\n * @param engine - Pre-configured Liquid template engine with template roots\n * @returns Rendered Markdown string ready to be written to the output directory\n * @throws When required agent files (identity.md, playbook.md) are missing from disk\n */\nasync function compileAgent(\n name: AgentName,\n agent: AgentConfig,\n projectRoot: string,\n engine: Liquid,\n): Promise<string> {\n verbose(`Reading agent files for ${name}...`);\n const files = await readAgentFiles(name, agent, projectRoot);\n const data = buildAgentTemplateContext(name, agent, files);\n\n verbose(`Rendering template for ${name}...`);\n return engine.renderFile(\"agent\", sanitizeCompiledAgentData(data));\n}\n\n/**\n * Compiles all resolved agents into Markdown files and writes them to the output directory.\n *\n * Each agent is compiled via `compileAgent()`, validated for structural issues\n * (missing sections, placeholder text), and written to `{outputDir}/agents/{name}.md`.\n * Validation warnings are printed but do not prevent compilation.\n *\n * @param resolvedAgents - Map of agent names to fully resolved agent configs with skills\n * @param ctx - Compilation context providing projectRoot and outputDir paths\n * @param engine - Pre-configured Liquid template engine\n * @throws When any agent fails to compile (missing files, template errors)\n */\nexport async function compileAllAgents(\n resolvedAgents: Record<AgentName, AgentConfig>,\n ctx: CompileContext,\n engine: Liquid,\n): Promise<void> {\n const outDir = path.join(ctx.outputDir, STANDARD_DIRS.AGENTS);\n await ensureDir(outDir);\n\n let hasValidationIssues = false;\n\n for (const [name, agent] of typedEntries<AgentName, AgentConfig>(resolvedAgents)) {\n try {\n const output = await compileAgent(name, agent, ctx.projectRoot, engine);\n await writeFile(path.join(outDir, `${name}.md`), output);\n log(` ✓ ${name}.md`);\n\n const validationResult = validateCompiledAgent(output);\n if (!validationResult.valid || validationResult.warnings.length > 0) {\n hasValidationIssues = true;\n printOutputValidationResult(name, validationResult);\n }\n } catch (error) {\n const errorMessage = getErrorMessage(error);\n warn(`Failed to compile '${name}': ${errorMessage}`);\n throw new Error(\n `Failed to compile agent '${name}': ${errorMessage}. Check that all required files exist in src/agents/${agent.path || name}/`,\n { cause: error },\n );\n }\n }\n\n if (hasValidationIssues) {\n log(\"\");\n }\n}\n\n/**\n * Copies all skill files referenced by resolved agents into the output directory.\n *\n * Deduplicates skills across agents (by skill ID) and copies each skill's\n * content to `{outputDir}/skills/{id}/`. For folder-based skills, copies\n * SKILL.md, optional reference.md, examples/, and scripts/ subdirectories.\n * For single-file skills, copies the file as SKILL.md.\n *\n * @param resolvedAgents - Map of agent names to configs (skills extracted from all agents)\n * @param ctx - Compilation context providing projectRoot and outputDir paths\n * @throws When a skill file or directory is missing from the expected source path\n */\nexport async function compileAllSkills(\n resolvedAgents: Record<AgentName, AgentConfig>,\n ctx: CompileContext,\n): Promise<void> {\n const allSkills = pipe(\n Object.values(resolvedAgents),\n flatMap((a) => a.skills),\n filter((s) => Boolean(s.path)),\n );\n\n const uniqueSkills = uniqueBy(allSkills, (s) => s.id);\n\n for (const skill of uniqueSkills) {\n const id = skill.id;\n const outDir = path.join(ctx.outputDir, \"skills\", id);\n await ensureDir(outDir);\n\n const sourcePath = path.join(ctx.projectRoot, skill.path);\n const isFolder = skill.path.endsWith(\"/\");\n\n try {\n if (isFolder) {\n const mainContent = await readFile(path.join(sourcePath, STANDARD_FILES.SKILL_MD));\n await writeFile(path.join(outDir, STANDARD_FILES.SKILL_MD), mainContent);\n log(` ✓ skills/${id}/${STANDARD_FILES.SKILL_MD}`);\n\n const referenceContent = await readFileOptional(\n path.join(sourcePath, STANDARD_FILES.REFERENCE_MD),\n );\n if (referenceContent) {\n await writeFile(path.join(outDir, STANDARD_FILES.REFERENCE_MD), referenceContent);\n log(` ✓ skills/${id}/${STANDARD_FILES.REFERENCE_MD}`);\n }\n\n const examplesDir = path.join(sourcePath, STANDARD_DIRS.EXAMPLES);\n if (await fileExists(examplesDir)) {\n await copy(examplesDir, path.join(outDir, STANDARD_DIRS.EXAMPLES));\n log(` ✓ skills/${id}/${STANDARD_DIRS.EXAMPLES}/`);\n }\n\n const scriptsDir = path.join(sourcePath, STANDARD_DIRS.SCRIPTS);\n if (await fileExists(scriptsDir)) {\n await copy(scriptsDir, path.join(outDir, STANDARD_DIRS.SCRIPTS));\n log(` ✓ skills/${id}/${STANDARD_DIRS.SCRIPTS}/`);\n }\n } else {\n const content = await readFile(sourcePath);\n await writeFile(path.join(outDir, STANDARD_FILES.SKILL_MD), content);\n log(` ✓ skills/${id}/${STANDARD_FILES.SKILL_MD}`);\n }\n } catch (error) {\n const errorMessage = getErrorMessage(error);\n warn(`Failed to compile skill '${id}': ${errorMessage}`);\n throw new Error(\n `Failed to compile skill '${skill.id}': ${errorMessage}. Expected skill at: ${sourcePath}`,\n { cause: error },\n );\n }\n }\n}\n\n/**\n * Copies the stack-specific CLAUDE.md file to the compilation output directory.\n *\n * Resolves the CLAUDE.md path from the stack directory, reads its content, and\n * writes it to the parent of the output directory (alongside the agents/ folder).\n *\n * @param ctx - Compilation context with stackId, projectRoot, and outputDir\n * @throws When the stack's CLAUDE.md file is missing\n */\nexport async function copyClaudeMdToOutput(ctx: CompileContext): Promise<void> {\n const claudePath = await resolveClaudeMd(ctx.projectRoot, ctx.stackId);\n\n const content = await readFile(claudePath);\n const outputPath = path.join(ctx.outputDir, \"..\", STANDARD_FILES.CLAUDE_MD);\n await writeFile(outputPath, content);\n log(` ✓ ${STANDARD_FILES.CLAUDE_MD} (from stack)`);\n}\n\n/**\n * Copies all custom command Markdown files from the commands source directory\n * to the compilation output directory.\n *\n * Skips gracefully if no commands directory exists or contains no .md files.\n *\n * @param ctx - Compilation context with projectRoot and outputDir\n * @throws When a command file exists but cannot be read or written\n */\nexport async function compileAllCommands(ctx: CompileContext): Promise<void> {\n const commandsDir = path.join(ctx.projectRoot, DIRS.commands);\n const outDir = path.join(ctx.outputDir, STANDARD_DIRS.COMMANDS);\n\n if (!(await fileExists(commandsDir))) {\n log(\" - No commands directory found, skipping...\");\n return;\n }\n\n const files = await glob(\"*.md\", commandsDir);\n\n if (files.length === 0) {\n log(\" - No commands found, skipping...\");\n return;\n }\n\n await ensureDir(outDir);\n\n for (const file of files) {\n try {\n const content = await readFile(path.join(commandsDir, file));\n await writeFile(path.join(outDir, file), content);\n log(` ✓ ${file}`);\n } catch (error) {\n const errorMessage = getErrorMessage(error);\n warn(`Failed to compile command '${file}': ${errorMessage}`);\n throw new Error(\n `Failed to compile command '${file}': ${errorMessage}. Expected at: ${path.join(commandsDir, file)}`,\n { cause: error },\n );\n }\n }\n}\n\n/**\n * Creates a Liquid template engine with a layered template root hierarchy.\n *\n * Template resolution order (first match wins):\n * 1. Project-local templates: `{projectDir}/.claude-src/agents/_templates/`\n * 2. Legacy templates: `{projectDir}/.claude/templates/`\n * 3. Built-in templates: `{PROJECT_ROOT}/templates/`\n *\n * @param projectDir - Optional project directory for local template overrides\n * @returns Configured Liquid engine with `.liquid` extension and strict filters\n */\nexport async function createLiquidEngine(projectDir?: string): Promise<Liquid> {\n const roots: string[] = [];\n\n if (projectDir) {\n const srcTemplatesDir = path.join(\n projectDir,\n CLAUDE_SRC_DIR,\n STANDARD_DIRS.AGENTS,\n path.basename(DIRS.templates),\n );\n if (await directoryExists(srcTemplatesDir)) {\n roots.push(srcTemplatesDir);\n verbose(`Using local templates from: ${srcTemplatesDir}`);\n }\n\n const legacyTemplatesDir = path.join(projectDir, CLAUDE_DIR, STANDARD_DIRS.TEMPLATES);\n if (await directoryExists(legacyTemplatesDir)) {\n roots.push(legacyTemplatesDir);\n verbose(`Using legacy templates from: ${legacyTemplatesDir}`);\n }\n }\n\n roots.push(path.join(PROJECT_ROOT, DIRS.templates));\n\n return new Liquid({\n root: roots,\n extname: \".liquid\",\n strictVariables: false,\n strictFilters: true,\n });\n}\n\n/** Removes the agents/, skills/, and commands/ subdirectories from the output directory. */\nexport async function removeCompiledOutputDirs(outputDir: string): Promise<void> {\n await remove(path.join(outputDir, STANDARD_DIRS.AGENTS));\n await remove(path.join(outputDir, STANDARD_DIRS.SKILLS));\n await remove(path.join(outputDir, STANDARD_DIRS.COMMANDS));\n}\n\n/**\n * D-217: per-skill pluginRef decision. A skill renders as `${id}:${id}` only\n * when it has an explicit non-eject source on its SkillReference — i.e. it was\n * installed from a marketplace. `undefined` source (user-authored local skills\n * with no SkillConfig entry) and `\"eject\"` both fall through to bare id.\n */\nfunction derivePluginRef(skill: Skill): PluginSkillRef | undefined {\n if (skill.source === undefined || skill.source === EJECT_SOURCE) return undefined;\n return `${skill.id}:${skill.id}` as const;\n}\n\nexport async function compileAgentForPlugin(\n name: AgentName,\n agent: AgentConfig,\n fallbackRoot: string,\n engine: Liquid,\n): Promise<string> {\n verbose(`Compiling agent: ${name}`);\n\n const files = await readAgentFiles(name, agent, fallbackRoot);\n\n // D-217: per-skill pluginRef attachment. Each skill's own `source` decides\n // whether it renders as `${id}:${id}` (plugin-installed) or bare id (ejected).\n // This correctly handles mixed-mode agents where some skills are plugin and\n // others are ejected. Missing `source` (user-authored local skills with no\n // SkillConfig entry) falls through to bare id — the expected case, not a\n // silent fallback.\n const data = buildAgentTemplateContext(name, agent, files, (skill) => ({\n ...skill,\n pluginRef: derivePluginRef(skill),\n }));\n\n return engine.renderFile(\"agent\", sanitizeCompiledAgentData(data));\n}\n","import path from \"path\";\nimport { DIRS, STANDARD_FILES } from \"../consts\";\nimport type {\n AgentConfig,\n AgentDefinition,\n AgentName,\n Category,\n CompileAgentConfig,\n CompileConfig,\n ProjectConfig,\n Skill,\n SkillDefinitionMap,\n SkillReference,\n Stack,\n StackAgentConfig,\n} from \"../types\";\nimport { fileExists } from \"../utils/fs\";\nimport { verbose } from \"../utils/logger\";\nimport { typedKeys } from \"../utils/typed-object\";\nimport { resolveAgentConfigToSkills } from \"./stacks/stacks-loader\";\n\nexport async function resolveClaudeMd(projectRoot: string, stackId: string): Promise<string> {\n const stackClaude = path.join(projectRoot, DIRS.stacks, stackId, STANDARD_FILES.CLAUDE_MD);\n if (await fileExists(stackClaude)) return stackClaude;\n\n throw new Error(\n `Stack '${stackId}' is missing required ${STANDARD_FILES.CLAUDE_MD} file. Expected at: ${stackClaude}`,\n );\n}\n\nexport function resolveSkillReference(\n ref: SkillReference,\n skills: SkillDefinitionMap,\n): Skill | null {\n const definition = skills[ref.id];\n if (!definition) {\n verbose(`Skill '${ref.id}' not found in available skills, skipping`);\n return null;\n }\n return {\n ...definition,\n usage: ref.usage,\n preloaded: ref.preloaded ?? false,\n source: ref.source,\n };\n}\n\nexport function resolveSkillReferences(\n skillRefs: SkillReference[],\n skills: SkillDefinitionMap,\n): Skill[] {\n return skillRefs\n .map((ref) => resolveSkillReference(ref, skills))\n .filter((skill): skill is Skill => skill !== null);\n}\n\n/**\n * Builds skill references from a ProjectConfig stack mapping (agent -> category -> SkillAssignment[]).\n *\n * Values are normalized to SkillAssignment[] at load time (by normalizeStackRecord in project-config.ts).\n * Preserves preloaded flags from skill assignments.\n *\n * @param agentStack - Category-to-SkillAssignment[] mapping from ProjectConfig.stack for one agent\n * @returns Skill references with usage hints derived from category names\n */\nexport function buildSkillRefsFromConfig(agentStack: StackAgentConfig): SkillReference[] {\n return resolveAgentConfigToSkills(agentStack);\n}\n\n/**\n * Resolves skill references for an agent from a Stack definition.\n *\n * Stack values are already SkillAssignment[] normalized by loadStacks().\n * Returns an empty array if the agent is not present in the stack or has\n * no technology-specific skills configured.\n *\n * @param agentName - Agent to resolve skills for\n * @param stack - Loaded stack definition with normalized skill assignments\n * @returns Skill references with usage and preloaded flags from the stack\n */\nexport function resolveAgentSkillsFromStack(agentName: AgentName, stack: Stack): SkillReference[] {\n const agentConfig = stack.agents[agentName];\n\n if (!agentConfig) {\n verbose(`Agent '${agentName}' not found in stack '${stack.id}'`);\n return [];\n }\n\n // Empty config {} means agent has no technology-specific skills\n if (typedKeys<Category>(agentConfig).length === 0) {\n verbose(`Agent '${agentName}' has no technology config in stack '${stack.id}'`);\n return [];\n }\n\n const skillRefs = resolveAgentConfigToSkills(agentConfig);\n\n verbose(`Resolved ${skillRefs.length} skills for agent '${agentName}' from stack '${stack.id}'`);\n\n return skillRefs;\n}\n\n/**\n * Resolves skill references for an agent using a priority hierarchy.\n *\n * Priority order:\n * 1. Explicit skills defined in the agent's compile config\n * 2. Skills derived from the stack definition\n *\n * @param agentName - Agent to resolve skills for\n * @param agentConfig - Compile-time agent config (may contain explicit skills)\n * @param stack - Optional stack definition for fallback skill resolution\n * @returns Skill references from the highest-priority source, or empty array\n */\nexport async function resolveAgentSkillRefs(\n agentName: AgentName,\n agentConfig: CompileAgentConfig,\n stack?: Stack,\n): Promise<SkillReference[]> {\n // Priority 1: Explicit skills in compile config\n if (agentConfig.skills && agentConfig.skills.length > 0) {\n return agentConfig.skills;\n }\n\n // Priority 2: Stack-based skills — values are already skill IDs\n if (stack) {\n const stackSkills = resolveAgentSkillsFromStack(agentName, stack);\n if (stackSkills.length > 0) {\n verbose(`Resolved ${stackSkills.length} skills from stack for ${agentName}`);\n return stackSkills;\n }\n }\n\n return [];\n}\n\n/**\n * Resolves all agents referenced in a compile config into fully populated AgentConfigs\n * with their skill lists materialized from definitions.\n *\n * For each agent in `compileConfig.agents`, this function:\n * 1. Validates the agent exists in the scanned agent definitions\n * 2. Resolves skill references (from explicit config or stack fallback)\n * 3. Materializes skill references into full Skill objects using the skill definitions map\n * 4. Merges the agent definition with its resolved skills into an AgentConfig\n *\n * @param agents - Available agent definitions keyed by name (from scanning agent directories)\n * @param skills - Available skill definitions keyed by ID (from scanning skill directories)\n * @param compileConfig - Compilation config specifying which agents to compile and their overrides\n * @param _projectRoot - Project root directory (currently unused, reserved for future use)\n * @param stack - Optional stack definition for stack-based skill resolution\n * @returns Map of agent names to fully resolved AgentConfig objects ready for compilation\n * @throws When an agent referenced in compileConfig is not found in scanned agents\n */\nexport async function resolveAgents(\n agents: Record<AgentName, AgentDefinition>,\n skills: SkillDefinitionMap,\n compileConfig: CompileConfig,\n _projectRoot: string,\n stack?: Stack,\n): Promise<Record<AgentName, AgentConfig>> {\n const agentNames = typedKeys<AgentName>(compileConfig.agents);\n\n const entries = await Promise.all(\n agentNames.map(async (agentName) => {\n const definition = agents[agentName];\n if (!definition) {\n const availableAgents = typedKeys<AgentName>(agents);\n const agentList =\n availableAgents.length > 0\n ? `Available agents: ${availableAgents.slice(0, 5).join(\", \")}${availableAgents.length > 5 ? ` (and ${availableAgents.length - 5} more)` : \"\"}`\n : \"No agents found in scanned directories\";\n throw new Error(\n `Agent '${agentName}' referenced in compile config but not found in scanned agents. ${agentList}. Check that src/agents/${agentName}/metadata.yaml exists.`,\n );\n }\n\n const agentConfig = compileConfig.agents[agentName];\n const skillRefs = await resolveAgentSkillRefs(agentName, agentConfig, stack);\n const resolvedSkills = resolveSkillReferences(skillRefs, skills);\n\n return [\n agentName,\n {\n name: agentName,\n title: definition.title,\n description: definition.description,\n // The project config carries the user's deliberate choice; the agent's own metadata\n // carries the default. Config wins, silently — warning on every compile for a setting\n // someone made on purpose is noise.\n model: agentConfig?.model ?? definition.model,\n effort: agentConfig?.effort ?? definition.effort,\n tools: definition.tools,\n skills: resolvedSkills,\n path: definition.path,\n sourceRoot: definition.sourceRoot,\n agentBaseDir: definition.agentBaseDir,\n },\n ] as const;\n }),\n );\n\n // Structural cast: Object.fromEntries returns Record<string, V>, narrowing to typed keys\n return Object.fromEntries(entries) as Record<AgentName, AgentConfig>;\n}\n\nexport function convertStackToCompileConfig(stackId: string, stack: ProjectConfig): CompileConfig {\n return {\n name: stack.name,\n description: stack.description || \"\",\n stack: stackId,\n // Structural cast: Object.fromEntries returns Record<string, V>, narrowing to typed keys\n agents: Object.fromEntries(stack.agents.map((a) => [a.name, {}])) as Record<\n AgentName,\n CompileAgentConfig\n >,\n };\n}\n","import { createHash } from \"crypto\";\nimport path from \"path\";\nimport { getErrorMessage } from \"../utils/errors\";\nimport { readFile, readFileSafe, writeFile, glob, fileExists } from \"../utils/fs\";\nimport { warn } from \"../utils/logger\";\nimport {\n DEFAULT_VERSION,\n MAX_PLUGIN_FILE_SIZE,\n STANDARD_FILES,\n HASH_PREFIX_LENGTH,\n} from \"../consts\";\nimport { pluginManifestSchema } from \"./schemas\";\nimport { SKILL_CONTENT_FILES, SKILL_CONTENT_DIRS } from \"./metadata-keys\";\n\nexport function getCurrentDate(): string {\n return new Date().toISOString().split(\"T\")[0];\n}\n\nexport function computeStringHash(content: string): string {\n const hash = createHash(\"sha256\");\n hash.update(content);\n return hash.digest(\"hex\").slice(0, HASH_PREFIX_LENGTH);\n}\n\nexport async function computeFileHash(filePath: string): Promise<string> {\n const content = await readFile(filePath);\n return computeStringHash(content);\n}\n\nexport async function computeSkillFolderHash(skillPath: string): Promise<string> {\n const contents: string[] = [];\n\n for (const fileName of SKILL_CONTENT_FILES) {\n const filePath = path.join(skillPath, fileName);\n if (await fileExists(filePath)) {\n const content = await readFile(filePath);\n contents.push(`${fileName}:${content}`);\n }\n }\n\n for (const dirName of SKILL_CONTENT_DIRS) {\n const dirPath = path.join(skillPath, dirName);\n if (await fileExists(dirPath)) {\n const files = await glob(\"**/*\", dirPath);\n for (const file of files.sort()) {\n const filePath = path.join(dirPath, file);\n const content = await readFile(filePath);\n contents.push(`${dirName}/${file}:${content}`);\n }\n }\n }\n\n const combined = contents.join(\"\\n---\\n\");\n return computeStringHash(combined);\n}\n\n/**\n * Plugin versioning utilities shared by skill, agent, and stack plugin compilers.\n * Reads existing plugin.json + .content-hash, bumps semver major on content change.\n */\n\nconst CONTENT_HASH_FILE = \".content-hash\";\n\nexport function parseMajorVersion(version: string): number {\n const match = version.match(/^(\\d+)\\./);\n return match ? parseInt(match[1], 10) : 1;\n}\n\nexport function bumpMajorVersion(version: string): string {\n const major = parseMajorVersion(version);\n return `${major + 1}.0.0`;\n}\n\nasync function readExistingPluginManifest(\n pluginDir: string,\n getManifestPath: (dir: string) => string,\n): Promise<{ version: string; contentHash: string | undefined } | null> {\n const manifestPath = getManifestPath(pluginDir);\n\n if (!(await fileExists(manifestPath))) {\n return null;\n }\n\n try {\n const content = await readFileSafe(manifestPath, MAX_PLUGIN_FILE_SIZE);\n const manifest = pluginManifestSchema.parse(JSON.parse(content));\n\n const hashFilePath = manifestPath.replace(STANDARD_FILES.PLUGIN_JSON, CONTENT_HASH_FILE);\n const contentHash = (await fileExists(hashFilePath))\n ? (await readFile(hashFilePath)).trim()\n : undefined;\n\n return {\n version: manifest.version ?? DEFAULT_VERSION,\n contentHash,\n };\n } catch (error) {\n warn(`Failed to read plugin manifest at '${manifestPath}': ${getErrorMessage(error)}`);\n return null;\n }\n}\n\nexport async function determinePluginVersion(\n newHash: string,\n pluginDir: string,\n getManifestPath: (dir: string) => string,\n): Promise<{ version: string; contentHash: string }> {\n const existing = await readExistingPluginManifest(pluginDir, getManifestPath);\n\n if (!existing) {\n return {\n version: DEFAULT_VERSION,\n contentHash: newHash,\n };\n }\n\n if (existing.contentHash !== newHash) {\n return {\n version: bumpMajorVersion(existing.version),\n contentHash: newHash,\n };\n }\n\n return {\n version: existing.version,\n contentHash: newHash,\n };\n}\n\nexport async function writeContentHash(\n pluginDir: string,\n contentHash: string,\n getManifestPath: (dir: string) => string,\n): Promise<void> {\n const hashFilePath = getManifestPath(pluginDir).replace(\n STANDARD_FILES.PLUGIN_JSON,\n CONTENT_HASH_FILE,\n );\n await writeFile(hashFilePath, contentHash);\n}\n","import { spawn } from \"child_process\";\nimport { z } from \"zod\";\nimport os from \"os\";\nimport type { ClaudePluginScope } from \"../types/config\";\nimport { getErrorMessage } from \"./errors\";\nimport { warn } from \"./logger\";\n\n// Argument length limits to prevent oversized CLI arguments\nconst MAX_PLUGIN_PATH_LENGTH = 1024;\nconst MAX_PLUGIN_NAME_LENGTH = 256;\nconst MAX_MARKETPLACE_SOURCE_LENGTH = 1024;\n\n// Marketplace/plugin names: alphanumeric, dashes, underscores, dots, @\nconst SAFE_NAME_PATTERN = /^[a-zA-Z0-9._@/-]+$/;\n\n// Plugin path/ref: alphanumeric, dashes, underscores, dots, slashes, @, colons (for marketplace refs like skill@marketplace)\nconst SAFE_PLUGIN_PATH_PATTERN = /^[a-zA-Z0-9._@/:~-]+$/;\n\n// eslint-disable-next-line no-control-regex\nconst CONTROL_CHAR_PATTERN = /[\\x00-\\x08\\x0E-\\x1F\\x7F]/u;\n\nfunction validatePluginPath(pluginPath: string): void {\n if (!pluginPath || pluginPath.trim().length === 0) {\n throw new Error(\"Plugin path must not be empty.\");\n }\n\n if (pluginPath.length > MAX_PLUGIN_PATH_LENGTH) {\n throw new Error(\n `Plugin path is too long (${pluginPath.length} characters, max ${MAX_PLUGIN_PATH_LENGTH}).`,\n );\n }\n\n if (CONTROL_CHAR_PATTERN.test(pluginPath)) {\n throw new Error(\"Plugin path contains invalid control characters.\");\n }\n\n if (!SAFE_PLUGIN_PATH_PATTERN.test(pluginPath)) {\n throw new Error(\n `Plugin path contains invalid characters: \"${pluginPath}\"\\n` +\n \"Plugin paths may only contain alphanumeric characters, dashes, underscores, dots, slashes, @, and colons.\",\n );\n }\n}\n\nfunction validateMarketplaceSource(source: string): void {\n if (!source || source.trim().length === 0) {\n throw new Error(\"Marketplace source must not be empty.\");\n }\n\n if (source.length > MAX_MARKETPLACE_SOURCE_LENGTH) {\n throw new Error(\n `Marketplace source is too long (${source.length} characters, max ${MAX_MARKETPLACE_SOURCE_LENGTH}).`,\n );\n }\n\n if (CONTROL_CHAR_PATTERN.test(source)) {\n throw new Error(\"Marketplace source contains invalid control characters.\");\n }\n\n if (!SAFE_PLUGIN_PATH_PATTERN.test(source)) {\n throw new Error(\n `Marketplace source contains invalid characters: \"${source}\"\\n` +\n \"Source may only contain alphanumeric characters, dashes, underscores, dots, slashes, @, and colons.\",\n );\n }\n}\n\nfunction validatePluginName(pluginName: string): void {\n if (!pluginName || pluginName.trim().length === 0) {\n throw new Error(\"Plugin name must not be empty.\");\n }\n\n if (pluginName.length > MAX_PLUGIN_NAME_LENGTH) {\n throw new Error(\n `Plugin name is too long (${pluginName.length} characters, max ${MAX_PLUGIN_NAME_LENGTH}).`,\n );\n }\n\n if (CONTROL_CHAR_PATTERN.test(pluginName)) {\n throw new Error(\"Plugin name contains invalid control characters.\");\n }\n\n if (!SAFE_NAME_PATTERN.test(pluginName)) {\n throw new Error(\n `Plugin name contains invalid characters: \"${pluginName}\"\\n` +\n \"Names may only contain alphanumeric characters, dashes, underscores, dots, @, and slashes.\",\n );\n }\n}\n\nexport type ExecResult = {\n stdout: string;\n stderr: string;\n exitCode: number;\n};\n\nexport async function execCommand(\n command: string,\n args: string[],\n options?: { cwd?: string; env?: NodeJS.ProcessEnv },\n): Promise<ExecResult> {\n return new Promise((resolve, reject) => {\n const proc = spawn(command, args, {\n cwd: options?.cwd,\n env: { ...process.env, ...options?.env },\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n });\n\n let stdout = \"\";\n let stderr = \"\";\n\n proc.stdout.on(\"data\", (data) => {\n stdout += data.toString();\n });\n\n proc.stderr.on(\"data\", (data) => {\n stderr += data.toString();\n });\n\n proc.on(\"close\", (code) => {\n resolve({\n stdout,\n stderr,\n exitCode: code ?? 1,\n });\n });\n\n proc.on(\"error\", (err) => {\n reject(err);\n });\n });\n}\n\n/** User-scoped plugins run from home dir so Claude CLI only writes to ~/.claude/settings.json */\nfunction resolvePluginCwd(scope: ClaudePluginScope, projectDir: string): string {\n return scope === \"user\" ? os.homedir() : projectDir;\n}\n\nexport async function claudePluginInstall(\n pluginPath: string,\n scope: ClaudePluginScope,\n projectDir: string,\n): Promise<void> {\n validatePluginPath(pluginPath);\n\n const cwd = resolvePluginCwd(scope, projectDir);\n const args = [\"plugin\", \"install\", pluginPath, \"--scope\", scope];\n const result = await execCommand(\"claude\", args, { cwd });\n\n if (result.exitCode !== 0) {\n const errorMessage = result.stderr || result.stdout || \"Unknown error\";\n throw new Error(`Plugin installation failed: ${errorMessage.trim()}`);\n }\n}\n\nexport async function isClaudeCLIAvailable(): Promise<boolean> {\n try {\n const result = await execCommand(\"claude\", [\"--version\"], {});\n return result.exitCode === 0;\n } catch {\n return false;\n }\n}\n\nexport type MarketplaceInfo = {\n name: string;\n source: string;\n repo?: string;\n path?: string;\n};\n\nconst marketplaceInfoListSchema: z.ZodType<MarketplaceInfo[]> = z.array(\n z.object({\n name: z.string(),\n source: z.string(),\n repo: z.string().optional(),\n path: z.string().optional(),\n }),\n);\n\nexport async function claudePluginMarketplaceList(): Promise<MarketplaceInfo[]> {\n try {\n const result = await execCommand(\"claude\", [\"plugin\", \"marketplace\", \"list\", \"--json\"], {});\n\n if (result.exitCode !== 0) {\n return [];\n }\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(result.stdout);\n } catch {\n warn(\"Failed to parse marketplace list output as JSON\");\n return [];\n }\n\n const listResult = marketplaceInfoListSchema.safeParse(parsed);\n if (!listResult.success) {\n warn(\"Unexpected marketplace list format — expected an array of marketplace entries\");\n return [];\n }\n\n return listResult.data;\n } catch {\n return [];\n }\n}\n\nexport async function claudePluginMarketplaceExists(name: string): Promise<boolean> {\n const marketplaces = await claudePluginMarketplaceList();\n return marketplaces.some((m) => m.name === name);\n}\n\nexport async function claudePluginMarketplaceAdd(source: string): Promise<void> {\n validateMarketplaceSource(source);\n\n const args = [\"plugin\", \"marketplace\", \"add\", source];\n let result;\n try {\n result = await execCommand(\"claude\", args, {});\n } catch (err) {\n throw new Error(`Failed to add marketplace: ${getErrorMessage(err)}`, { cause: err });\n }\n\n if (result.exitCode !== 0) {\n const errorMessage = result.stderr || result.stdout || \"Unknown error\";\n if (errorMessage.includes(\"already installed\")) {\n return;\n }\n throw new Error(`Failed to add marketplace: ${errorMessage.trim()}`);\n }\n}\n\nexport async function claudePluginMarketplaceRemove(name: string): Promise<void> {\n validatePluginName(name);\n\n const args = [\"plugin\", \"marketplace\", \"remove\", name];\n let result;\n try {\n result = await execCommand(\"claude\", args, {});\n } catch (err) {\n throw new Error(`Failed to remove marketplace: ${getErrorMessage(err)}`, { cause: err });\n }\n\n if (result.exitCode !== 0) {\n const errorMessage = result.stderr || result.stdout || \"Unknown error\";\n if (errorMessage.includes(\"not found\") || errorMessage.includes(\"not installed\")) {\n return;\n }\n throw new Error(`Failed to remove marketplace: ${errorMessage.trim()}`);\n }\n}\n\nexport async function claudePluginMarketplaceUpdate(name: string): Promise<void> {\n validatePluginName(name);\n\n const args = [\"plugin\", \"marketplace\", \"update\", name];\n let result;\n try {\n result = await execCommand(\"claude\", args, {});\n } catch (err) {\n throw new Error(`Failed to update marketplace: ${getErrorMessage(err)}`, { cause: err });\n }\n\n if (result.exitCode !== 0) {\n const errorMessage = result.stderr || result.stdout || \"Unknown error\";\n throw new Error(`Failed to update marketplace: ${errorMessage.trim()}`);\n }\n}\n\nexport async function claudePluginUninstall(\n pluginName: string,\n scope: ClaudePluginScope,\n projectDir: string,\n): Promise<void> {\n validatePluginName(pluginName);\n\n const cwd = resolvePluginCwd(scope, projectDir);\n const args = [\"plugin\", \"uninstall\", pluginName, \"--scope\", scope];\n const result = await execCommand(\"claude\", args, { cwd });\n\n if (result.exitCode !== 0) {\n const errorMessage = result.stderr || result.stdout || \"Unknown error\";\n // Ignore \"not installed\" errors - plugin may already be removed\n if (errorMessage.includes(\"not installed\") || errorMessage.includes(\"not found\")) {\n return;\n }\n throw new Error(`Plugin uninstall failed: ${errorMessage.trim()}`);\n }\n}\n\n/**\n * Best-effort plugin uninstall that tries both scopes.\n *\n * Use when the plugin's actual registered scope is ambiguous — e.g., a skill\n * was re-scoped after install, or we're cleaning up on uninstall and the config\n * scope may not match the registry entry. Tries the primary scope first, then\n * the fallback, silently swallowing errors from each attempt.\n *\n * The plugin reference must be qualified (e.g., `skill-id@marketplace`), matching\n * the form used at install time — bare skill IDs will not match the registry.\n */\nexport async function claudePluginUninstallBestEffort(\n pluginRef: string,\n primaryScope: ClaudePluginScope,\n projectDir: string,\n): Promise<void> {\n const fallbackScope = primaryScope === \"project\" ? \"user\" : \"project\";\n try {\n await claudePluginUninstall(pluginRef, primaryScope, projectDir);\n } catch {\n // Best-effort: plugin may not be registered with primary scope\n }\n try {\n await claudePluginUninstall(pluginRef, fallbackScope, projectDir);\n } catch {\n // Best-effort: plugin may not be registered with fallback scope either\n }\n}\n","import os from \"os\";\nimport path from \"path\";\nimport type { Liquid } from \"liquidjs\";\nimport { compileAgentForPlugin } from \"../compiler.js\";\nimport { resolveInstallPaths } from \"../installation/install-base-dir.js\";\nimport { writeFile, ensureDir } from \"../../utils/fs.js\";\nimport { typedEntries } from \"../../utils/typed-object.js\";\nimport type { AgentConfig, AgentName, SkillScope } from \"../../types/index.js\";\n\nexport type AgentWriteOutcome =\n | { name: AgentName; ok: true; scope: SkillScope; targetDir: string }\n | { name: AgentName; ok: false; error: unknown };\n\n/**\n * Compiles each resolved agent and writes it to its scope's agents directory:\n * global agents to `~/.claude/agents/`, project agents to `projectAgentsDir`.\n * Per-agent failures are collected as outcomes — callers own the policy\n * (recompile reports and continues; install hard-errors).\n */\nexport async function writeCompiledAgentsByScope(params: {\n resolvedAgents: Record<AgentName, AgentConfig>;\n sourcePath: string;\n engine: Liquid;\n projectAgentsDir: string;\n agentScopeMap?: Map<AgentName, SkillScope>;\n}): Promise<AgentWriteOutcome[]> {\n const globalAgentsDir = resolveInstallPaths(os.homedir(), \"global\").agentsDir;\n\n // Ensure both directories exist before writing agents.\n // ensureDir is idempotent (mkdir -p), so calling it when dirs already exist is safe.\n await ensureDir(globalAgentsDir);\n\n const outcomes: AgentWriteOutcome[] = [];\n for (const [name, agent] of typedEntries<AgentName, AgentConfig>(params.resolvedAgents)) {\n try {\n const output = await compileAgentForPlugin(name, agent, params.sourcePath, params.engine);\n const scope = params.agentScopeMap?.get(name) ?? \"project\";\n const targetDir = scope === \"global\" ? globalAgentsDir : params.projectAgentsDir;\n await writeFile(path.join(targetDir, `${name}.md`), output);\n outcomes.push({ name, ok: true, scope, targetDir });\n } catch (error) {\n outcomes.push({ name, ok: false, error });\n }\n }\n return outcomes;\n}\n","import path from \"path\";\nimport { sortBy } from \"remeda\";\nimport { parse as parseYaml, stringify as stringifyYaml } from \"yaml\";\n\nimport { fileExists, readFile, writeFile, listDirectories } from \"../../utils/fs\";\nimport { computeFileHash } from \"../versioning\";\nimport { getCurrentDate } from \"../versioning\";\nimport {\n LOCAL_SKILLS_PATH,\n SCHEMA_PATHS,\n SOURCE_SRC_DIR,\n STANDARD_FILES,\n YAML_FORMATTING,\n} from \"../../consts\";\nimport { yamlSchemaComment, stripYamlSchemaComment } from \"../../utils/yaml-schema\";\nimport type { ResolvedSkill, SkillId } from \"../../types\";\nimport { formatZodIssues, localSkillMetadataSchema } from \"../schemas\";\nimport { warn } from \"../../utils/logger\";\n\n/**\n * Tracks the original marketplace source of a locally-installed skill.\n *\n * Written into each skill's metadata.yaml under the `forkedFrom` key when a skill\n * is copied from a source repository to the local `.claude/skills/` directory.\n * Used for version comparison, update detection, and provenance tracking.\n */\nexport type ForkedFromMetadata = {\n /** Canonical skill ID from the source repository (e.g., \"cc-ts-react-hook-form\") */\n skillId: SkillId;\n /** SHA-256 hash of the source SKILL.md content at the time of installation */\n contentHash: string;\n /** ISO date string (YYYY-MM-DD) when the skill was installed or last updated */\n date: string;\n /** Source URL the skill was installed from (e.g., \"github:agents-inc/skills\") */\n source?: string;\n};\n\n/**\n * Full metadata.yaml content for a locally-installed skill.\n *\n * Parsed from the `metadata.yaml` file in each skill directory under `.claude/skills/`.\n * Uses an index signature to preserve unknown fields written by other tools.\n */\nexport type LocalSkillMetadata = {\n /** Provenance metadata linking back to the original source skill, if any */\n forkedFrom?: ForkedFromMetadata;\n [key: string]: unknown;\n};\n\n/**\n * Result of comparing a local skill against its source repository version.\n *\n * Produced by {@link compareLocalSkillsWithSource} for each skill in the local\n * `.claude/skills/` directory. Used by `npx agents-inc outdated` to display update status.\n */\nexport type SkillComparisonResult = {\n /** Canonical skill ID (from forkedFrom metadata, or directory name if no metadata) */\n id: SkillId;\n /** SHA-256 hash of the local SKILL.md content at install time, null if no forkedFrom metadata */\n localHash: string | null;\n /** SHA-256 hash of the current source SKILL.md, null if source skill no longer exists */\n sourceHash: string | null;\n /** \"current\" if hashes match, \"outdated\" if they differ, \"local-only\" if no source link */\n status: \"current\" | \"outdated\" | \"local-only\";\n /** Directory name under `.claude/skills/` (may differ from skill ID for aliased skills) */\n dirName: string;\n /** Relative path within the source repository, present only when the source skill exists */\n sourcePath?: string;\n};\n\n/**\n * Reads forkedFrom metadata from a skill's metadata.yaml file.\n *\n * This metadata tracks the original marketplace source of a locally-installed skill,\n * enabling version comparison and update detection via content hash matching.\n *\n * @param skillDir - Absolute path to the skill directory (e.g., `/project/.claude/skills/react-hook-form`)\n * @returns The `forkedFrom` metadata if present and valid, `null` if the file doesn't exist,\n * has no `forkedFrom` field, or fails Zod validation (warns on invalid metadata)\n *\n * @example\n * ```ts\n * const metadata = await readForkedFromMetadata(\"/project/.claude/skills/react-hook-form\");\n * if (metadata) {\n * console.log(`Installed from ${metadata.skillId} on ${metadata.date}`);\n * }\n * ```\n */\nexport async function readForkedFromMetadata(skillDir: string): Promise<ForkedFromMetadata | null> {\n const metadata = await readLocalSkillMetadata(skillDir);\n return metadata?.forkedFrom ?? null;\n}\n\n/**\n * Reads the full local skill metadata from a skill's metadata.yaml file.\n *\n * Returns the parsed metadata including `forkedFrom` field.\n * Used by the uninstall command to determine whether a skill was installed by the CLI.\n *\n * @param skillDir - Absolute path to the skill directory\n * @returns The parsed metadata if valid, `null` if the file doesn't exist or is invalid\n */\nexport async function readLocalSkillMetadata(skillDir: string): Promise<LocalSkillMetadata | null> {\n const metadataPath = path.join(skillDir, STANDARD_FILES.METADATA_YAML);\n\n if (!(await fileExists(metadataPath))) {\n return null;\n }\n\n const content = await readFile(metadataPath);\n const result = localSkillMetadataSchema.safeParse(parseYaml(content));\n\n if (!result.success) {\n warn(`Invalid metadata.yaml at ${metadataPath}: ${formatZodIssues(result.error.issues)}`);\n return null;\n }\n\n return result.data;\n}\n\n/**\n * Scans all local skill directories and reads their forked-from metadata.\n *\n * Enumerates every subdirectory under `{projectDir}/.claude/skills/` and reads\n * the `forkedFrom` field from each skill's metadata.yaml. The returned Map is\n * keyed by skill ID (from `forkedFrom.skillId` if available, otherwise the\n * directory name).\n *\n * @param projectDir - Absolute path to the project root containing `.claude/skills/`\n * @returns Map from skill identifier to its directory name and forked-from metadata.\n * Returns an empty Map if the skills directory doesn't exist.\n *\n * @example\n * ```ts\n * const skills = await getLocalSkillsWithMetadata(\"/project\");\n * for (const [id, { dirName, forkedFrom }] of skills) {\n * console.log(`${id} in ${dirName}, forked: ${forkedFrom !== null}`);\n * }\n * ```\n */\nexport async function getLocalSkillsWithMetadata(\n projectDir: string,\n): Promise<Map<string, { dirName: string; forkedFrom: ForkedFromMetadata | null }>> {\n const localSkillsPath = path.join(projectDir, LOCAL_SKILLS_PATH);\n\n if (!(await fileExists(localSkillsPath))) {\n return new Map();\n }\n\n const skillDirs = await listDirectories(localSkillsPath);\n // Parallel reads; Map insertion order (and last-wins on duplicate ids) follows dir order\n const entries = await Promise.all(\n skillDirs.map(async (dirName) => {\n const forkedFrom = await readForkedFromMetadata(path.join(localSkillsPath, dirName));\n return { skillId: forkedFrom?.skillId ?? dirName, dirName, forkedFrom };\n }),\n );\n return new Map(\n entries.map(({ skillId, dirName, forkedFrom }) => [skillId, { dirName, forkedFrom }]),\n );\n}\n\n/**\n * Computes the SHA-256 content hash of a skill's SKILL.md in a source repository.\n *\n * Used to compare the current source version against the locally-installed version's\n * `contentHash` to detect whether updates are available.\n *\n * @param sourcePath - Absolute path to the source repository root\n * @param skillPath - Relative path to the skill within `src/` (e.g., \"web/react/react-hook-form\")\n * @returns SHA-256 hash string of the source SKILL.md, or `null` if the file doesn't exist\n */\nexport async function computeSourceHash(\n sourcePath: string,\n skillPath: string,\n): Promise<string | null> {\n const skillMdPath = path.join(sourcePath, SOURCE_SRC_DIR, skillPath, STANDARD_FILES.SKILL_MD);\n\n if (!(await fileExists(skillMdPath))) {\n return null;\n }\n\n return computeFileHash(skillMdPath);\n}\n\n/**\n * Compares all local skills against their source repository versions.\n *\n * For each skill in `{projectDir}/.claude/skills/`, reads its `forkedFrom` metadata\n * and computes the current source hash. Skills are classified as:\n * - **\"current\"** -- local content hash matches the source (no update available)\n * - **\"outdated\"** -- hashes differ (source has been updated since installation)\n * - **\"local-only\"** -- no `forkedFrom` metadata, or the source skill no longer exists\n *\n * Results are sorted alphabetically by skill ID.\n *\n * @param projectDir - Absolute path to the project root containing `.claude/skills/`\n * @param sourcePath - Absolute path to the source repository root (used to locate SKILL.md files)\n * @param sourceSkills - Map of skill IDs to their relative paths within the source repository.\n * Typically built from the skills matrix. Keys are skill IDs, values have\n * a `path` field (e.g., `{ path: \"web/react/react-hook-form\" }`)\n * @returns Array of comparison results, one per local skill, sorted by skill ID\n *\n * @example\n * ```ts\n * const results = await compareLocalSkillsWithSource(\n * \"/project\",\n * \"/tmp/source-repo\",\n * { \"cc-ts-react-hook-form\": { path: \"web/react/react-hook-form\" } },\n * );\n * const outdated = results.filter((r) => r.status === \"outdated\");\n * ```\n */\nexport async function compareLocalSkillsWithSource(\n projectDir: string,\n sourcePath: string,\n sourceSkills: Partial<Record<SkillId, Pick<ResolvedSkill, \"path\">>>,\n): Promise<SkillComparisonResult[]> {\n const localSkills = await getLocalSkillsWithMetadata(projectDir);\n\n const results = await Promise.all(\n [...localSkills].map(([skillId, { dirName, forkedFrom }]) =>\n classifyLocalSkill(skillId, dirName, forkedFrom, sourcePath, sourceSkills),\n ),\n );\n return sortBy(results, (r) => r.id);\n}\n\n/** Classifies one local skill against the source: local-only, current, or outdated. */\nasync function classifyLocalSkill(\n skillId: string,\n dirName: string,\n forkedFrom: ForkedFromMetadata | null,\n sourcePath: string,\n sourceSkills: Partial<Record<SkillId, Pick<ResolvedSkill, \"path\">>>,\n): Promise<SkillComparisonResult> {\n if (!forkedFrom) {\n // Boundary cast: skillId comes from Map<string, ...> keys (directory names or forkedFrom.skillId)\n return {\n id: skillId as SkillId,\n localHash: null,\n sourceHash: null,\n status: \"local-only\",\n dirName,\n };\n }\n\n const localHash = forkedFrom.contentHash;\n const sourceSkill = sourceSkills[forkedFrom.skillId];\n if (!sourceSkill) {\n return { id: forkedFrom.skillId, localHash, sourceHash: null, status: \"local-only\", dirName };\n }\n\n const sourceHash = await computeSourceHash(sourcePath, sourceSkill.path);\n if (sourceHash === null) {\n return { id: forkedFrom.skillId, localHash, sourceHash: null, status: \"local-only\", dirName };\n }\n\n return {\n id: forkedFrom.skillId,\n localHash,\n sourceHash,\n status: localHash === sourceHash ? \"current\" : \"outdated\",\n dirName,\n sourcePath: sourceSkill.path,\n };\n}\n\n/**\n * Writes forked-from provenance metadata into a skill's metadata.yaml.\n *\n * Reads the existing metadata.yaml (preserving any extra fields), sets the\n * `forkedFrom` block with the given skill ID, content hash, and current date,\n * then writes the file back with a YAML language server schema comment.\n *\n * Called during skill installation (by the skill copier) to record where a\n * locally-installed skill originated from.\n *\n * @param destPath - Absolute path to the skill directory containing metadata.yaml.\n * The file must already exist (created during skill copy).\n * @param skillId - Canonical skill ID from the source repository (e.g., \"cc-ts-react-hook-form\")\n * @param contentHash - SHA-256 hash of the source SKILL.md content at install time\n * @param source - Source URL the skill was installed from (e.g., \"github:agents-inc/skills\")\n *\n * @remarks\n * **Side effect:** Overwrites `{destPath}/metadata.yaml` on disk. Existing fields\n * are preserved if the file parses successfully; if parsing fails, only `forkedFrom`\n * is written (with a warning logged).\n */\nexport async function injectForkedFromMetadata(\n destPath: string,\n skillId: SkillId,\n contentHash: string,\n source?: string,\n): Promise<void> {\n const metadataPath = path.join(destPath, STANDARD_FILES.METADATA_YAML);\n const rawContent = await readFile(metadataPath);\n const { yamlContent } = stripYamlSchemaComment(rawContent);\n\n const parseResult = localSkillMetadataSchema.safeParse(parseYaml(yamlContent));\n if (!parseResult.success) {\n warn(`Malformed metadata.yaml at '${metadataPath}' — existing fields may be lost`);\n }\n const metadata: LocalSkillMetadata = {\n ...(parseResult.success ? parseResult.data : {}),\n forkedFrom: {\n skillId: skillId,\n contentHash: contentHash,\n date: getCurrentDate(),\n ...(source ? { source } : {}),\n },\n };\n\n await writeMetadataYaml(metadataPath, metadata, `${yamlSchemaComment(SCHEMA_PATHS.metadata)}\\n`);\n}\n\n/**\n * Serializes skill metadata with the standard line-width policy and writes it,\n * optionally prefixed by a yaml-language-server schema comment.\n */\nexport async function writeMetadataYaml(\n filePath: string,\n metadata: unknown,\n schemaComment = \"\",\n): Promise<void> {\n const yamlContent = stringifyYaml(metadata, { lineWidth: YAML_FORMATTING.LINE_WIDTH_NONE });\n await writeFile(filePath, schemaComment + yamlContent);\n}\n","/** Generates a yaml-language-server schema comment for the top of YAML files. */\nexport function yamlSchemaComment(schemaPath: string): string {\n return `# yaml-language-server: $schema=${schemaPath}`;\n}\n\n/**\n * Splits YAML file content into its leading yaml-language-server schema\n * comment (empty string when absent, trailing newline included when present)\n * and the parseable YAML body.\n */\nexport function stripYamlSchemaComment(content: string): {\n schemaComment: string;\n yamlContent: string;\n} {\n const lines = content.split(\"\\n\");\n if (lines[0]?.startsWith(\"# yaml-language-server:\")) {\n return { schemaComment: `${lines[0]}\\n`, yamlContent: lines.slice(1).join(\"\\n\") };\n }\n return { schemaComment: \"\", yamlContent: content };\n}\n","import path from \"path\";\n\nimport { copy, ensureDir, isPathWithin } from \"../../utils/fs\";\nimport { computeFileHash } from \"../versioning\";\nimport { EJECT_SOURCE, SOURCE_SRC_DIR, STANDARD_FILES } from \"../../consts\";\nimport type { ResolvedSkill, SkillId } from \"../../types\";\nimport type { SourceLoadResult } from \"../loading\";\nimport { getSkillById } from \"../matrix/matrix-provider\";\nimport { injectForkedFromMetadata } from \"./skill-metadata\";\n\nexport type CopiedSkill = {\n skillId: SkillId;\n contentHash: string;\n sourcePath: string;\n destPath: string;\n local?: boolean;\n};\n\nconst NULL_BYTE_PATTERN = /\\0/;\n\n/**\n * Validate that a resolved path stays within the expected parent directory.\n * Prevents path traversal attacks where skill.path contains sequences like \"../../sensitive\".\n */\nexport function validateSkillPath(\n resolvedPath: string,\n expectedParent: string,\n skillPath: string,\n): void {\n if (NULL_BYTE_PATTERN.test(skillPath)) {\n throw new Error(`Invalid skill path: '${skillPath}' contains null bytes`);\n }\n\n if (!isPathWithin(resolvedPath, expectedParent)) {\n throw new Error(\n `Invalid skill path: '${skillPath}' escapes expected directory '${path.resolve(expectedParent)}'`,\n );\n }\n}\n\n/**\n * Join basePath + skillPath, validate the result stays within basePath,\n * and return the resolved path. Combines path.join + validateSkillPath\n * to eliminate repeated join-then-validate boilerplate.\n */\nfunction resolveSkillPath(basePath: string, skillPath: string): string {\n const resolved = path.join(basePath, skillPath);\n validateSkillPath(resolved, basePath, skillPath);\n return resolved;\n}\n\nfunction getSkillSourcePath(skill: ResolvedSkill, rootDir: string): string {\n const srcDir = path.join(rootDir, SOURCE_SRC_DIR);\n return resolveSkillPath(srcDir, skill.path);\n}\n\nfunction getSkillDestPath(skill: ResolvedSkill, stackDir: string): string {\n const skillRelativePath = skill.path.replace(/^skills\\//, \"\");\n const skillsDir = path.join(stackDir, \"skills\");\n return resolveSkillPath(skillsDir, skillRelativePath);\n}\n\nasync function generateSkillHash(skillSourcePath: string): Promise<string> {\n const skillMdPath = path.join(skillSourcePath, STANDARD_FILES.SKILL_MD);\n return computeFileHash(skillMdPath);\n}\n\n/** Core copy: hash the source SKILL.md, copy the directory, stamp forkedFrom provenance. */\nasync function copySkillTo(\n skill: ResolvedSkill,\n sourcePath: string,\n destPath: string,\n source?: string,\n): Promise<CopiedSkill> {\n const contentHash = await generateSkillHash(sourcePath);\n\n await ensureDir(path.dirname(destPath));\n await copy(sourcePath, destPath);\n\n await injectForkedFromMetadata(destPath, skill.id, contentHash, source);\n\n return { skillId: skill.id, contentHash, sourcePath, destPath };\n}\n\nexport async function copySkill(\n skill: ResolvedSkill,\n stackDir: string,\n registryRoot: string,\n source?: string,\n): Promise<CopiedSkill> {\n return copySkillTo(\n skill,\n getSkillSourcePath(skill, registryRoot),\n getSkillDestPath(skill, stackDir),\n source,\n );\n}\n\nexport async function copySkillFromSource(\n skill: ResolvedSkill,\n stackDir: string,\n sourceResult: SourceLoadResult,\n): Promise<CopiedSkill> {\n return copySkillTo(\n skill,\n getSkillSourcePath(skill, sourceResult.sourcePath),\n getSkillDestPath(skill, stackDir),\n sourceResult.sourceConfig.source,\n );\n}\n\n/**\n * In-place CopiedSkill for a local skill left where it already lives (no copy):\n * source and destination are the skill's own local path.\n */\nasync function resolveLocalCopiedSkill(\n skill: ResolvedSkill,\n localPath: string,\n): Promise<CopiedSkill> {\n const contentHash = await generateSkillHash(localPath);\n return {\n skillId: skill.id,\n sourcePath: localPath,\n destPath: localPath,\n contentHash,\n local: true,\n };\n}\n\nexport type CopyProgressCallback = (completed: number, total: number) => void;\n\nexport async function copySkillsToPluginFromSource(\n selectedSkillIds: SkillId[],\n pluginDir: string,\n sourceResult: SourceLoadResult,\n sourceSelections?: Partial<Record<SkillId, string>>,\n onProgress?: CopyProgressCallback,\n): Promise<CopiedSkill[]> {\n const total = selectedSkillIds.length;\n let completed = 0;\n const results = await Promise.all(\n selectedSkillIds.map(async (skillId): Promise<CopiedSkill> => {\n const skill = getSkillById(skillId);\n\n const selectedSource = sourceSelections?.[skillId];\n const userSelectedRemote = selectedSource && selectedSource !== EJECT_SOURCE;\n\n let result: CopiedSkill;\n if (skill.local && skill.localPath && !userSelectedRemote) {\n result = await resolveLocalCopiedSkill(skill, skill.localPath);\n } else {\n result = await copySkillFromSource(skill, pluginDir, sourceResult);\n }\n\n completed++;\n onProgress?.(completed, total);\n return result;\n }),\n );\n\n return results;\n}\n\nfunction getFlattenedSkillDestPath(skill: ResolvedSkill, localSkillsDir: string): string {\n return resolveSkillPath(localSkillsDir, skill.id);\n}\n\nasync function copySkillToLocalFlattened(\n skill: ResolvedSkill,\n localSkillsDir: string,\n sourceResult: SourceLoadResult,\n): Promise<CopiedSkill> {\n return copySkillTo(\n skill,\n getSkillSourcePath(skill, sourceResult.sourcePath),\n getFlattenedSkillDestPath(skill, localSkillsDir),\n sourceResult.sourceConfig.source,\n );\n}\n\nexport async function copySkillsToLocalFlattened(\n selectedSkillIds: SkillId[],\n localSkillsDir: string,\n sourceResult: SourceLoadResult,\n sourceSelections?: Partial<Record<SkillId, string>>,\n): Promise<CopiedSkill[]> {\n const results = await Promise.all(\n selectedSkillIds.map(async (skillId): Promise<CopiedSkill> => {\n const skill = getSkillById(skillId);\n\n const selectedSource = sourceSelections?.[skillId];\n const userSelectedRemote = selectedSource && selectedSource !== EJECT_SOURCE;\n\n if (skill.local && skill.localPath && !userSelectedRemote) {\n const destPath = getFlattenedSkillDestPath(skill, localSkillsDir);\n const alreadyInPlace = path.resolve(skill.localPath) === path.resolve(destPath);\n\n if (alreadyInPlace) {\n return resolveLocalCopiedSkill(skill, skill.localPath);\n }\n\n const contentHash = await generateSkillHash(skill.localPath);\n await ensureDir(path.dirname(destPath));\n await copy(skill.localPath, destPath);\n return { skillId: skill.id, sourcePath: skill.localPath, destPath, contentHash };\n }\n\n return copySkillToLocalFlattened(skill, localSkillsDir, sourceResult);\n }),\n );\n\n return results;\n}\n","import path from \"path\";\nimport { parse as parseYaml } from \"yaml\";\nimport { getErrorMessage } from \"../../utils/errors\";\nimport { readFile, writeFile, ensureDir, glob, fileExists, copy } from \"../../utils/fs\";\nimport { log, verbose, warn } from \"../../utils/logger\";\nimport {\n generateSkillPluginManifest,\n writePluginManifest,\n getPluginManifestPath,\n} from \"../plugins\";\nimport { parseFrontmatter } from \"../loading\";\nimport { computeSkillFolderHash, determinePluginVersion, writeContentHash } from \"../versioning\";\nimport type { PluginManifest, SkillFrontmatter } from \"../../types\";\nimport { formatZodIssues, skillMetadataLoaderSchema } from \"../schemas\";\nimport type { z } from \"zod\";\n\ntype SkillMetadata = z.infer<typeof skillMetadataLoaderSchema>;\nimport { DEFAULT_BRANDING, STANDARD_FILES } from \"../../consts\";\nimport { stripYamlSchemaComment } from \"../../utils/yaml-schema\";\nimport { SKILL_CONTENT_FILES, SKILL_CONTENT_DIRS } from \"../metadata-keys\";\n\nexport type SkillPluginOptions = {\n skillPath: string;\n outputDir: string;\n skillName?: string;\n};\n\nexport type CompiledSkillPlugin = {\n pluginPath: string;\n manifest: PluginManifest;\n skillName: string;\n};\n\nexport type SkillCompilationRun = {\n compiled: CompiledSkillPlugin[];\n /** Directory basenames of skills that failed to compile this run. */\n failed: string[];\n};\n\nfunction sanitizeSkillName(name: string): string {\n return name.replace(/\\+/g, \"-\");\n}\n\nasync function readSkillMetadata(skillPath: string): Promise<SkillMetadata | null> {\n const metadataPath = path.join(skillPath, STANDARD_FILES.METADATA_YAML);\n\n if (!(await fileExists(metadataPath))) {\n return null;\n }\n\n try {\n const content = await readFile(metadataPath);\n const { yamlContent } = stripYamlSchemaComment(content);\n\n const result = skillMetadataLoaderSchema.safeParse(parseYaml(yamlContent));\n if (!result.success) {\n warn(`Invalid metadata.yaml at '${skillPath}': ${formatZodIssues(result.error.issues)}`);\n return null;\n }\n return result.data;\n } catch (error) {\n warn(`Failed to read metadata.yaml at '${skillPath}': ${error}`);\n return null;\n }\n}\n\nfunction generateReadme(skillName: string, frontmatter: SkillFrontmatter): string {\n return `# ${skillName}\n\n${frontmatter.description}\n\n## Installation\n\nAdd this plugin to your Claude Code configuration:\n\n\\`\\`\\`json\n{\n \"plugins\": [\"${skillName}\"]\n}\n\\`\\`\\`\n\n## Usage\n\nThis skill is automatically available when installed.\n\n---\n\n*Generated by ${DEFAULT_BRANDING.NAME} skill-plugin-compiler*\n`;\n}\n\nexport async function compileSkillPlugin(\n options: SkillPluginOptions,\n): Promise<CompiledSkillPlugin> {\n const { skillPath, outputDir, skillName: overrideName } = options;\n\n const dirBasename = path.basename(skillPath);\n\n const skillMdPath = path.join(skillPath, STANDARD_FILES.SKILL_MD);\n if (!(await fileExists(skillMdPath))) {\n throw new Error(\n `Skill '${dirBasename}' is missing required ${STANDARD_FILES.SKILL_MD} file. Expected at: ${skillMdPath}`,\n );\n }\n\n const skillMdContent = await readFile(skillMdPath);\n const frontmatter = parseFrontmatter(skillMdContent, skillMdPath);\n\n if (!frontmatter) {\n throw new Error(\n `Skill '${dirBasename}' has invalid or missing YAML frontmatter in ${STANDARD_FILES.SKILL_MD}. ` +\n `Required fields: 'name' and 'description'. File: ${skillMdPath}`,\n );\n }\n\n const skillName = overrideName ?? sanitizeSkillName(frontmatter.name);\n\n verbose(`Compiling skill plugin: ${skillName} from ${skillPath}`);\n\n const metadata = await readSkillMetadata(skillPath);\n\n const pluginDir = path.join(outputDir, skillName);\n const skillsDir = path.join(pluginDir, \"skills\", skillName);\n\n await ensureDir(pluginDir);\n await ensureDir(skillsDir);\n\n const newHash = await computeSkillFolderHash(skillPath);\n\n const { version, contentHash } = await determinePluginVersion(\n newHash,\n pluginDir,\n getPluginManifestPath,\n );\n\n const manifest = generateSkillPluginManifest({\n skillName,\n description: frontmatter.description,\n author: metadata?.author,\n version,\n });\n\n await writePluginManifest(pluginDir, manifest);\n\n await writeContentHash(pluginDir, contentHash, getPluginManifestPath);\n\n verbose(` Wrote plugin.json for ${skillName} (v${version})`);\n\n await writeFile(path.join(skillsDir, STANDARD_FILES.SKILL_MD), skillMdContent);\n verbose(` Copied ${STANDARD_FILES.SKILL_MD}`);\n\n for (const fileName of SKILL_CONTENT_FILES) {\n if (fileName === STANDARD_FILES.SKILL_MD) continue;\n\n const sourcePath = path.join(skillPath, fileName);\n if (await fileExists(sourcePath)) {\n const content = await readFile(sourcePath);\n await writeFile(path.join(skillsDir, fileName), content);\n verbose(` Copied ${fileName}`);\n }\n }\n\n for (const dirName of SKILL_CONTENT_DIRS) {\n const sourceDir = path.join(skillPath, dirName);\n if (await fileExists(sourceDir)) {\n await copy(sourceDir, path.join(skillsDir, dirName));\n verbose(` Copied ${dirName}/`);\n }\n }\n\n const readme = generateReadme(skillName, frontmatter);\n await writeFile(path.join(pluginDir, STANDARD_FILES.README_MD), readme);\n verbose(\" Generated README.md\");\n\n return {\n pluginPath: pluginDir,\n manifest,\n skillName,\n };\n}\n\nexport async function compileAllSkillPlugins(\n skillsDir: string,\n outputDir: string,\n): Promise<SkillCompilationRun> {\n const compiled: CompiledSkillPlugin[] = [];\n const failed: string[] = [];\n\n const skillMdFiles = await glob(`**/${STANDARD_FILES.SKILL_MD}`, skillsDir);\n\n for (const skillMdFile of skillMdFiles) {\n const skillPath = path.join(skillsDir, path.dirname(skillMdFile));\n\n try {\n const result = await compileSkillPlugin({\n skillPath,\n outputDir,\n });\n compiled.push(result);\n log(` [OK] ${result.skillName}`);\n } catch (error) {\n const errorMessage = getErrorMessage(error);\n const dirBasename = path.basename(skillPath);\n failed.push(dirBasename);\n warn(`Failed to compile skill from '${dirBasename}': ${errorMessage}`);\n }\n }\n\n return { compiled, failed };\n}\n\nexport function printCompilationSummary(results: CompiledSkillPlugin[]): void {\n log(`\\nCompiled ${results.length} skill plugins:`);\n for (const result of results) {\n log(` - ${result.skillName} (v${result.manifest.version})`);\n }\n}\n","import path from \"path\";\n\nimport { copy, directoryExists, ensureDir, isPathWithin, remove } from \"../../utils/fs\";\nimport { verbose, warn } from \"../../utils/logger\";\nimport { LOCAL_SKILLS_PATH } from \"../../consts\";\nimport { installBaseDir } from \"../installation/install-base-dir\";\nimport type { SkillId, SkillScope } from \"../../types\";\n\n/**\n * Validates a skill ID is safe for use in filesystem paths.\n * Blocks null bytes and path traversal sequences at runtime\n * since TypeScript template literal types don't prevent malformed data from YAML/JSON.\n */\nfunction validateSkillId(skillId: SkillId): boolean {\n return !(\n skillId.length === 0 ||\n skillId.includes(\"\\0\") ||\n skillId.includes(\"..\") ||\n skillId.includes(\"/\") ||\n skillId.includes(\"\\\\\")\n );\n}\n\n/**\n * Delete a local skill directory at .claude/skills/{skill-id}/\n */\nexport async function deleteLocalSkill(projectDir: string, skillId: SkillId): Promise<void> {\n if (!validateSkillId(skillId)) {\n warn(`Invalid skill ID for deletion: '${skillId}'`);\n return;\n }\n\n const skillPath = path.resolve(path.join(projectDir, LOCAL_SKILLS_PATH, skillId));\n const skillsDir = path.resolve(path.join(projectDir, LOCAL_SKILLS_PATH));\n\n if (!isPathWithin(skillPath, skillsDir)) {\n warn(`Skill ID '${skillId}' resolves outside the skills directory.`);\n return;\n }\n\n try {\n await remove(skillPath);\n } catch {\n // Skill may not exist — silently ignore\n }\n\n verbose(`Deleted local skill '${skillId}'`);\n}\n\n/**\n * Migrate a local skill's files between project and global directories.\n * Used when a skill's scope changes during edit (e.g., [P] → [G] or [G] → [P]).\n *\n * Copies the skill directory to the new location.\n * For P→G, removes the old project copy. For G→P (override model), the global copy stays untouched.\n * No-op if the source directory doesn't exist (skill may be plugin-mode).\n */\nexport async function migrateLocalSkillScope(\n skillId: SkillId,\n fromScope: SkillScope,\n projectDir: string,\n): Promise<void> {\n if (!validateSkillId(skillId)) {\n warn(`Invalid skill ID for scope migration: '${skillId}'`);\n return;\n }\n\n const toScope: SkillScope = fromScope === \"global\" ? \"project\" : \"global\";\n // installBaseDir resolves os.homedir() at runtime so test home-dir mocks apply\n // (GLOBAL_INSTALL_ROOT was captured once at module load — a latent test-mock bug).\n const fromBaseDir = installBaseDir(projectDir, fromScope);\n const toBaseDir = installBaseDir(projectDir, toScope);\n\n const fromPath = path.resolve(path.join(fromBaseDir, LOCAL_SKILLS_PATH, skillId));\n const toPath = path.resolve(path.join(toBaseDir, LOCAL_SKILLS_PATH, skillId));\n\n const fromSkillsDir = path.resolve(path.join(fromBaseDir, LOCAL_SKILLS_PATH));\n const toSkillsDir = path.resolve(path.join(toBaseDir, LOCAL_SKILLS_PATH));\n\n if (!isPathWithin(fromPath, fromSkillsDir)) {\n warn(`Skill ID '${skillId}' resolves outside the source skills directory.`);\n return;\n }\n if (!isPathWithin(toPath, toSkillsDir)) {\n warn(`Skill ID '${skillId}' resolves outside the destination skills directory.`);\n return;\n }\n\n if (!(await directoryExists(fromPath))) {\n if (await directoryExists(toPath)) {\n verbose(`Skill '${skillId}' already at ${toScope} scope — no migration needed`);\n return;\n }\n warn(`Could not migrate skill '${skillId}' — not found at either scope`);\n return;\n }\n\n await ensureDir(toSkillsDir);\n await copy(fromPath, toPath);\n\n // G→P is an override — the global copy stays untouched; the project copy overrides it.\n // Only P→G should delete the old directory.\n if (fromScope === \"project\") {\n await remove(fromPath);\n }\n\n verbose(`Migrated skill '${skillId}' from ${fromScope} to ${toScope}`);\n}\n","import type { SkillId } from \"../../types\";\nimport type { SkillConfig, SkillScope } from \"../../types/config\";\nimport type { SourceLoadResult } from \"../loading\";\nimport { deleteLocalSkill, copySkillsToLocalFlattened } from \"../skills\";\nimport { claudePluginInstall, claudePluginUninstall } from \"../../utils/exec\";\nimport { buildMarketplacePluginRef, toClaudePluginScope } from \"../plugins/plugin-ref\";\nimport { installBaseDir, resolveInstallPaths } from \"./install-base-dir\";\nimport { verbose } from \"../../utils/logger\";\nimport { getErrorMessage } from \"../../utils/errors\";\nimport { EJECT_SOURCE } from \"../../consts\";\n\nexport type SkillMigration = {\n id: SkillId;\n oldSource: string;\n newSource: string;\n oldScope: SkillScope;\n newScope: SkillScope;\n};\n\nexport type MigrationPlan = {\n toEject: SkillMigration[];\n toPlugin: SkillMigration[];\n scopeChanges: SkillMigration[];\n};\n\nexport type MigrationResult = {\n ejectedSkills: SkillId[];\n pluginizedSkills: SkillId[];\n /**\n * Per-skill plugin install failures, in the shape of `PluginInstallResult[\"failed\"]`.\n * A non-empty list means this run could NOT honor the user's plugin intent for those\n * skills, so the caller MUST hard-error before writing any config — otherwise config.ts\n * records a marketplace `source` for a skill that has no plugin registration.\n */\n failedPluginInstalls: Array<{ id: SkillId; error: string }>;\n warnings: string[];\n};\n\n/**\n * Detect which skills changed source or scope between old and new configs\n * by comparing SkillConfig[] entries by ID.\n */\nexport function detectMigrations(\n oldSkills: SkillConfig[],\n newSkills: SkillConfig[],\n): MigrationPlan {\n const toEject: SkillMigration[] = [];\n const toPlugin: SkillMigration[] = [];\n const scopeChanges: SkillMigration[] = [];\n\n const oldById = new Map(oldSkills.map((s) => [s.id, s]));\n\n for (const newSkill of newSkills) {\n const oldSkill = oldById.get(newSkill.id);\n if (!oldSkill) continue;\n\n const migration: SkillMigration = {\n id: newSkill.id,\n oldSource: oldSkill.source,\n newSource: newSkill.source,\n oldScope: oldSkill.scope,\n newScope: newSkill.scope,\n };\n\n const wasEject = oldSkill.source === EJECT_SOURCE;\n const isEject = newSkill.source === EJECT_SOURCE;\n\n if (wasEject && !isEject) {\n toPlugin.push(migration);\n } else if (!wasEject && isEject) {\n toEject.push(migration);\n }\n\n // Detect scope changes (independent of source changes)\n if (oldSkill.scope !== newSkill.scope && wasEject === isEject) {\n scopeChanges.push(migration);\n }\n }\n\n return { toEject, toPlugin, scopeChanges };\n}\n\n/**\n * Execute per-skill migration: delete locals that switch to plugin,\n * copy to local for skills that switch from plugin.\n * Uses per-skill scope from the migration plan.\n */\nexport async function executeMigration(\n plan: MigrationPlan,\n projectDir: string,\n sourceResult: SourceLoadResult,\n): Promise<MigrationResult> {\n const warnings: string[] = [];\n const ejectedSkills: SkillId[] = [];\n const pluginizedSkills: SkillId[] = [];\n const failedPluginInstalls: MigrationResult[\"failedPluginInstalls\"] = [];\n\n // Migrate skills from plugin to eject, split by scope\n if (plan.toEject.length > 0) {\n try {\n const scopes = [\"project\", \"global\"] as const;\n for (const scope of scopes) {\n const migrations = plan.toEject.filter((m) =>\n scope === \"global\" ? m.newScope === \"global\" : m.newScope !== \"global\",\n );\n if (migrations.length === 0) continue;\n const copied = await copySkillsToLocalFlattened(\n migrations.map((m) => m.id),\n resolveInstallPaths(projectDir, scope).skillsDir,\n sourceResult,\n );\n ejectedSkills.push(...copied.map((skill) => skill.skillId));\n }\n\n // Uninstall plugin references using per-skill scope\n if (!sourceResult.marketplace) {\n warnings.push(\n ...plan.toEject\n .filter((m) => !(m.oldScope === \"global\" && m.newScope === \"project\"))\n .map((m) => `Could not uninstall plugin for ${m.id}: no marketplace configured`),\n );\n } else {\n for (const migration of plan.toEject) {\n // Don't uninstall global plugins when migrating to project scope —\n // the global plugin must remain for other projects. The project config\n // tombstone (excluded: true) already prevents this project from using it.\n if (migration.oldScope === \"global\" && migration.newScope === \"project\") {\n verbose(`Keeping global plugin for ${migration.id} (migrated to project-eject)`);\n continue;\n }\n // Scope-precise uninstall keyed to this migration's own scope. A best-effort\n // both-scopes sweep would also drop a same-id plugin registered at the OTHER Claude\n // scope (e.g. a project→eject switch uninstalling the still-needed global/user-scope\n // plugin). The registered scope is unambiguous here, so target it exactly.\n // claudePluginUninstall still swallows \"not installed\" / \"not found\".\n const pluginScope = toClaudePluginScope(migration.oldScope);\n const pluginRef = buildMarketplacePluginRef(migration.id, sourceResult.marketplace);\n await claudePluginUninstall(pluginRef, pluginScope, projectDir);\n verbose(`Uninstalled plugin for ${migration.id}`);\n }\n }\n } catch (error) {\n warnings.push(`Could not copy skills for eject: ${getErrorMessage(error)}`);\n }\n }\n\n // Migrate skills from eject to plugin\n if (plan.toPlugin.length > 0) {\n // Plugin install intent is inviolable: without a marketplace NO migration in\n // this list can be installed, so fail before anything is deleted. Deleting\n // first and downgrading to a warning destroys the user's editable working\n // copy and leaves config entries claiming a plugin that was never installed.\n if (!sourceResult.marketplace) {\n throw new Error(\n `Cannot install skills as plugins: marketplace could not be resolved from source ` +\n `'${sourceResult.sourceConfig.source}'. Plugin install mode requires a marketplace — ` +\n `fix the source or switch the affected skills to eject mode.`,\n );\n }\n\n // The same rule applies per skill: install FIRST and delete the ejected working\n // copy only once THAT skill's plugin is registered. A failed install then leaves\n // the skill exactly as it was, and the caller hard-errors on\n // `failedPluginInstalls` before any config claims the plugin source.\n for (const migration of plan.toPlugin) {\n const pluginScope = toClaudePluginScope(migration.newScope);\n const pluginRef = buildMarketplacePluginRef(migration.id, sourceResult.marketplace);\n try {\n await claudePluginInstall(pluginRef, pluginScope, projectDir);\n } catch (error) {\n failedPluginInstalls.push({ id: migration.id, error: getErrorMessage(error) });\n continue;\n }\n pluginizedSkills.push(migration.id);\n verbose(`Installed plugin for ${migration.id}`);\n await deleteEjectedWorkingCopy(migration, projectDir);\n }\n }\n\n return { ejectedSkills, pluginizedSkills, failedPluginInstalls, warnings };\n}\n\n/**\n * Removes the local copy a now-pluginized skill no longer needs, from the scope it was\n * ejected at. A global copy is kept when the skill moves to project scope — the global\n * copy must remain for other projects.\n */\nasync function deleteEjectedWorkingCopy(\n migration: SkillMigration,\n projectDir: string,\n): Promise<void> {\n if (migration.oldScope === \"global\" && migration.newScope === \"project\") {\n verbose(`Keeping global local skill for ${migration.id} (migrated to project-plugin)`);\n return;\n }\n await deleteLocalSkill(installBaseDir(projectDir, migration.oldScope), migration.id);\n}\n","import path from \"path\";\nimport { z } from \"zod\";\nimport { fileExists, readFileSafe } from \"../../utils/fs\";\nimport { verbose } from \"../../utils/logger\";\nimport { getErrorMessage } from \"../../utils/errors\";\nimport { typedEntries } from \"../../utils/typed-object\";\nimport { CLAUDE_DIR, MAX_CONFIG_FILE_SIZE, STANDARD_FILES } from \"../../consts\";\nimport { formatZodErrors } from \"../schema-validator\";\nimport { getPluginManifestPath, getUserPluginsDir } from \"./plugin-finder\";\n\n/**\n * Plugin key format: \"plugin-name@marketplace\"\n * e.g., \"web-framework-react@acme-marketplace\"\n *\n * Kept as string — user-extensible identifiers (plugin names and marketplace names).\n */\nexport type PluginKey = string;\n\n/**\n * Resolved plugin with its install path\n */\nexport type ResolvedPlugin = {\n pluginKey: PluginKey;\n installPath: string;\n};\n\n// Zod schemas for JSON parse boundaries\n\nconst pluginSettingsSchema = z\n .object({\n enabledPlugins: z.record(z.string(), z.unknown()).optional(),\n })\n .passthrough();\n\nconst pluginInstallationSchema = z.object({\n scope: z.enum([\"user\", \"project\", \"local\"]),\n projectPath: z.string().optional(),\n installPath: z.string(),\n version: z.string(),\n installedAt: z.string(),\n lastUpdated: z.string().optional(),\n gitCommitSha: z.string().optional(),\n});\n\nconst installedPluginsSchema = z\n .object({\n version: z.number(),\n plugins: z.record(z.string(), z.array(pluginInstallationSchema)),\n })\n .passthrough();\n\nconst SETTINGS_FILE = STANDARD_FILES.SETTINGS_JSON;\nconst INSTALLED_PLUGINS_FILE = \"installed_plugins.json\";\n\n/** Absolute path of the claude CLI install registry inside a plugins directory. */\nexport function getInstalledPluginsRegistryPath(pluginsDir: string): string {\n return path.join(pluginsDir, INSTALLED_PLUGINS_FILE);\n}\n\n/**\n * Lists every install recorded in a plugins directory's `installed_plugins.json`\n * (v2 registry — claude CLI >=2.1.220 installs under `cache/<marketplace>/<plugin>/<version>/`),\n * flattened to unique (pluginKey, installPath) pairs across all scopes.\n *\n * Throws when the registry is unreadable or fails schema validation — callers\n * treat the registry as the source of truth for installed plugins, so a broken\n * registry must surface as an error rather than an empty result.\n */\nexport async function listRegisteredPluginInstalls(pluginsDir: string): Promise<ResolvedPlugin[]> {\n const registryPath = getInstalledPluginsRegistryPath(pluginsDir);\n const content = await readFileSafe(registryPath, MAX_CONFIG_FILE_SIZE);\n const raw: unknown = JSON.parse(content);\n const result = installedPluginsSchema.safeParse(raw);\n\n if (!result.success) {\n throw new Error(\n `Invalid ${INSTALLED_PLUGINS_FILE}: ${formatZodErrors(result.error).join(\"; \")}`,\n );\n }\n\n return typedEntries(result.data.plugins).flatMap(([pluginKey, installations]) => {\n const uniquePaths = [...new Set(installations.map((i) => i.installPath))];\n return uniquePaths.map((installPath) => ({ pluginKey, installPath }));\n });\n}\n\n/**\n * Read enabled plugin keys from project's .claude/settings.json\n */\nexport async function getEnabledPluginKeys(projectDir: string): Promise<PluginKey[]> {\n const settingsPath = path.join(projectDir, CLAUDE_DIR, SETTINGS_FILE);\n\n if (!(await fileExists(settingsPath))) {\n verbose(`No settings.json found at '${settingsPath}'`);\n return [];\n }\n\n try {\n const content = await readFileSafe(settingsPath, MAX_CONFIG_FILE_SIZE);\n const raw: unknown = JSON.parse(content);\n const result = pluginSettingsSchema.safeParse(raw);\n\n if (!result.success) {\n verbose(`Invalid settings.json structure: ${getErrorMessage(result.error)}`);\n return [];\n }\n\n const settings = result.data;\n\n if (!settings.enabledPlugins) {\n verbose(`No enabledPlugins found in '${settingsPath}'`);\n return [];\n }\n\n const enabledKeys = typedEntries(settings.enabledPlugins)\n .filter(([, enabled]) => enabled === true)\n .map(([key]) => key);\n\n verbose(`Found ${enabledKeys.length} enabled plugins in settings.json`);\n return enabledKeys;\n } catch (error) {\n verbose(`Failed to read settings.json: ${getErrorMessage(error)}`);\n return [];\n }\n}\n\ntype RegisteredInstallation = Pick<\n z.infer<typeof pluginInstallationSchema>,\n \"scope\" | \"projectPath\" | \"installPath\"\n>;\n\n/** This project's own project-scoped installation wins; otherwise the user-scoped one. */\nfunction pickInstallation(\n installations: RegisteredInstallation[],\n projectDir: string,\n): RegisteredInstallation | undefined {\n return (\n installations.find((i) => i.scope === \"project\" && i.projectPath === projectDir) ??\n installations.find((i) => i.scope === \"user\")\n );\n}\n\n/**\n * Resolve install paths for the given plugin keys from global registry\n */\nexport async function resolvePluginInstallPaths(\n pluginKeys: PluginKey[],\n projectDir: string,\n): Promise<ResolvedPlugin[]> {\n if (pluginKeys.length === 0) {\n return [];\n }\n\n const registryPath = getInstalledPluginsRegistryPath(getUserPluginsDir());\n\n if (!(await fileExists(registryPath))) {\n verbose(`Plugin registry not found at '${registryPath}'`);\n return [];\n }\n\n try {\n const content = await readFileSafe(registryPath, MAX_CONFIG_FILE_SIZE);\n const raw: unknown = JSON.parse(content);\n const result = installedPluginsSchema.safeParse(raw);\n\n if (!result.success) {\n verbose(`Invalid plugin registry structure: ${getErrorMessage(result.error)}`);\n return [];\n }\n\n const registry = result.data;\n\n return pluginKeys.flatMap((pluginKey) => {\n const installations = registry.plugins[pluginKey];\n if (!installations || installations.length === 0) {\n verbose(`Plugin '${pluginKey}' not found in registry`);\n return [];\n }\n\n const picked = pickInstallation(installations, projectDir);\n if (!picked) {\n verbose(`No matching installation found for '${pluginKey}'`);\n return [];\n }\n\n const scopeSuffix = picked.scope === \"user\" ? \" (user scope)\" : \"\";\n verbose(`Resolved '${pluginKey}' to '${picked.installPath}'${scopeSuffix}`);\n return [{ pluginKey, installPath: picked.installPath }];\n });\n } catch (error) {\n verbose(`Failed to read plugin registry: ${getErrorMessage(error)}`);\n return [];\n }\n}\n\n/**\n * Get verified plugin install paths for the project\n * Combines settings.json reading, registry lookup, and path verification\n */\nexport async function getVerifiedPluginInstallPaths(projectDir: string): Promise<ResolvedPlugin[]> {\n const enabledKeys = await getEnabledPluginKeys(projectDir);\n const resolvedPaths = await resolvePluginInstallPaths(enabledKeys, projectDir);\n\n // Filter out paths that don't exist on disk\n const checks = await Promise.all(\n resolvedPaths.map(async ({ pluginKey, installPath }) => {\n const pluginJsonPath = getPluginManifestPath(installPath);\n const manifestExists = await fileExists(pluginJsonPath);\n if (!manifestExists) {\n verbose(`Plugin '${pluginKey}' manifest does not exist at: '${pluginJsonPath}'`);\n }\n return { pluginKey, installPath, manifestExists };\n }),\n );\n const verified: ResolvedPlugin[] = checks\n .filter((c) => c.manifestExists)\n .map(({ pluginKey, installPath }) => ({ pluginKey, installPath }));\n\n verbose(`Verified ${verified.length} plugin install paths`);\n return verified;\n}\n","import type { SkillDefinitionMap } from \"../../types\";\nimport { getErrorMessage } from \"../../utils/errors\";\nimport { verbose } from \"../../utils/logger\";\nimport { typedEntries } from \"../../utils/typed-object\";\nimport { loadPluginSkills } from \"../loading\";\nimport { getVerifiedPluginInstallPaths } from \"./plugin-settings\";\n\n/**\n * Discovers all plugin-installed skills from enabled plugins.\n *\n * Reads `.claude/settings.json` to find enabled plugins, then looks up their\n * install paths in the global plugin registry (`~/.claude/plugins/installed_plugins.json`).\n * Loads skills from the plugin cache directories.\n *\n * @param projectDir - Absolute path to the project root\n * @returns Merged map of all discovered plugin skills (later plugins override earlier)\n */\nexport async function discoverAllPluginSkills(projectDir: string): Promise<SkillDefinitionMap> {\n const allSkills: SkillDefinitionMap = {};\n\n try {\n const pluginPaths = await getVerifiedPluginInstallPaths(projectDir);\n\n if (pluginPaths.length === 0) {\n verbose(`No enabled plugins found in settings.json`);\n return allSkills;\n }\n\n const perPluginSkills = await Promise.all(\n pluginPaths.map(async ({ pluginKey, installPath }) => {\n verbose(`Discovering skills from plugin: '${pluginKey}'`);\n try {\n return await loadPluginSkills(installPath);\n } catch (error) {\n verbose(`Failed to load skills from '${pluginKey}': ${getErrorMessage(error)}`);\n return {};\n }\n }),\n );\n // Later plugins override earlier (merge follows pluginPaths order); skip absent entries\n for (const pluginSkills of perPluginSkills) {\n for (const [id, skill] of typedEntries(pluginSkills)) {\n if (skill) {\n allSkills[id] = skill;\n }\n }\n }\n } catch (error) {\n verbose(`Plugin discovery failed: ${getErrorMessage(error)}`);\n }\n\n return allSkills;\n}\n\n/**\n * Checks whether any plugins are enabled in settings.json.\n *\n * @param projectDir - Absolute path to the project root\n * @returns true if at least one plugin is enabled in settings.json\n */\nexport async function hasIndividualPlugins(projectDir: string): Promise<boolean> {\n try {\n const pluginPaths = await getVerifiedPluginInstallPaths(projectDir);\n return pluginPaths.length > 0;\n } catch (error) {\n verbose(`Failed to check for individual plugins: ${getErrorMessage(error)}`);\n return false;\n }\n}\n\n/**\n * Lists the keys of all enabled plugins.\n *\n * @param projectDir - Absolute path to the project root\n * @returns Array of plugin keys (e.g., [\"web-framework-react@acme-marketplace\"])\n */\nexport async function listPluginNames(projectDir: string): Promise<string[]> {\n try {\n const pluginPaths = await getVerifiedPluginInstallPaths(projectDir);\n return pluginPaths.map(({ pluginKey }) => pluginKey);\n } catch (error) {\n verbose(`Failed to list plugin names: ${getErrorMessage(error)}`);\n return [];\n }\n}\n","import { isRecord } from \"../../utils/type-guards.js\";\nimport path from \"path\";\nimport fg from \"fast-glob\";\nimport { getErrorMessage } from \"../../utils/errors\";\nimport {\n fileExists,\n readFile,\n readFileSafe,\n directoryExists,\n listDirectories,\n} from \"../../utils/fs\";\nimport type { ValidationResult } from \"../../types\";\nimport { validResult, invalidResult, mergeValidationResults } from \"../validation-result\";\nimport { extractFrontmatter } from \"../../utils/frontmatter\";\nimport { log } from \"../../utils/logger\";\nimport { formatZodErrors } from \"../schema-validator\";\nimport {\n pluginManifestValidationSchema,\n skillFrontmatterValidationSchema,\n agentFrontmatterValidationSchema,\n} from \"../schemas\";\nimport {\n KEBAB_CASE_PATTERN,\n MAX_PLUGIN_FILE_SIZE,\n PLUGIN_MANIFEST_DIR,\n STANDARD_FILES,\n} from \"../../consts\";\nimport { getPluginManifestPath } from \"./plugin-finder\";\n\nconst PLUGIN_DIR = PLUGIN_MANIFEST_DIR;\nconst PLUGIN_MANIFEST = STANDARD_FILES.PLUGIN_JSON;\nconst SEMVER_REGEX =\n /^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?$/;\n\nfunction isKebabCase(str: string): boolean {\n return KEBAB_CASE_PATTERN.test(str);\n}\n\nfunction isValidSemver(str: string): boolean {\n return SEMVER_REGEX.test(str);\n}\n\n/**\n * Validates the directory structure of a plugin.\n *\n * Checks for the required `.claude-plugin/` directory and `plugin.json` manifest file.\n * Warns if README.md is missing (recommended but not required).\n *\n * @param pluginPath - Absolute path to the plugin root directory\n * @returns Validation result with errors for missing required structure\n */\nexport async function validatePluginStructure(pluginPath: string): Promise<ValidationResult> {\n const errors: string[] = [];\n const warnings: string[] = [];\n\n if (!(await directoryExists(pluginPath))) {\n return invalidResult(`Plugin directory does not exist: ${pluginPath}`);\n }\n\n const pluginDir = path.join(pluginPath, PLUGIN_DIR);\n if (!(await directoryExists(pluginDir))) {\n errors.push(`Missing ${PLUGIN_DIR}/ directory`);\n }\n\n const manifestPath = path.join(pluginDir, PLUGIN_MANIFEST);\n if (!(await fileExists(manifestPath))) {\n errors.push(`Missing ${PLUGIN_DIR}/${PLUGIN_MANIFEST}`);\n }\n\n const readmePath = path.join(pluginPath, STANDARD_FILES.README_MD);\n if (!(await fileExists(readmePath))) {\n warnings.push(\"Missing README.md (recommended for documentation)\");\n }\n\n return {\n valid: errors.length === 0,\n errors,\n warnings,\n };\n}\n\n/**\n * Validates a plugin manifest file (plugin.json) for correctness and completeness.\n *\n * Performs the following validation checks:\n * 1. File existence and readability\n * 2. Valid JSON syntax (with file size limit via readFileSafe)\n * 3. Zod schema validation (strict mode rejects unrecognized keys)\n * 4. Plugin name is kebab-case\n * 5. Version string is valid semver\n * 6. Description field is present (warning if missing)\n * 7. Skills directory path exists on disk (if specified as string)\n * 8. Agents directory path exists on disk (if specified as string)\n *\n * @param manifestPath - Absolute path to the plugin.json file\n * @returns Validation result with errors for invalid/missing data and warnings for recommendations\n */\nexport async function validatePluginManifest(manifestPath: string): Promise<ValidationResult> {\n const errors: string[] = [];\n const warnings: string[] = [];\n\n if (!(await fileExists(manifestPath))) {\n return invalidResult(`Manifest file not found: ${manifestPath}`);\n }\n\n let manifest: Record<string, unknown>;\n try {\n const content = await readFileSafe(manifestPath, MAX_PLUGIN_FILE_SIZE);\n manifest = JSON.parse(content);\n } catch (err) {\n return invalidResult(`Invalid JSON in ${PLUGIN_MANIFEST}: ${getErrorMessage(err)}`);\n }\n\n const result = pluginManifestValidationSchema.safeParse(manifest);\n\n if (!result.success) {\n errors.push(...formatZodErrors(result.error));\n }\n\n if (manifest.name && typeof manifest.name === \"string\") {\n if (!isKebabCase(manifest.name)) {\n errors.push(`name must be kebab-case: \"${manifest.name}\"`);\n }\n }\n\n if (manifest.version && typeof manifest.version === \"string\") {\n if (!isValidSemver(manifest.version)) {\n errors.push(\n `version \"${manifest.version}\" is not valid semver (expected: major.minor.patch)`,\n );\n }\n }\n\n if (!manifest.description) {\n warnings.push(\"Missing description field (recommended for discoverability)\");\n }\n\n const pluginDir = path.dirname(path.dirname(manifestPath));\n\n if (manifest.skills && typeof manifest.skills === \"string\") {\n const skillsPath = path.join(pluginDir, manifest.skills);\n if (!(await directoryExists(skillsPath))) {\n errors.push(`Skills path does not exist: ${manifest.skills}`);\n }\n }\n\n if (manifest.agents && typeof manifest.agents === \"string\") {\n const agentsPath = path.join(pluginDir, manifest.agents);\n if (!(await directoryExists(agentsPath))) {\n errors.push(`Agents path does not exist: ${manifest.agents}`);\n }\n }\n\n return {\n valid: errors.length === 0,\n errors,\n warnings,\n };\n}\n\nexport async function validateSkillFrontmatter(skillPath: string): Promise<ValidationResult> {\n const errors: string[] = [];\n const warnings: string[] = [];\n\n if (!(await fileExists(skillPath))) {\n return invalidResult(`Skill file not found: ${skillPath}`);\n }\n\n const content = await readFile(skillPath);\n const frontmatter = extractFrontmatter(content);\n\n if (frontmatter === null) {\n return invalidResult(\"Missing or invalid YAML frontmatter\");\n }\n\n const result = skillFrontmatterValidationSchema.safeParse(frontmatter);\n\n if (!result.success) {\n errors.push(...formatZodErrors(result.error));\n }\n\n return {\n valid: errors.length === 0,\n errors,\n warnings,\n };\n}\n\nexport async function validateAgentFrontmatter(agentPath: string): Promise<ValidationResult> {\n const errors: string[] = [];\n const warnings: string[] = [];\n\n if (!(await fileExists(agentPath))) {\n return invalidResult(`Agent file not found: ${agentPath}`);\n }\n\n const content = await readFile(agentPath);\n const frontmatter = extractFrontmatter(content);\n\n if (frontmatter === null) {\n return invalidResult(\"Missing or invalid YAML frontmatter\");\n }\n\n const result = agentFrontmatterValidationSchema.safeParse(frontmatter);\n\n if (!result.success) {\n errors.push(...formatZodErrors(result.error));\n }\n\n // Boundary cast: YAML frontmatter parsed as unknown, narrow to record for field access\n const fm = frontmatter as Record<string, unknown>;\n\n if (fm.name && typeof fm.name === \"string\") {\n if (!isKebabCase(fm.name)) {\n errors.push(`name must be kebab-case: \"${fm.name}\"`);\n }\n }\n\n return {\n valid: errors.length === 0,\n errors,\n warnings,\n };\n}\n\nfunction prefixResult(result: ValidationResult, prefix: string): ValidationResult {\n return {\n valid: result.valid,\n errors: result.valid ? [] : result.errors.map((e) => `${prefix}: ${e}`),\n warnings: result.warnings.map((w) => `${prefix}: ${w}`),\n };\n}\n\nasync function validatePluginSkillFiles(\n pluginPath: string,\n skillsRelPath: string,\n): Promise<ValidationResult> {\n const skillsDir = path.join(pluginPath, skillsRelPath);\n if (!(await directoryExists(skillsDir))) return validResult();\n\n const files = await fg(`**/${STANDARD_FILES.SKILL_MD}`, { cwd: skillsDir, absolute: true });\n if (files.length === 0) {\n return {\n valid: true,\n errors: [],\n warnings: [`Skills directory exists but contains no SKILL.md files: ${skillsRelPath}`],\n };\n }\n\n const results = await Promise.all(\n files.map(async (f) =>\n prefixResult(await validateSkillFrontmatter(f), path.relative(pluginPath, f)),\n ),\n );\n return mergeValidationResults(results);\n}\n\nasync function validatePluginAgentFiles(\n pluginPath: string,\n agentsRelPath: string,\n): Promise<ValidationResult> {\n const agentsDir = path.join(pluginPath, agentsRelPath);\n if (!(await directoryExists(agentsDir))) return validResult();\n\n const files = await fg(\"*.md\", { cwd: agentsDir, absolute: true });\n if (files.length === 0) {\n return {\n valid: true,\n errors: [],\n warnings: [`Agents directory exists but contains no .md files: ${agentsRelPath}`],\n };\n }\n\n const results = await Promise.all(\n files.map(async (f) =>\n prefixResult(await validateAgentFrontmatter(f), path.relative(pluginPath, f)),\n ),\n );\n return mergeValidationResults(results);\n}\n\nasync function loadManifestForValidation(\n manifestPath: string,\n): Promise<Record<string, unknown> | null> {\n try {\n const content = await readFileSafe(manifestPath, MAX_PLUGIN_FILE_SIZE);\n const parsed: unknown = JSON.parse(content);\n return isRecord(parsed) ? parsed : null;\n } catch {\n return null;\n }\n}\n\n/**\n * Runs comprehensive validation on a plugin: structure, manifest, skill files, and agent files.\n *\n * Short-circuits on structure validation failure (no point checking manifest if\n * the directory structure is wrong). For valid structures, validates the manifest\n * and then checks all SKILL.md and agent .md files for valid frontmatter.\n *\n * @param pluginPath - Absolute path to the plugin root directory\n * @returns Merged validation result from all validation passes\n */\nexport async function validatePlugin(pluginPath: string): Promise<ValidationResult> {\n const structureResult = await validatePluginStructure(pluginPath);\n if (!structureResult.valid) return structureResult;\n\n const manifestPath = getPluginManifestPath(pluginPath);\n const manifestResult = await validatePluginManifest(manifestPath);\n const manifest = await loadManifestForValidation(manifestPath);\n\n const skillsResult =\n manifest?.skills && typeof manifest.skills === \"string\"\n ? await validatePluginSkillFiles(pluginPath, manifest.skills)\n : validResult();\n\n const agentsResult =\n manifest?.agents && typeof manifest.agents === \"string\"\n ? await validatePluginAgentFiles(pluginPath, manifest.agents)\n : validResult();\n\n return mergeValidationResults([structureResult, manifestResult, skillsResult, agentsResult]);\n}\n\n/**\n * Validates all plugins found in a directory, returning individual results and an aggregate summary.\n *\n * Scans subdirectories for `.claude-plugin/` markers to identify plugins, then validates\n * each one. Returns early with an error if the directory doesn't exist or contains no plugins.\n *\n * @param pluginsDir - Absolute path to the directory containing plugin subdirectories\n * @returns Object with overall validity, per-plugin results, and counts summary\n */\nexport async function validateAllPlugins(pluginsDir: string): Promise<{\n valid: boolean;\n results: Array<{ name: string; result: ValidationResult }>;\n summary: {\n total: number;\n valid: number;\n invalid: number;\n withWarnings: number;\n };\n}> {\n const results: Array<{ name: string; result: ValidationResult }> = [];\n\n if (!(await directoryExists(pluginsDir))) {\n return {\n valid: false,\n results: [\n {\n name: pluginsDir,\n result: invalidResult(`Directory does not exist: ${pluginsDir}`),\n },\n ],\n summary: { total: 0, valid: 0, invalid: 1, withWarnings: 0 },\n };\n }\n\n const allDirs = await listDirectories(pluginsDir);\n const dirChecks = await Promise.all(\n allDirs.map(async (dirName) => ({\n dirName,\n isPlugin: await directoryExists(path.join(pluginsDir, dirName, PLUGIN_DIR)),\n })),\n );\n const pluginDirs = dirChecks.filter((c) => c.isPlugin).map((c) => c.dirName);\n\n if (pluginDirs.length === 0) {\n return {\n valid: false,\n results: [\n {\n name: pluginsDir,\n result: invalidResult(\n `No plugins found in directory: ${pluginsDir}. Plugins must contain a ${PLUGIN_DIR}/ directory.`,\n ),\n },\n ],\n summary: { total: 0, valid: 0, invalid: 1, withWarnings: 0 },\n };\n }\n\n for (const pluginName of pluginDirs) {\n const pluginPath = path.join(pluginsDir, pluginName);\n const result = await validatePlugin(pluginPath);\n results.push({ name: pluginName, result });\n }\n\n const validCount = results.filter((r) => r.result.valid).length;\n const summary = {\n total: results.length,\n valid: validCount,\n invalid: results.length - validCount,\n withWarnings: results.filter((r) => r.result.warnings.length > 0).length,\n };\n\n return {\n valid: summary.invalid === 0,\n results,\n summary,\n };\n}\n\nexport function printPluginValidationResult(name: string, result: ValidationResult): void {\n const status = result.valid ? \"\\u2713\" : \"\\u2717\";\n\n if (result.valid && result.warnings.length === 0) {\n return;\n }\n\n log(`\\n ${status} ${name}`);\n\n if (result.errors.length > 0) {\n log(\" Errors:\");\n result.errors.forEach((e) => log(` - ${e}`));\n }\n\n if (result.warnings.length > 0) {\n log(\" Warnings:\");\n result.warnings.forEach((w) => log(` - ${w}`));\n }\n}\n","import type { SourceEntry } from \"./config\";\nimport { loadProjectSourceConfig, DEFAULT_SOURCE } from \"./config\";\nimport { isHomeDirectory } from \"../installation/is-home-directory\";\nimport { lazyGateDeps, mutateGlobal, writeProjectPartial } from \"../config-gate/index.js\";\nimport { fetchMarketplace } from \"../loading/source-fetcher\";\nimport { discoverLocalSkills } from \"../skills/local-skill-loader\";\nimport { discoverAllPluginSkills } from \"../plugins/plugin-discovery\";\nimport { verbose } from \"../../utils/logger\";\n\nconst DEFAULT_SOURCE_NAME = \"public\";\n\nexport type SourceSummary = {\n sources: Array<SourceEntry & { enabled: boolean }>;\n localSkillCount: number;\n pluginSkillCount: number;\n};\n\n/**\n * Add a new source to the project configuration.\n * Validates the URL by fetching the marketplace.\n */\nexport async function addSource(\n projectDir: string,\n url: string,\n): Promise<{ name: string; skillCount: number }> {\n const result = await fetchMarketplace(url, { forceRefresh: true });\n const name = result.marketplace.name;\n const skillCount = result.marketplace.plugins.length;\n\n await saveSourceList(projectDir, { kind: \"add-source\", entry: { name, url } }, (sources) => {\n if (sources.some((s) => s.name === name)) throw new Error(`Source \"${name}\" already exists`);\n return [...sources, { name, url }];\n });\n\n verbose(`Added source \"${name}\" with ${skillCount} skills`);\n return { name, skillCount };\n}\n\n/**\n * Remove a source by name. Cannot remove \"public\" (the default).\n */\nexport async function removeSource(projectDir: string, name: string): Promise<void> {\n if (name === DEFAULT_SOURCE_NAME) {\n throw new Error(`Cannot remove the \"${DEFAULT_SOURCE_NAME}\" source`);\n }\n\n await saveSourceList(projectDir, { kind: \"remove-source\", name }, (sources) => {\n const filtered = sources.filter((s) => s.name !== name);\n if (filtered.length === sources.length) throw new Error(`Source \"${name}\" not found`);\n return filtered;\n });\n\n verbose(`Removed source \"${name}\"`);\n}\n\n/**\n * Persists a change to the configured source list at whichever scope\n * `projectDir` names.\n *\n * At the home directory the file is the global manifest, so the change goes\n * through the gate: `sources` is a scalar the generated unions do not encode,\n * but registered projects inline it, so the gate propagates the config half\n * without regenerating any types or recompiling any agent. At project scope the\n * config is nobody else's input and is written directly.\n *\n * The write is immediate rather than deferred to the end of the wizard: the\n * sources step re-reads the persisted config to resolve what a newly added\n * marketplace offers, and a source the user confirmed by URL is a machine-level\n * preference that must survive an abandoned install.\n */\nasync function saveSourceList(\n projectDir: string,\n mutation: Parameters<typeof mutateGlobal>[0],\n apply: (sources: SourceEntry[]) => SourceEntry[],\n): Promise<void> {\n if (isHomeDirectory(projectDir)) {\n await mutateGlobal(mutation, lazyGateDeps(projectDir));\n return;\n }\n\n const config = (await loadProjectSourceConfig(projectDir)) ?? {};\n await writeProjectPartial(projectDir, { ...config, sources: apply(config.sources ?? []) });\n}\n\n/**\n * Get summary of all configured sources and local/plugin counts.\n */\nexport async function getSourceSummary(projectDir: string): Promise<SourceSummary> {\n const config = (await loadProjectSourceConfig(projectDir)) ?? {};\n\n const sources: Array<SourceEntry & { enabled: boolean }> = [\n { name: DEFAULT_SOURCE_NAME, url: config.source ?? DEFAULT_SOURCE, enabled: true },\n ...(config.sources ?? []).map((source) => ({ ...source, enabled: true })),\n ];\n\n const [localSkillCount, pluginSkillCount] = await Promise.all([\n countLocalSkills(projectDir),\n countPluginSkills(projectDir),\n ]);\n\n return { sources, localSkillCount, pluginSkillCount };\n}\n\nasync function countLocalSkills(projectDir: string): Promise<number> {\n try {\n const localResult = await discoverLocalSkills(projectDir);\n return localResult ? localResult.skills.length : 0;\n } catch {\n verbose(\"Failed to discover local skills for source summary\");\n return 0;\n }\n}\n\nasync function countPluginSkills(projectDir: string): Promise<number> {\n try {\n const discoveredSkills = await discoverAllPluginSkills(projectDir);\n return Object.keys(discoveredSkills).length;\n } catch {\n verbose(\"Failed to discover plugin skills for source summary\");\n return 0;\n }\n}\n"],"mappings":"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","names":["os","unique","path","os","os","path","os","path","os","CONTROL_CHAR_PATTERN","indexBy","uniqueBy","os","path","path","path","path","os","indexBy","uniqueBy","os","path","os","path","path","groupBy","unique","path","matrix","groupBy","loadSkillsMatrixFromSource","loadMergedAgents","unique","partition","path","os","EXTRACTED_FIELDS","matrix","os","path","path","os","matrix","fs","isDeepEqual","unique","isDeepEqual","fs","matrix","isExclusiveCategory","unique","loadSkillsMatrixFromSource","matrix","os","path","ensureBlankPair","os","path","path","os","parseYaml","path","os","path","path","uniqueBy","uniqueBy","slug","path","groupBy","groupBy","matrix","field","path","PLUGIN_MANIFEST_FILE","path","PLUGIN_MANIFEST_FILE","os","path","path","os","path","path","os","path","path","os","unique","path","pipe","flatMap","uniqueBy","path","path","createHash","path","createHash","path","os","SAFE_NAME_PATTERN","os","os","path","os","path","unique","path","parseYaml","path","parseYaml","path","NULL_BYTE_PATTERN","path","path","path","path","parseYaml","path","parseYaml","path","path","path","z","z","path","allSkills","path","path","path","matrix","os","path","parseYaml","countPluginSkills","os","matrix","path","unique"]}
|