@claude-collective/cli 0.21.0 → 0.26.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 +192 -0
- package/README.md +41 -27
- package/config/skills-matrix.yaml +38 -37
- package/config/stacks.yaml +8 -14
- package/dist/{chunk-ZNIDWLL5.js → chunk-3X5D7RM5.js} +4 -3
- package/dist/chunk-3X5D7RM5.js.map +1 -0
- package/dist/chunk-4357L7VK.js +251 -0
- package/dist/chunk-4357L7VK.js.map +1 -0
- package/dist/chunk-4S4FCAA2.js +100 -0
- package/dist/chunk-4S4FCAA2.js.map +1 -0
- package/dist/chunk-7UPXT32F.js +197 -0
- package/dist/chunk-7UPXT32F.js.map +1 -0
- package/dist/{chunk-DHET7RCE.js → chunk-AWKZ5BDL.js} +9 -2
- package/dist/{chunk-DHET7RCE.js.map → chunk-AWKZ5BDL.js.map} +1 -1
- package/dist/{chunk-6Q3Y7KVB.js → chunk-DBRUQQUF.js} +8 -2
- package/dist/chunk-DBRUQQUF.js.map +1 -0
- package/dist/{chunk-OQYYMQJR.js → chunk-ETCVEV3S.js} +8 -11
- package/dist/chunk-ETCVEV3S.js.map +1 -0
- package/dist/chunk-ETQ3BPGU.js +4204 -0
- package/dist/chunk-ETQ3BPGU.js.map +1 -0
- package/dist/{chunk-ZSVMS677.js → chunk-F4RD5FYM.js} +2 -2
- package/dist/chunk-F4RD5FYM.js.map +1 -0
- package/dist/{chunk-5KXUDHAB.js → chunk-GGFOD5PK.js} +6 -9
- package/dist/chunk-GGFOD5PK.js.map +1 -0
- package/dist/{chunk-UMORK7OK.js → chunk-H7SSBSPR.js} +2 -2
- package/dist/chunk-H7SSBSPR.js.map +1 -0
- package/dist/chunk-HWD32NP7.js +19 -0
- package/dist/chunk-HWD32NP7.js.map +1 -0
- package/dist/{chunk-HGCBZUH5.js → chunk-I3YYG5IO.js} +9 -10
- package/dist/chunk-I3YYG5IO.js.map +1 -0
- package/dist/{chunk-RTE64SJA.js → chunk-IXBCRT3F.js} +2 -2
- package/dist/chunk-IXBCRT3F.js.map +1 -0
- package/dist/{chunk-WFEFICFM.js → chunk-KWYO3M5Q.js} +5 -5
- package/dist/chunk-KWYO3M5Q.js.map +1 -0
- package/dist/{chunk-HEOHU5EZ.js → chunk-MCTSHLAF.js} +22 -11
- package/dist/chunk-MCTSHLAF.js.map +1 -0
- package/dist/chunk-NQJ47R4N.js +1092 -0
- package/dist/chunk-NQJ47R4N.js.map +1 -0
- package/dist/{chunk-FJFEKPXF.js → chunk-O6ZTD7ZI.js} +14 -3
- package/dist/chunk-O6ZTD7ZI.js.map +1 -0
- package/dist/chunk-OBXAY23Y.js +56 -0
- package/dist/chunk-OBXAY23Y.js.map +1 -0
- package/dist/{chunk-XY3XDVMI.js → chunk-QR2EBWL2.js} +3 -3
- package/dist/chunk-R5KJVI54.js +311 -0
- package/dist/chunk-R5KJVI54.js.map +1 -0
- package/dist/{chunk-2LSGX6R4.js → chunk-R7B63JAP.js} +83 -25
- package/dist/chunk-R7B63JAP.js.map +1 -0
- package/dist/{chunk-66UDJBF6.js → chunk-REJGRCVQ.js} +2 -2
- package/dist/chunk-TDZE4TDG.js +220 -0
- package/dist/chunk-TDZE4TDG.js.map +1 -0
- package/dist/{chunk-CBLPAMZO.js → chunk-TMED5DQ2.js} +68 -42
- package/dist/chunk-TMED5DQ2.js.map +1 -0
- package/dist/{chunk-Q3J43SF3.js → chunk-U7HFKR74.js} +2 -2
- package/dist/chunk-U7HFKR74.js.map +1 -0
- package/dist/{chunk-3EHUF54X.js → chunk-UEMRJI2K.js} +17 -4
- package/dist/chunk-UEMRJI2K.js.map +1 -0
- package/dist/{chunk-Z2CWURZ6.js → chunk-UNN7523L.js} +2 -2
- package/dist/chunk-V2ZIH7HV.js +29 -0
- package/dist/chunk-V2ZIH7HV.js.map +1 -0
- package/dist/{chunk-ZEI3ZUDU.js → chunk-VVYNZZUX.js} +7 -15
- package/dist/chunk-VVYNZZUX.js.map +1 -0
- package/dist/{chunk-A46TPNBJ.js → chunk-XENOESJZ.js} +7 -16
- package/dist/chunk-XENOESJZ.js.map +1 -0
- package/dist/chunk-ZDREFYD2.js +696 -0
- package/dist/chunk-ZDREFYD2.js.map +1 -0
- package/dist/chunk-ZW2PELOH.js +197 -0
- package/dist/chunk-ZW2PELOH.js.map +1 -0
- package/dist/cli/defaults/agent-mappings.yaml +0 -1
- package/dist/commands/build/marketplace.js +22 -21
- package/dist/commands/build/marketplace.js.map +1 -1
- package/dist/commands/build/plugins.js +35 -231
- package/dist/commands/build/plugins.js.map +1 -1
- package/dist/commands/build/stack.js +11 -18
- package/dist/commands/build/stack.js.map +1 -1
- package/dist/commands/compile.js +36 -58
- package/dist/commands/compile.js.map +1 -1
- package/dist/commands/config/get.js +8 -8
- package/dist/commands/config/get.js.map +1 -1
- package/dist/commands/config/index.js +7 -7
- package/dist/commands/config/index.js.map +1 -1
- package/dist/commands/config/path.js +6 -6
- package/dist/commands/config/path.js.map +1 -1
- package/dist/commands/config/set-project.js +8 -8
- package/dist/commands/config/set-project.js.map +1 -1
- package/dist/commands/config/show.js +7 -7
- package/dist/commands/config/unset-project.js +8 -8
- package/dist/commands/config/unset-project.js.map +1 -1
- package/dist/commands/diff.js +10 -16
- package/dist/commands/diff.js.map +1 -1
- package/dist/commands/doctor.js +18 -51
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/edit.js +112 -57
- package/dist/commands/edit.js.map +1 -1
- package/dist/commands/eject.js +17 -49
- package/dist/commands/eject.js.map +1 -1
- package/dist/commands/import/skill.js +26 -26
- package/dist/commands/import/skill.js.map +1 -1
- package/dist/commands/info.js +15 -17
- package/dist/commands/info.js.map +1 -1
- package/dist/commands/init.js +103 -727
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/list.js +8 -87
- package/dist/commands/list.js.map +1 -1
- package/dist/commands/new/agent.js +8 -12
- package/dist/commands/new/agent.js.map +1 -1
- package/dist/commands/new/skill.js +6 -6
- package/dist/commands/new/skill.js.map +1 -1
- package/dist/commands/outdated.js +15 -19
- package/dist/commands/outdated.js.map +1 -1
- package/dist/commands/search.js +21 -34
- package/dist/commands/search.js.map +1 -1
- package/dist/commands/uninstall.js +15 -14
- package/dist/commands/uninstall.js.map +1 -1
- package/dist/commands/update.js +13 -24
- package/dist/commands/update.js.map +1 -1
- package/dist/commands/validate.js +44 -487
- package/dist/commands/validate.js.map +1 -1
- package/dist/commands/version/bump.js +11 -11
- package/dist/commands/version/bump.js.map +1 -1
- package/dist/commands/version/index.js +9 -10
- package/dist/commands/version/index.js.map +1 -1
- package/dist/commands/version/set.js +10 -8
- package/dist/commands/version/set.js.map +1 -1
- package/dist/commands/version/show.js +9 -10
- package/dist/commands/version/show.js.map +1 -1
- package/dist/components/common/confirm.js +2 -2
- package/dist/components/common/confirm.test.js +203 -0
- package/dist/components/common/confirm.test.js.map +1 -0
- package/dist/components/common/message.js +1 -1
- package/dist/components/common/spinner.js +1 -1
- package/dist/components/common/spinner.js.map +1 -1
- package/dist/components/skill-search/skill-search.js +3 -3
- package/dist/components/wizard/category-grid.js +2 -2
- package/dist/components/wizard/category-grid.test.js +132 -78
- package/dist/components/wizard/category-grid.test.js.map +1 -1
- package/dist/components/wizard/menu-item.js +2 -2
- package/dist/components/wizard/search-modal.js +9 -0
- package/dist/components/wizard/search-modal.js.map +1 -0
- package/dist/components/wizard/search-modal.test.js +216 -0
- package/dist/components/wizard/search-modal.test.js.map +1 -0
- package/dist/components/wizard/section-progress.js +2 -2
- package/dist/components/wizard/section-progress.test.js +4 -4
- package/dist/components/wizard/section-progress.test.js.map +1 -1
- package/dist/components/wizard/source-grid.js +10 -0
- package/dist/components/wizard/source-grid.js.map +1 -0
- package/dist/components/wizard/source-grid.test.js +500 -0
- package/dist/components/wizard/source-grid.test.js.map +1 -0
- package/dist/components/wizard/step-approach.js +7 -6
- package/dist/components/wizard/step-approach.test.js +115 -0
- package/dist/components/wizard/step-approach.test.js.map +1 -0
- package/dist/components/wizard/step-build.js +9 -4
- package/dist/components/wizard/step-build.test.js +103 -122
- package/dist/components/wizard/step-build.test.js.map +1 -1
- package/dist/components/wizard/step-confirm.js +3 -2
- package/dist/components/wizard/step-confirm.test.js +364 -0
- package/dist/components/wizard/step-confirm.test.js.map +1 -0
- package/dist/components/wizard/step-refine.js +2 -2
- package/dist/components/wizard/step-refine.test.js +19 -13
- package/dist/components/wizard/step-refine.test.js.map +1 -1
- package/dist/components/wizard/step-settings.js +14 -0
- package/dist/components/wizard/step-settings.js.map +1 -0
- package/dist/components/wizard/step-settings.test.js +240 -0
- package/dist/components/wizard/step-settings.test.js.map +1 -0
- package/dist/components/wizard/step-sources.js +17 -0
- package/dist/components/wizard/step-sources.js.map +1 -0
- package/dist/components/wizard/step-sources.test.js +290 -0
- package/dist/components/wizard/step-sources.test.js.map +1 -0
- package/dist/components/wizard/step-stack.js +7 -6
- package/dist/components/wizard/step-stack.test.js +344 -0
- package/dist/components/wizard/step-stack.test.js.map +1 -0
- package/dist/components/wizard/view-title.js +2 -2
- package/dist/components/wizard/wizard-layout.js +6 -5
- package/dist/components/wizard/wizard-tabs.js +2 -2
- package/dist/components/wizard/wizard-tabs.test.js +292 -0
- package/dist/components/wizard/wizard-tabs.test.js.map +1 -0
- package/dist/components/wizard/wizard.js +22 -14
- package/dist/config/skills-matrix.yaml +38 -37
- package/dist/config/stacks.yaml +8 -14
- package/dist/hooks/init.js +5 -5
- package/dist/hooks/init.js.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/{magic-string.es-RGXYGAW3.js → magic-string.es-PAH2SOTR.js} +2 -2
- package/dist/source-manager-EYO3F2DV.js +16 -0
- package/dist/source-manager-EYO3F2DV.js.map +1 -0
- package/dist/src/agents/_templates/agent.liquid +1 -1
- package/dist/src/agents/developer/api-developer/agent.yaml +1 -1
- package/dist/src/agents/developer/cli-developer/agent.yaml +1 -1
- package/dist/src/agents/developer/web-architecture/agent.yaml +1 -1
- package/dist/src/agents/developer/web-developer/agent.yaml +1 -1
- package/dist/src/agents/meta/agent-summoner/agent.yaml +1 -1
- package/dist/src/agents/meta/documentor/agent.yaml +1 -1
- package/dist/src/agents/meta/skill-summoner/agent.yaml +1 -1
- package/dist/src/agents/migration/cli-migrator/agent.yaml +1 -1
- package/dist/src/agents/pattern/pattern-scout/agent.yaml +1 -1
- package/dist/src/agents/pattern/web-pattern-critique/agent.yaml +1 -1
- package/dist/src/agents/planning/web-pm/agent.yaml +1 -1
- package/dist/src/agents/researcher/api-researcher/agent.yaml +1 -1
- package/dist/src/agents/researcher/web-researcher/agent.yaml +1 -1
- package/dist/src/agents/reviewer/api-reviewer/agent.yaml +1 -1
- package/dist/src/agents/reviewer/cli-reviewer/agent.yaml +1 -1
- package/dist/src/agents/reviewer/web-reviewer/agent.yaml +1 -1
- package/dist/src/agents/tester/cli-tester/agent.yaml +1 -1
- package/dist/src/agents/tester/web-tester/agent.yaml +1 -1
- package/dist/stores/wizard-store.js +4 -3
- package/dist/stores/wizard-store.test.js +51 -82
- package/dist/stores/wizard-store.test.js.map +1 -1
- package/package.json +5 -3
- package/src/agents/_templates/agent.liquid +1 -1
- package/src/agents/developer/api-developer/agent.yaml +1 -1
- package/src/agents/developer/cli-developer/agent.yaml +1 -1
- package/src/agents/developer/web-architecture/agent.yaml +1 -1
- package/src/agents/developer/web-developer/agent.yaml +1 -1
- package/src/agents/meta/agent-summoner/agent.yaml +1 -1
- package/src/agents/meta/documentor/agent.yaml +1 -1
- package/src/agents/meta/skill-summoner/agent.yaml +1 -1
- package/src/agents/migration/cli-migrator/agent.yaml +1 -1
- package/src/agents/pattern/pattern-scout/agent.yaml +1 -1
- package/src/agents/pattern/web-pattern-critique/agent.yaml +1 -1
- package/src/agents/planning/web-pm/agent.yaml +1 -1
- package/src/agents/researcher/api-researcher/agent.yaml +1 -1
- package/src/agents/researcher/web-researcher/agent.yaml +1 -1
- package/src/agents/reviewer/api-reviewer/agent.yaml +1 -1
- package/src/agents/reviewer/cli-reviewer/agent.yaml +1 -1
- package/src/agents/reviewer/web-reviewer/agent.yaml +1 -1
- package/src/agents/tester/cli-tester/agent.yaml +1 -1
- package/src/agents/tester/web-tester/agent.yaml +1 -1
- package/dist/chunk-2LSGX6R4.js.map +0 -1
- package/dist/chunk-2OKUEELH.js +0 -32
- package/dist/chunk-2OKUEELH.js.map +0 -1
- package/dist/chunk-374JNMR6.js +0 -212
- package/dist/chunk-374JNMR6.js.map +0 -1
- package/dist/chunk-3EHUF54X.js.map +0 -1
- package/dist/chunk-3XR4PALU.js +0 -529
- package/dist/chunk-3XR4PALU.js.map +0 -1
- package/dist/chunk-5K2ZLUO5.js +0 -57
- package/dist/chunk-5K2ZLUO5.js.map +0 -1
- package/dist/chunk-5KXUDHAB.js.map +0 -1
- package/dist/chunk-6Q3Y7KVB.js.map +0 -1
- package/dist/chunk-7SLV7CMF.js +0 -615
- package/dist/chunk-7SLV7CMF.js.map +0 -1
- package/dist/chunk-A46TPNBJ.js.map +0 -1
- package/dist/chunk-AL74GBW4.js +0 -69
- package/dist/chunk-AL74GBW4.js.map +0 -1
- package/dist/chunk-BQX23RBV.js +0 -191
- package/dist/chunk-BQX23RBV.js.map +0 -1
- package/dist/chunk-CA4LH4LI.js +0 -132
- package/dist/chunk-CA4LH4LI.js.map +0 -1
- package/dist/chunk-CBLPAMZO.js.map +0 -1
- package/dist/chunk-CKPQHGXR.js +0 -417
- package/dist/chunk-CKPQHGXR.js.map +0 -1
- package/dist/chunk-CXOFOJCN.js +0 -80
- package/dist/chunk-CXOFOJCN.js.map +0 -1
- package/dist/chunk-EHGD7HIE.js +0 -104
- package/dist/chunk-EHGD7HIE.js.map +0 -1
- package/dist/chunk-EHS3TWWP.js +0 -95
- package/dist/chunk-EHS3TWWP.js.map +0 -1
- package/dist/chunk-FJFEKPXF.js.map +0 -1
- package/dist/chunk-HEOHU5EZ.js.map +0 -1
- package/dist/chunk-HGCBZUH5.js.map +0 -1
- package/dist/chunk-HPGFY5ZN.js +0 -114
- package/dist/chunk-HPGFY5ZN.js.map +0 -1
- package/dist/chunk-INJ2EFRW.js +0 -127
- package/dist/chunk-INJ2EFRW.js.map +0 -1
- package/dist/chunk-IOBFMF6X.js +0 -61
- package/dist/chunk-IOBFMF6X.js.map +0 -1
- package/dist/chunk-KH3HA7J7.js +0 -116
- package/dist/chunk-KH3HA7J7.js.map +0 -1
- package/dist/chunk-N6JNE326.js +0 -261
- package/dist/chunk-N6JNE326.js.map +0 -1
- package/dist/chunk-NAGU7TVZ.js +0 -36
- package/dist/chunk-NAGU7TVZ.js.map +0 -1
- package/dist/chunk-OQYYMQJR.js.map +0 -1
- package/dist/chunk-PLZOUVDD.js +0 -419
- package/dist/chunk-PLZOUVDD.js.map +0 -1
- package/dist/chunk-Q3J43SF3.js.map +0 -1
- package/dist/chunk-RTE64SJA.js.map +0 -1
- package/dist/chunk-T25OEQFI.js +0 -26
- package/dist/chunk-T25OEQFI.js.map +0 -1
- package/dist/chunk-UMORK7OK.js.map +0 -1
- package/dist/chunk-VFHWU7JU.js +0 -287
- package/dist/chunk-VFHWU7JU.js.map +0 -1
- package/dist/chunk-VS4GVTZE.js +0 -91
- package/dist/chunk-VS4GVTZE.js.map +0 -1
- package/dist/chunk-WFEFICFM.js.map +0 -1
- package/dist/chunk-WG6KIAPK.js +0 -54
- package/dist/chunk-WG6KIAPK.js.map +0 -1
- package/dist/chunk-ZEI3ZUDU.js.map +0 -1
- package/dist/chunk-ZNIDWLL5.js.map +0 -1
- package/dist/chunk-ZSVMS677.js.map +0 -1
- /package/dist/{chunk-XY3XDVMI.js.map → chunk-QR2EBWL2.js.map} +0 -0
- /package/dist/{chunk-66UDJBF6.js.map → chunk-REJGRCVQ.js.map} +0 -0
- /package/dist/{chunk-Z2CWURZ6.js.map → chunk-UNN7523L.js.map} +0 -0
- /package/dist/{magic-string.es-RGXYGAW3.js.map → magic-string.es-PAH2SOTR.js.map} +0 -0
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cli/lib/installation.ts"],"sourcesContent":["/**\n * Installation detection utilities for Claude Collective.\n *\n * Detects whether a project uses local mode (.claude-src/config.yaml) or\n * plugin mode (.claude/plugins/claude-collective/).\n */\nimport path from \"path\";\nimport { directoryExists, fileExists } from \"../utils/fs\";\nimport { loadProjectConfig } from \"./project-config\";\nimport { getCollectivePluginDir } from \"./plugin-finder\";\nimport { CLAUDE_DIR, CLAUDE_SRC_DIR } from \"../consts\";\n\nexport type InstallMode = \"local\" | \"plugin\";\n\nexport interface Installation {\n mode: InstallMode;\n configPath: string;\n agentsDir: string;\n skillsDir: string;\n projectDir: string;\n}\n\n/**\n * Detect the current installation mode by checking for local config first.\n * Priority: Local (.claude-src/config.yaml with installMode: local) > Plugin\n */\nexport async function detectInstallation(\n projectDir: string = process.cwd(),\n): Promise<Installation | null> {\n // 1. Check for local installation first\n // Check .claude-src/config.yaml first (new location)\n const srcConfigPath = path.join(projectDir, CLAUDE_SRC_DIR, \"config.yaml\");\n // Fall back to .claude/config.yaml (legacy location)\n const legacyConfigPath = path.join(projectDir, CLAUDE_DIR, \"config.yaml\");\n\n const localConfigPath = (await fileExists(srcConfigPath))\n ? srcConfigPath\n : (await fileExists(legacyConfigPath))\n ? legacyConfigPath\n : null;\n\n if (localConfigPath) {\n const loaded = await loadProjectConfig(projectDir);\n\n // If config exists and has installMode: local (or no installMode, defaults to local)\n // treat it as local mode\n const mode: InstallMode = loaded?.config?.installMode ?? \"local\";\n\n if (mode === \"local\") {\n return {\n mode: \"local\",\n configPath: localConfigPath,\n agentsDir: path.join(projectDir, CLAUDE_DIR, \"agents\"),\n skillsDir: path.join(projectDir, CLAUDE_DIR, \"skills\"),\n projectDir,\n };\n }\n }\n\n // 2. Check for plugin installation\n const pluginDir = getCollectivePluginDir(projectDir);\n const pluginConfigPath = path.join(pluginDir, \"config.yaml\");\n\n if (await directoryExists(pluginDir)) {\n return {\n mode: \"plugin\",\n configPath: pluginConfigPath,\n agentsDir: path.join(pluginDir, \"agents\"),\n skillsDir: path.join(pluginDir, \"skills\"),\n projectDir,\n };\n }\n\n // No installation found\n return null;\n}\n\n/**\n * Get installation or throw with helpful error message\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(\"No Claude Collective installation found.\\n\" + \"Run 'cc init' to create one.\");\n }\n\n return installation;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAMA,OAAO,UAAU;AAoBjB,eAAsB,mBACpB,aAAqB,QAAQ,IAAI,GACH;AAG9B,QAAM,gBAAgB,KAAK,KAAK,YAAY,gBAAgB,aAAa;AAEzE,QAAM,mBAAmB,KAAK,KAAK,YAAY,YAAY,aAAa;AAExE,QAAM,kBAAmB,MAAM,WAAW,aAAa,IACnD,gBACC,MAAM,WAAW,gBAAgB,IAChC,mBACA;AAEN,MAAI,iBAAiB;AACnB,UAAM,SAAS,MAAM,kBAAkB,UAAU;AAIjD,UAAM,OAAoB,QAAQ,QAAQ,eAAe;AAEzD,QAAI,SAAS,SAAS;AACpB,aAAO;AAAA,QACL,MAAM;AAAA,QACN,YAAY;AAAA,QACZ,WAAW,KAAK,KAAK,YAAY,YAAY,QAAQ;AAAA,QACrD,WAAW,KAAK,KAAK,YAAY,YAAY,QAAQ;AAAA,QACrD;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAGA,QAAM,YAAY,uBAAuB,UAAU;AACnD,QAAM,mBAAmB,KAAK,KAAK,WAAW,aAAa;AAE3D,MAAI,MAAM,gBAAgB,SAAS,GAAG;AACpC,WAAO;AAAA,MACL,MAAM;AAAA,MACN,YAAY;AAAA,MACZ,WAAW,KAAK,KAAK,WAAW,QAAQ;AAAA,MACxC,WAAW,KAAK,KAAK,WAAW,QAAQ;AAAA,MACxC;AAAA,IACF;AAAA,EACF;AAGA,SAAO;AACT;","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cli/components/skill-search/skill-search.tsx"],"sourcesContent":["/**\n * Interactive skill search component.\n *\n * Features:\n * - Live text filtering as you type\n * - Multi-select checkboxes\n * - Keyboard navigation (arrows, vim keys, space, enter, c, esc)\n * - Source attribution for each skill\n *\n * Keyboard controls:\n * - Up/Down/k/j: Navigate results\n * - Space: Toggle selection\n * - Enter: Import selected skills\n * - c: Copy link of focused skill\n * - Esc: Cancel/exit\n */\nimport React, { useState, useCallback, useMemo } from \"react\";\nimport { Box, Text, useApp, useInput } from \"ink\";\nimport { ThemeProvider } from \"@inkjs/ui\";\nimport { cliTheme } from \"../themes/default.js\";\nimport type { ResolvedSkill } from \"../../types-matrix.js\";\n\n// =============================================================================\n// Types\n// =============================================================================\n\nexport interface SourcedSkill extends ResolvedSkill {\n /** Source name where this skill came from */\n sourceName: string;\n /** Source URL for reference */\n sourceUrl?: string;\n}\n\nexport interface SkillSearchResult {\n /** Skills selected for import */\n selectedSkills: SourcedSkill[];\n /** Whether the user cancelled */\n cancelled: boolean;\n}\n\nexport interface SkillSearchProps {\n /** All available skills from all sources */\n skills: SourcedSkill[];\n /** Total number of sources */\n sourceCount: number;\n /** Initial search query (from command args) */\n initialQuery?: string;\n /** Called when user completes selection (Enter) */\n onComplete: (result: SkillSearchResult) => void;\n /** Called when user cancels (Esc) */\n onCancel: () => void;\n}\n\n// =============================================================================\n// Constants\n// =============================================================================\n\n/** Maximum results to show at once */\nconst MAX_VISIBLE_RESULTS = 10;\n\n/** Checkbox display */\nconst CHECKBOX_CHECKED = \"[x]\";\nconst CHECKBOX_UNCHECKED = \"[ ]\";\n\n// =============================================================================\n// Helper Functions\n// =============================================================================\n\n/**\n * Match skill against search query (case-insensitive substring)\n */\nfunction matchesQuery(skill: SourcedSkill, query: string): boolean {\n if (!query.trim()) return true;\n\n const lowerQuery = query.toLowerCase();\n\n // Match against name\n if (skill.name.toLowerCase().includes(lowerQuery)) return true;\n\n // Match against ID\n if (skill.id.toLowerCase().includes(lowerQuery)) return true;\n\n // Match against alias\n if (skill.alias?.toLowerCase().includes(lowerQuery)) return true;\n\n // Match against description\n if (skill.description.toLowerCase().includes(lowerQuery)) return true;\n\n // Match against category\n if (skill.category.toLowerCase().includes(lowerQuery)) return true;\n\n // Match against tags\n if (skill.tags.some((tag) => tag.toLowerCase().includes(lowerQuery))) {\n return true;\n }\n\n // Match against source name\n if (skill.sourceName.toLowerCase().includes(lowerQuery)) return true;\n\n return false;\n}\n\n/**\n * Truncate text with ellipsis\n */\nfunction truncate(text: string, maxLength: number): string {\n if (text.length <= maxLength) return text;\n return text.slice(0, maxLength - 3) + \"...\";\n}\n\n// =============================================================================\n// Sub-Components\n// =============================================================================\n\ninterface HeaderProps {\n sourceCount: number;\n}\n\nconst Header: React.FC<HeaderProps> = ({ sourceCount }) => {\n return (\n <Box\n flexDirection=\"row\"\n justifyContent=\"space-between\"\n borderStyle=\"single\"\n borderBottom={false}\n borderLeft={false}\n borderRight={false}\n paddingX={1}\n >\n <Text bold color=\"cyan\">\n Search Skills\n </Text>\n <Text dimColor>\n {sourceCount} source{sourceCount !== 1 ? \"s\" : \"\"}\n </Text>\n </Box>\n );\n};\n\ninterface SearchInputProps {\n value: string;\n onChange: (value: string) => void;\n}\n\nconst SearchInput: React.FC<SearchInputProps> = ({ value, onChange }) => {\n // Handle text input\n useInput((input, key) => {\n if (key.backspace || key.delete) {\n onChange(value.slice(0, -1));\n } else if (!key.ctrl && !key.meta && input && input.length === 1) {\n // Only handle printable characters\n const charCode = input.charCodeAt(0);\n if (charCode >= 32 && charCode <= 126) {\n onChange(value + input);\n }\n }\n });\n\n return (\n <Box paddingX={1} paddingY={1}>\n <Text color=\"cyan\">{\">\"} </Text>\n <Text>{value}</Text>\n <Text color=\"cyan\">_</Text>\n </Box>\n );\n};\n\ninterface ResultItemProps {\n skill: SourcedSkill;\n isSelected: boolean;\n isFocused: boolean;\n}\n\nconst ResultItem: React.FC<ResultItemProps> = ({ skill, isSelected, isFocused }) => {\n const checkbox = isSelected ? CHECKBOX_CHECKED : CHECKBOX_UNCHECKED;\n const displayName = skill.alias || skill.id;\n const descriptionWidth = 30;\n\n return (\n <Box flexDirection=\"row\" gap={1}>\n <Text\n color={isFocused ? \"cyan\" : isSelected ? \"green\" : undefined}\n bold={isFocused}\n backgroundColor={isFocused ? \"#333333\" : undefined}\n >\n {\" \"}\n {checkbox}{\" \"}\n </Text>\n <Box width={14}>\n <Text dimColor>{truncate(skill.sourceName, 12)}</Text>\n </Box>\n <Box width={24}>\n <Text color={isFocused ? \"cyan\" : undefined} bold={isFocused || isSelected}>\n {truncate(displayName, 22)}\n </Text>\n </Box>\n <Text dimColor>{truncate(skill.description, descriptionWidth)}</Text>\n </Box>\n );\n};\n\ninterface ResultsListProps {\n results: SourcedSkill[];\n selectedIds: Set<string>;\n focusedIndex: number;\n scrollOffset: number;\n}\n\nconst ResultsList: React.FC<ResultsListProps> = ({\n results,\n selectedIds,\n focusedIndex,\n scrollOffset,\n}) => {\n const visibleResults = results.slice(scrollOffset, scrollOffset + MAX_VISIBLE_RESULTS);\n\n if (results.length === 0) {\n return (\n <Box paddingX={1} paddingY={1}>\n <Text dimColor>No skills found matching your search.</Text>\n </Box>\n );\n }\n\n return (\n <Box\n flexDirection=\"column\"\n borderStyle=\"single\"\n borderTop={false}\n borderBottom={false}\n paddingX={1}\n >\n {visibleResults.map((skill, index) => {\n const actualIndex = scrollOffset + index;\n return (\n <ResultItem\n key={skill.id}\n skill={skill}\n isSelected={selectedIds.has(skill.id)}\n isFocused={actualIndex === focusedIndex}\n />\n );\n })}\n </Box>\n );\n};\n\ninterface StatusBarProps {\n resultCount: number;\n selectedCount: number;\n}\n\nconst StatusBar: React.FC<StatusBarProps> = ({ resultCount, selectedCount }) => {\n return (\n <Box paddingX={1}>\n <Text dimColor>\n {resultCount} result{resultCount !== 1 ? \"s\" : \"\"}\n {selectedCount > 0 && <Text color=\"green\"> | {selectedCount} selected</Text>}\n </Text>\n </Box>\n );\n};\n\ninterface FooterProps {\n hasSelection: boolean;\n}\n\nconst Footer: React.FC<FooterProps> = ({ hasSelection }) => {\n return (\n <Box\n flexDirection=\"row\"\n justifyContent=\"center\"\n gap={2}\n borderStyle=\"single\"\n borderTop={false}\n borderLeft={false}\n borderRight={false}\n paddingX={1}\n marginTop={1}\n >\n <Text dimColor>\n <Text color=\"white\">j/k</Text> navigate\n </Text>\n <Text dimColor>\n <Text color=\"white\">SPACE</Text> select\n </Text>\n {hasSelection && (\n <Text dimColor>\n <Text color=\"green\">ENTER</Text> import\n </Text>\n )}\n <Text dimColor>\n <Text color=\"white\">c</Text> copy link\n </Text>\n <Text dimColor>\n <Text color=\"yellow\">ESC</Text> cancel\n </Text>\n </Box>\n );\n};\n\n// =============================================================================\n// Main Component\n// =============================================================================\n\nexport const SkillSearch: React.FC<SkillSearchProps> = ({\n skills,\n sourceCount,\n initialQuery = \"\",\n onComplete,\n onCancel,\n}) => {\n const { exit } = useApp();\n\n // State\n const [query, setQuery] = useState(initialQuery);\n const [selectedIds, setSelectedIds] = useState<Set<string>>(new Set());\n const [focusedIndex, setFocusedIndex] = useState(0);\n const [scrollOffset, setScrollOffset] = useState(0);\n const [copiedMessage, setCopiedMessage] = useState<string | null>(null);\n\n // Filter results based on query\n const filteredResults = useMemo(() => {\n return skills.filter((skill) => matchesQuery(skill, query));\n }, [skills, query]);\n\n // Ensure focus stays in bounds when results change\n const safeFocusedIndex = Math.min(focusedIndex, Math.max(0, filteredResults.length - 1));\n\n // Get the currently focused skill\n const focusedSkill = filteredResults[safeFocusedIndex];\n\n // Handle query change\n const handleQueryChange = useCallback((newQuery: string) => {\n setQuery(newQuery);\n setFocusedIndex(0);\n setScrollOffset(0);\n }, []);\n\n // Toggle selection\n const toggleSelection = useCallback((skillId: string) => {\n setSelectedIds((prev) => {\n const next = new Set(prev);\n if (next.has(skillId)) {\n next.delete(skillId);\n } else {\n next.add(skillId);\n }\n return next;\n });\n }, []);\n\n // Copy skill link to clipboard\n const copySkillLink = useCallback(async (skill: SourcedSkill) => {\n const link = skill.sourceUrl ? `${skill.sourceUrl}/${skill.id}` : skill.id;\n\n try {\n // Use native clipboard API via process.stdout.write with OSC 52\n // This is a cross-platform terminal clipboard method\n const encoded = Buffer.from(link).toString(\"base64\");\n process.stdout.write(`\\x1b]52;c;${encoded}\\x07`);\n setCopiedMessage(`Copied: ${link}`);\n setTimeout(() => setCopiedMessage(null), 2000);\n } catch {\n setCopiedMessage(`Link: ${link}`);\n setTimeout(() => setCopiedMessage(null), 3000);\n }\n }, []);\n\n // Handle keyboard navigation\n useInput((input, key) => {\n // Escape to cancel\n if (key.escape) {\n onCancel();\n exit();\n return;\n }\n\n // Enter to import selected\n if (key.return) {\n if (selectedIds.size > 0) {\n const selectedSkills = filteredResults.filter((s) => selectedIds.has(s.id));\n onComplete({\n selectedSkills,\n cancelled: false,\n });\n exit();\n }\n return;\n }\n\n // Space to toggle selection\n if (input === \" \" && focusedSkill) {\n toggleSelection(focusedSkill.id);\n return;\n }\n\n // c to copy link\n if ((input === \"c\" || input === \"C\") && focusedSkill) {\n void copySkillLink(focusedSkill);\n return;\n }\n\n // Navigation\n const isUp = key.upArrow || input === \"k\";\n const isDown = key.downArrow || input === \"j\";\n\n if (isUp && safeFocusedIndex > 0) {\n const newIndex = safeFocusedIndex - 1;\n setFocusedIndex(newIndex);\n // Scroll up if needed\n if (newIndex < scrollOffset) {\n setScrollOffset(newIndex);\n }\n }\n\n if (isDown && safeFocusedIndex < filteredResults.length - 1) {\n const newIndex = safeFocusedIndex + 1;\n setFocusedIndex(newIndex);\n // Scroll down if needed\n if (newIndex >= scrollOffset + MAX_VISIBLE_RESULTS) {\n setScrollOffset(newIndex - MAX_VISIBLE_RESULTS + 1);\n }\n }\n });\n\n return (\n <ThemeProvider theme={cliTheme}>\n <Box flexDirection=\"column\">\n <Header sourceCount={sourceCount} />\n <SearchInput value={query} onChange={handleQueryChange} />\n <ResultsList\n results={filteredResults}\n selectedIds={selectedIds}\n focusedIndex={safeFocusedIndex}\n scrollOffset={scrollOffset}\n />\n <StatusBar resultCount={filteredResults.length} selectedCount={selectedIds.size} />\n {copiedMessage && (\n <Box paddingX={1}>\n <Text color=\"green\">{copiedMessage}</Text>\n </Box>\n )}\n <Footer hasSelection={selectedIds.size > 0} />\n </Box>\n </ThemeProvider>\n );\n};\n"],"mappings":"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","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cli/lib/__tests__/test-constants.ts"],"sourcesContent":["/**\n * Shared test constants for CLI tests.\n *\n * Contains keyboard escape sequences and timing constants for ink-testing-library tests.\n */\n\n// =============================================================================\n// Keyboard Escape Sequences\n// =============================================================================\n\n/** Arrow Up key escape sequence */\nexport const ARROW_UP = \"\\x1B[A\";\n\n/** Arrow Down key escape sequence */\nexport const ARROW_DOWN = \"\\x1B[B\";\n\n/** Arrow Left key escape sequence */\nexport const ARROW_LEFT = \"\\x1B[D\";\n\n/** Arrow Right key escape sequence */\nexport const ARROW_RIGHT = \"\\x1B[C\";\n\n/** Enter key */\nexport const ENTER = \"\\r\";\n\n/** Escape key */\nexport const ESCAPE = \"\\x1B\";\n\n/** Ctrl+C key */\nexport const CTRL_C = \"\\x03\";\n\n/** Tab key */\nexport const TAB = \"\\t\";\n\n/** Backspace key */\nexport const BACKSPACE = \"\\x7F\";\n\n/** Letter Y for ConfirmInput */\nexport const KEY_Y = \"y\";\n\n/** Letter N for ConfirmInput */\nexport const KEY_N = \"n\";\n\n// =============================================================================\n// Timing Constants\n// =============================================================================\n\n/** Delay after keyboard input to allow terminal to process (ms) */\nexport const INPUT_DELAY_MS = 50;\n\n/** Delay for render/rerender operations (ms) */\nexport const RENDER_DELAY_MS = 100;\n\n/** Delay for complex multi-step operations (ms) */\nexport const OPERATION_DELAY_MS = 150;\n\n// =============================================================================\n// Test Utilities\n// =============================================================================\n\n/**\n * Create a delay promise for async tests.\n *\n * @param ms - Milliseconds to wait\n * @returns Promise that resolves after the delay\n */\nexport const delay = (ms: number): Promise<void> =>\n new Promise((resolve) => setTimeout(resolve, ms));\n"],"mappings":";;;;;;AAAA;AAWO,IAAM,WAAW;AAGjB,IAAM,aAAa;AAGnB,IAAM,aAAa;AAGnB,IAAM,cAAc;AAGpB,IAAM,QAAQ;AAGd,IAAM,SAAS;AAMf,IAAM,MAAM;AAgBZ,IAAM,iBAAiB;AAGvB,IAAM,kBAAkB;AAexB,IAAM,QAAQ,CAAC,OACpB,IAAI,QAAQ,CAAC,YAAY,WAAW,SAAS,EAAE,CAAC;","names":[]}
|
package/dist/chunk-7SLV7CMF.js
DELETED
|
@@ -1,615 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
generateStackPluginManifest,
|
|
4
|
-
getPluginManifestPath,
|
|
5
|
-
writePluginManifest
|
|
6
|
-
} from "./chunk-VS4GVTZE.js";
|
|
7
|
-
import {
|
|
8
|
-
hashString
|
|
9
|
-
} from "./chunk-IOBFMF6X.js";
|
|
10
|
-
import {
|
|
11
|
-
loadSkillsMatrix,
|
|
12
|
-
loadStackById,
|
|
13
|
-
resolveAgentConfigToSkills
|
|
14
|
-
} from "./chunk-CKPQHGXR.js";
|
|
15
|
-
import {
|
|
16
|
-
loadAllAgents,
|
|
17
|
-
loadSkillsByIds
|
|
18
|
-
} from "./chunk-BQX23RBV.js";
|
|
19
|
-
import {
|
|
20
|
-
verbose
|
|
21
|
-
} from "./chunk-T25OEQFI.js";
|
|
22
|
-
import {
|
|
23
|
-
copy,
|
|
24
|
-
directoryExists,
|
|
25
|
-
ensureDir,
|
|
26
|
-
fileExists,
|
|
27
|
-
readFile,
|
|
28
|
-
readFileOptional,
|
|
29
|
-
writeFile
|
|
30
|
-
} from "./chunk-AL74GBW4.js";
|
|
31
|
-
import {
|
|
32
|
-
CLAUDE_DIR,
|
|
33
|
-
CLAUDE_SRC_DIR,
|
|
34
|
-
DEFAULT_VERSION,
|
|
35
|
-
DIRS,
|
|
36
|
-
PROJECT_ROOT,
|
|
37
|
-
SKILLS_MATRIX_PATH
|
|
38
|
-
} from "./chunk-FJFEKPXF.js";
|
|
39
|
-
import {
|
|
40
|
-
init_esm_shims
|
|
41
|
-
} from "./chunk-DHET7RCE.js";
|
|
42
|
-
|
|
43
|
-
// src/cli/lib/stack-plugin-compiler.ts
|
|
44
|
-
init_esm_shims();
|
|
45
|
-
import path2 from "path";
|
|
46
|
-
|
|
47
|
-
// src/cli/lib/compiler.ts
|
|
48
|
-
init_esm_shims();
|
|
49
|
-
import { Liquid } from "liquidjs";
|
|
50
|
-
import path from "path";
|
|
51
|
-
|
|
52
|
-
// src/cli/lib/resolver.ts
|
|
53
|
-
init_esm_shims();
|
|
54
|
-
function resolveSkillReference(ref, skills) {
|
|
55
|
-
const definition = skills[ref.id];
|
|
56
|
-
if (!definition) {
|
|
57
|
-
verbose(`Skill '${ref.id}' not found in available skills, skipping`);
|
|
58
|
-
return null;
|
|
59
|
-
}
|
|
60
|
-
return {
|
|
61
|
-
id: ref.id,
|
|
62
|
-
path: definition.path,
|
|
63
|
-
name: definition.name,
|
|
64
|
-
description: definition.description,
|
|
65
|
-
usage: ref.usage,
|
|
66
|
-
preloaded: ref.preloaded ?? false
|
|
67
|
-
};
|
|
68
|
-
}
|
|
69
|
-
function resolveSkillReferences(skillRefs, skills) {
|
|
70
|
-
return skillRefs.map((ref) => resolveSkillReference(ref, skills)).filter((skill) => skill !== null);
|
|
71
|
-
}
|
|
72
|
-
function flattenAgentSkills(categorizedSkills) {
|
|
73
|
-
const assignments = [];
|
|
74
|
-
for (const category of Object.keys(categorizedSkills)) {
|
|
75
|
-
assignments.push(...categorizedSkills[category]);
|
|
76
|
-
}
|
|
77
|
-
return assignments;
|
|
78
|
-
}
|
|
79
|
-
function normalizeSkillEntry(entry) {
|
|
80
|
-
if (typeof entry === "string") {
|
|
81
|
-
return { id: entry };
|
|
82
|
-
}
|
|
83
|
-
return entry;
|
|
84
|
-
}
|
|
85
|
-
function expandSkillIdIfDirectory(skillId, skills) {
|
|
86
|
-
if (skills[skillId]) {
|
|
87
|
-
return [skillId];
|
|
88
|
-
}
|
|
89
|
-
const allSkillIds = Object.keys(skills);
|
|
90
|
-
const seenPaths = /* @__PURE__ */ new Set();
|
|
91
|
-
const matchingSkills = [];
|
|
92
|
-
for (const id of allSkillIds) {
|
|
93
|
-
const skillDef = skills[id];
|
|
94
|
-
if (skillDef.path.startsWith(`src/skills/${skillId}/`)) {
|
|
95
|
-
if (!seenPaths.has(skillDef.path)) {
|
|
96
|
-
seenPaths.add(skillDef.path);
|
|
97
|
-
matchingSkills.push(id);
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
if (matchingSkills.length > 0) {
|
|
102
|
-
return matchingSkills;
|
|
103
|
-
}
|
|
104
|
-
return [skillId];
|
|
105
|
-
}
|
|
106
|
-
var KEY_SUBCATEGORIES = /* @__PURE__ */ new Set([
|
|
107
|
-
"framework",
|
|
108
|
-
"api",
|
|
109
|
-
"database",
|
|
110
|
-
"meta-framework",
|
|
111
|
-
"base-framework",
|
|
112
|
-
"platform"
|
|
113
|
-
]);
|
|
114
|
-
function resolveAgentSkillsFromStack(agentName, stack, skillAliases) {
|
|
115
|
-
const agentConfig = stack.agents[agentName];
|
|
116
|
-
if (!agentConfig) {
|
|
117
|
-
verbose(`Agent '${agentName}' not found in stack '${stack.id}'`);
|
|
118
|
-
return [];
|
|
119
|
-
}
|
|
120
|
-
if (Object.keys(agentConfig).length === 0) {
|
|
121
|
-
verbose(`Agent '${agentName}' has no technology config in stack '${stack.id}'`);
|
|
122
|
-
return [];
|
|
123
|
-
}
|
|
124
|
-
const skillRefs = [];
|
|
125
|
-
for (const [subcategory, technologyAlias] of Object.entries(agentConfig)) {
|
|
126
|
-
const fullSkillId = skillAliases[technologyAlias];
|
|
127
|
-
if (!fullSkillId) {
|
|
128
|
-
verbose(
|
|
129
|
-
`Warning: No skill alias found for '${technologyAlias}' (agent: ${agentName}, subcategory: ${subcategory}). Skipping.`
|
|
130
|
-
);
|
|
131
|
-
continue;
|
|
132
|
-
}
|
|
133
|
-
const isKeySkill = KEY_SUBCATEGORIES.has(subcategory);
|
|
134
|
-
skillRefs.push({
|
|
135
|
-
id: fullSkillId,
|
|
136
|
-
usage: `when working with ${subcategory}`,
|
|
137
|
-
preloaded: isKeySkill
|
|
138
|
-
});
|
|
139
|
-
}
|
|
140
|
-
verbose(`Resolved ${skillRefs.length} skills for agent '${agentName}' from stack '${stack.id}'`);
|
|
141
|
-
return skillRefs;
|
|
142
|
-
}
|
|
143
|
-
function resolveStackSkills(stack, agentName, skills) {
|
|
144
|
-
const skillRefs = [];
|
|
145
|
-
const rawAgentSkills = stack.agent_skills?.[agentName];
|
|
146
|
-
const normalizedSkills = (stack.skills ?? []).map(normalizeSkillEntry);
|
|
147
|
-
let assignments;
|
|
148
|
-
if (rawAgentSkills) {
|
|
149
|
-
if (Array.isArray(rawAgentSkills)) {
|
|
150
|
-
assignments = rawAgentSkills.map(normalizeSkillEntry);
|
|
151
|
-
} else {
|
|
152
|
-
const normalized = {};
|
|
153
|
-
for (const [category, entries] of Object.entries(rawAgentSkills)) {
|
|
154
|
-
normalized[category] = entries.map(normalizeSkillEntry);
|
|
155
|
-
}
|
|
156
|
-
assignments = flattenAgentSkills(normalized);
|
|
157
|
-
}
|
|
158
|
-
} else {
|
|
159
|
-
assignments = normalizedSkills;
|
|
160
|
-
}
|
|
161
|
-
const validSkillIds = /* @__PURE__ */ new Set();
|
|
162
|
-
for (const s of normalizedSkills) {
|
|
163
|
-
const expandedIds = expandSkillIdIfDirectory(s.id, skills);
|
|
164
|
-
for (const id of expandedIds) {
|
|
165
|
-
validSkillIds.add(id);
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
const addedSkills = /* @__PURE__ */ new Set();
|
|
169
|
-
for (const assignment of assignments) {
|
|
170
|
-
const skillId = assignment.id;
|
|
171
|
-
const expandedSkillIds = expandSkillIdIfDirectory(skillId, skills);
|
|
172
|
-
for (const expandedId of expandedSkillIds) {
|
|
173
|
-
if (addedSkills.has(expandedId)) {
|
|
174
|
-
continue;
|
|
175
|
-
}
|
|
176
|
-
if (!skills[expandedId]) {
|
|
177
|
-
throw new Error(
|
|
178
|
-
`Stack "${stack.name}" references skill "${expandedId}" for agent "${agentName}" not found in scanned skills`
|
|
179
|
-
);
|
|
180
|
-
}
|
|
181
|
-
if (rawAgentSkills && !validSkillIds.has(expandedId)) {
|
|
182
|
-
throw new Error(
|
|
183
|
-
`Stack "${stack.name}" agent_skills for "${agentName}" includes skill "${expandedId}" not in stack's skills array`
|
|
184
|
-
);
|
|
185
|
-
}
|
|
186
|
-
const skillDef = skills[expandedId];
|
|
187
|
-
skillRefs.push({
|
|
188
|
-
id: expandedId,
|
|
189
|
-
usage: `when working with ${skillDef.name.toLowerCase()}`,
|
|
190
|
-
preloaded: assignment.preloaded ?? false
|
|
191
|
-
});
|
|
192
|
-
addedSkills.add(expandedId);
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
return skillRefs;
|
|
196
|
-
}
|
|
197
|
-
async function getAgentSkills(agentName, agentConfig, _compileConfig, _skills, _projectRoot, stack, skillAliases) {
|
|
198
|
-
if (agentConfig.skills && agentConfig.skills.length > 0) {
|
|
199
|
-
return agentConfig.skills;
|
|
200
|
-
}
|
|
201
|
-
if (stack && skillAliases) {
|
|
202
|
-
const stackSkills = resolveAgentSkillsFromStack(agentName, stack, skillAliases);
|
|
203
|
-
if (stackSkills.length > 0) {
|
|
204
|
-
verbose(`Resolved ${stackSkills.length} skills from stack for ${agentName}`);
|
|
205
|
-
return stackSkills;
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
return [];
|
|
209
|
-
}
|
|
210
|
-
async function resolveAgents(agents, skills, compileConfig, projectRoot, stack, skillAliases) {
|
|
211
|
-
const resolved = {};
|
|
212
|
-
const agentNames = Object.keys(compileConfig.agents);
|
|
213
|
-
for (const agentName of agentNames) {
|
|
214
|
-
const definition = agents[agentName];
|
|
215
|
-
if (!definition) {
|
|
216
|
-
const availableAgents = Object.keys(agents);
|
|
217
|
-
const agentList = availableAgents.length > 0 ? `Available agents: ${availableAgents.slice(0, 5).join(", ")}${availableAgents.length > 5 ? ` (and ${availableAgents.length - 5} more)` : ""}` : "No agents found in scanned directories";
|
|
218
|
-
throw new Error(
|
|
219
|
-
`Agent '${agentName}' referenced in compile config but not found in scanned agents. ${agentList}. Check that src/agents/${agentName}/agent.yaml exists.`
|
|
220
|
-
);
|
|
221
|
-
}
|
|
222
|
-
const agentConfig = compileConfig.agents[agentName];
|
|
223
|
-
const skillRefs = await getAgentSkills(
|
|
224
|
-
agentName,
|
|
225
|
-
agentConfig,
|
|
226
|
-
compileConfig,
|
|
227
|
-
skills,
|
|
228
|
-
projectRoot,
|
|
229
|
-
stack,
|
|
230
|
-
skillAliases
|
|
231
|
-
);
|
|
232
|
-
const resolvedSkills = resolveSkillReferences(skillRefs, skills);
|
|
233
|
-
resolved[agentName] = {
|
|
234
|
-
name: agentName,
|
|
235
|
-
title: definition.title,
|
|
236
|
-
description: definition.description,
|
|
237
|
-
model: definition.model,
|
|
238
|
-
tools: definition.tools,
|
|
239
|
-
skills: resolvedSkills,
|
|
240
|
-
path: definition.path,
|
|
241
|
-
sourceRoot: definition.sourceRoot,
|
|
242
|
-
agentBaseDir: definition.agentBaseDir
|
|
243
|
-
};
|
|
244
|
-
}
|
|
245
|
-
return resolved;
|
|
246
|
-
}
|
|
247
|
-
function stackToCompileConfig(stackId, stack) {
|
|
248
|
-
const agents = {};
|
|
249
|
-
for (const agentId of stack.agents) {
|
|
250
|
-
agents[agentId] = {};
|
|
251
|
-
}
|
|
252
|
-
return {
|
|
253
|
-
name: stack.name,
|
|
254
|
-
description: stack.description || "",
|
|
255
|
-
claude_md: "",
|
|
256
|
-
stack: stackId,
|
|
257
|
-
agents
|
|
258
|
-
};
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
// src/cli/lib/compiler.ts
|
|
262
|
-
async function createLiquidEngine(projectDir) {
|
|
263
|
-
const roots = [];
|
|
264
|
-
if (projectDir) {
|
|
265
|
-
const srcTemplatesDir = path.join(projectDir, CLAUDE_SRC_DIR, "agents", "_templates");
|
|
266
|
-
if (await directoryExists(srcTemplatesDir)) {
|
|
267
|
-
roots.push(srcTemplatesDir);
|
|
268
|
-
verbose(`Using local templates from: ${srcTemplatesDir}`);
|
|
269
|
-
}
|
|
270
|
-
const legacyTemplatesDir = path.join(projectDir, CLAUDE_DIR, "templates");
|
|
271
|
-
if (await directoryExists(legacyTemplatesDir)) {
|
|
272
|
-
roots.push(legacyTemplatesDir);
|
|
273
|
-
verbose(`Using legacy templates from: ${legacyTemplatesDir}`);
|
|
274
|
-
}
|
|
275
|
-
}
|
|
276
|
-
roots.push(path.join(PROJECT_ROOT, DIRS.templates));
|
|
277
|
-
return new Liquid({
|
|
278
|
-
root: roots,
|
|
279
|
-
extname: ".liquid",
|
|
280
|
-
strictVariables: false,
|
|
281
|
-
strictFilters: true
|
|
282
|
-
});
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
// src/cli/lib/stack-plugin-compiler.ts
|
|
286
|
-
var CONTENT_HASH_FILE = ".content-hash";
|
|
287
|
-
function parseMajorVersion(version) {
|
|
288
|
-
const match = version.match(/^(\d+)\./);
|
|
289
|
-
return match ? parseInt(match[1], 10) : 1;
|
|
290
|
-
}
|
|
291
|
-
function bumpMajorVersion(version) {
|
|
292
|
-
const major = parseMajorVersion(version);
|
|
293
|
-
return `${major + 1}.0.0`;
|
|
294
|
-
}
|
|
295
|
-
async function readExistingManifest(pluginDir) {
|
|
296
|
-
const manifestPath = getPluginManifestPath(pluginDir);
|
|
297
|
-
if (!await fileExists(manifestPath)) {
|
|
298
|
-
return null;
|
|
299
|
-
}
|
|
300
|
-
try {
|
|
301
|
-
const content = await readFile(manifestPath);
|
|
302
|
-
const manifest = JSON.parse(content);
|
|
303
|
-
const hashFilePath = manifestPath.replace("plugin.json", CONTENT_HASH_FILE);
|
|
304
|
-
let contentHash;
|
|
305
|
-
if (await fileExists(hashFilePath)) {
|
|
306
|
-
contentHash = (await readFile(hashFilePath)).trim();
|
|
307
|
-
}
|
|
308
|
-
return {
|
|
309
|
-
version: manifest.version ?? DEFAULT_VERSION,
|
|
310
|
-
contentHash
|
|
311
|
-
};
|
|
312
|
-
} catch {
|
|
313
|
-
return null;
|
|
314
|
-
}
|
|
315
|
-
}
|
|
316
|
-
function hashStackConfig(stack) {
|
|
317
|
-
const parts = [
|
|
318
|
-
`name:${stack.name}`,
|
|
319
|
-
`description:${stack.description ?? ""}`,
|
|
320
|
-
`skills:${(stack.skills || []).map((s) => typeof s === "string" ? s : s.id).sort().join(",")}`,
|
|
321
|
-
`agents:${(stack.agents || []).sort().join(",")}`
|
|
322
|
-
];
|
|
323
|
-
return hashString(parts.join("\n"));
|
|
324
|
-
}
|
|
325
|
-
async function determineStackVersion(stack, pluginDir) {
|
|
326
|
-
const newHash = hashStackConfig(stack);
|
|
327
|
-
const existing = await readExistingManifest(pluginDir);
|
|
328
|
-
if (!existing) {
|
|
329
|
-
return {
|
|
330
|
-
version: DEFAULT_VERSION,
|
|
331
|
-
contentHash: newHash
|
|
332
|
-
};
|
|
333
|
-
}
|
|
334
|
-
if (existing.contentHash !== newHash) {
|
|
335
|
-
return {
|
|
336
|
-
version: bumpMajorVersion(existing.version),
|
|
337
|
-
contentHash: newHash
|
|
338
|
-
};
|
|
339
|
-
}
|
|
340
|
-
return {
|
|
341
|
-
version: existing.version,
|
|
342
|
-
contentHash: newHash
|
|
343
|
-
};
|
|
344
|
-
}
|
|
345
|
-
async function compileAgentForPlugin(name, agent, fallbackRoot, engine) {
|
|
346
|
-
verbose(`Compiling agent: ${name}`);
|
|
347
|
-
const agentSourceRoot = agent.sourceRoot || fallbackRoot;
|
|
348
|
-
const agentBaseDir = agent.agentBaseDir || DIRS.agents;
|
|
349
|
-
const agentDir = path2.join(agentSourceRoot, agentBaseDir, agent.path || name);
|
|
350
|
-
const intro = await readFile(path2.join(agentDir, "intro.md"));
|
|
351
|
-
const workflow = await readFile(path2.join(agentDir, "workflow.md"));
|
|
352
|
-
const examples = await readFileOptional(
|
|
353
|
-
path2.join(agentDir, "examples.md"),
|
|
354
|
-
"## Examples\n\n_No examples defined._"
|
|
355
|
-
);
|
|
356
|
-
const criticalRequirementsTop = await readFileOptional(
|
|
357
|
-
path2.join(agentDir, "critical-requirements.md"),
|
|
358
|
-
""
|
|
359
|
-
);
|
|
360
|
-
const criticalReminders = await readFileOptional(
|
|
361
|
-
path2.join(agentDir, "critical-reminders.md"),
|
|
362
|
-
""
|
|
363
|
-
);
|
|
364
|
-
const agentPath = agent.path || name;
|
|
365
|
-
const category = agentPath.split("/")[0];
|
|
366
|
-
const categoryDir = path2.join(agentSourceRoot, agentBaseDir, category);
|
|
367
|
-
let outputFormat = await readFileOptional(path2.join(agentDir, "output-format.md"), "");
|
|
368
|
-
if (!outputFormat) {
|
|
369
|
-
outputFormat = await readFileOptional(path2.join(categoryDir, "output-format.md"), "");
|
|
370
|
-
}
|
|
371
|
-
const preloadedSkills = agent.skills.filter((s) => s.preloaded);
|
|
372
|
-
const dynamicSkills = agent.skills.filter((s) => !s.preloaded);
|
|
373
|
-
const preloadedSkillIds = preloadedSkills.map((s) => s.id);
|
|
374
|
-
verbose(
|
|
375
|
-
`Skills for ${name}: ${preloadedSkills.length} preloaded, ${dynamicSkills.length} dynamic`
|
|
376
|
-
);
|
|
377
|
-
const data = {
|
|
378
|
-
agent,
|
|
379
|
-
intro,
|
|
380
|
-
workflow,
|
|
381
|
-
examples,
|
|
382
|
-
criticalRequirementsTop,
|
|
383
|
-
criticalReminders,
|
|
384
|
-
outputFormat,
|
|
385
|
-
skills: agent.skills,
|
|
386
|
-
preloadedSkills,
|
|
387
|
-
dynamicSkills,
|
|
388
|
-
preloadedSkillIds
|
|
389
|
-
};
|
|
390
|
-
return engine.renderFile("agent", data);
|
|
391
|
-
}
|
|
392
|
-
function generateStackReadme(stackId, stack, agents, skillPlugins) {
|
|
393
|
-
const lines = [];
|
|
394
|
-
lines.push(`# ${stack.name}`);
|
|
395
|
-
lines.push("");
|
|
396
|
-
lines.push(stack.description || "A Claude Code stack plugin.");
|
|
397
|
-
lines.push("");
|
|
398
|
-
if (stack.tags && stack.tags.length > 0) {
|
|
399
|
-
lines.push("## Tags");
|
|
400
|
-
lines.push("");
|
|
401
|
-
lines.push(stack.tags.map((t) => `\`${t}\``).join(" "));
|
|
402
|
-
lines.push("");
|
|
403
|
-
}
|
|
404
|
-
lines.push("## Installation");
|
|
405
|
-
lines.push("");
|
|
406
|
-
lines.push("Add this plugin to your Claude Code configuration:");
|
|
407
|
-
lines.push("");
|
|
408
|
-
lines.push("```json");
|
|
409
|
-
lines.push(`{`);
|
|
410
|
-
lines.push(` "plugins": ["${stackId}"]`);
|
|
411
|
-
lines.push(`}`);
|
|
412
|
-
lines.push("```");
|
|
413
|
-
lines.push("");
|
|
414
|
-
lines.push("## Agents");
|
|
415
|
-
lines.push("");
|
|
416
|
-
lines.push("This stack includes the following agents:");
|
|
417
|
-
lines.push("");
|
|
418
|
-
for (const agent of agents) {
|
|
419
|
-
lines.push(`- \`${agent}\``);
|
|
420
|
-
}
|
|
421
|
-
lines.push("");
|
|
422
|
-
if (skillPlugins.length > 0) {
|
|
423
|
-
lines.push("## Included Skills");
|
|
424
|
-
lines.push("");
|
|
425
|
-
lines.push("This stack includes the following skills:");
|
|
426
|
-
lines.push("");
|
|
427
|
-
const uniqueSkills = [...new Set(skillPlugins)].sort();
|
|
428
|
-
for (const skill of uniqueSkills) {
|
|
429
|
-
lines.push(`- \`${skill}\``);
|
|
430
|
-
}
|
|
431
|
-
lines.push("");
|
|
432
|
-
}
|
|
433
|
-
if (stack.philosophy) {
|
|
434
|
-
lines.push("## Philosophy");
|
|
435
|
-
lines.push("");
|
|
436
|
-
lines.push(stack.philosophy);
|
|
437
|
-
lines.push("");
|
|
438
|
-
}
|
|
439
|
-
if (stack.principles && stack.principles.length > 0) {
|
|
440
|
-
lines.push("## Principles");
|
|
441
|
-
lines.push("");
|
|
442
|
-
for (const principle of stack.principles) {
|
|
443
|
-
lines.push(`- ${principle}`);
|
|
444
|
-
}
|
|
445
|
-
lines.push("");
|
|
446
|
-
}
|
|
447
|
-
lines.push("---");
|
|
448
|
-
lines.push("");
|
|
449
|
-
lines.push("*Generated by Claude Collective stack-plugin-compiler*");
|
|
450
|
-
lines.push("");
|
|
451
|
-
return lines.join("\n");
|
|
452
|
-
}
|
|
453
|
-
function stackHasHooks(stack) {
|
|
454
|
-
return stack.hooks !== void 0 && Object.keys(stack.hooks).length > 0;
|
|
455
|
-
}
|
|
456
|
-
function generateHooksJson(hooks) {
|
|
457
|
-
const output = { hooks };
|
|
458
|
-
return JSON.stringify(output, null, 2);
|
|
459
|
-
}
|
|
460
|
-
async function compileStackPlugin(options) {
|
|
461
|
-
const { stackId, outputDir, projectRoot, agentSourcePath } = options;
|
|
462
|
-
const localAgentRoot = agentSourcePath || projectRoot;
|
|
463
|
-
verbose(`Compiling stack plugin: ${stackId}`);
|
|
464
|
-
verbose(` Stack/skills source: ${projectRoot}`);
|
|
465
|
-
verbose(` Local agent source: ${localAgentRoot}`);
|
|
466
|
-
verbose(` CLI agent source: ${PROJECT_ROOT}`);
|
|
467
|
-
const cliAgents = await loadAllAgents(PROJECT_ROOT);
|
|
468
|
-
const localAgents = await loadAllAgents(localAgentRoot);
|
|
469
|
-
const agents = { ...cliAgents, ...localAgents };
|
|
470
|
-
verbose(
|
|
471
|
-
` Loaded ${Object.keys(localAgents).length} local agents, ${Object.keys(cliAgents).length} CLI agents`
|
|
472
|
-
);
|
|
473
|
-
const newStack = options.stack || await loadStackById(stackId, PROJECT_ROOT);
|
|
474
|
-
const matrixPath = path2.join(PROJECT_ROOT, SKILLS_MATRIX_PATH);
|
|
475
|
-
const matrix = await loadSkillsMatrix(matrixPath);
|
|
476
|
-
const skillAliases = matrix.skill_aliases || {};
|
|
477
|
-
let stack;
|
|
478
|
-
if (newStack) {
|
|
479
|
-
verbose(` Found stack: ${newStack.name}`);
|
|
480
|
-
const agentSkillIds = /* @__PURE__ */ new Set();
|
|
481
|
-
for (const agentName of Object.keys(newStack.agents)) {
|
|
482
|
-
const agentConfig = newStack.agents[agentName];
|
|
483
|
-
const skillRefs = resolveAgentConfigToSkills(agentConfig, skillAliases);
|
|
484
|
-
for (const ref of skillRefs) {
|
|
485
|
-
agentSkillIds.add(ref.id);
|
|
486
|
-
}
|
|
487
|
-
}
|
|
488
|
-
stack = {
|
|
489
|
-
name: newStack.name,
|
|
490
|
-
description: newStack.description,
|
|
491
|
-
skills: Array.from(agentSkillIds).map((id) => ({ id })),
|
|
492
|
-
agents: Object.keys(newStack.agents),
|
|
493
|
-
philosophy: newStack.philosophy
|
|
494
|
-
};
|
|
495
|
-
} else {
|
|
496
|
-
throw new Error(`Stack '${stackId}' not found in config/stacks.yaml`);
|
|
497
|
-
}
|
|
498
|
-
const normalizedSkillIds = (stack.skills || []).map(
|
|
499
|
-
(s) => typeof s === "string" ? { id: s } : s
|
|
500
|
-
);
|
|
501
|
-
const skills = await loadSkillsByIds(normalizedSkillIds, projectRoot);
|
|
502
|
-
const compileConfig = stackToCompileConfig(stackId, stack);
|
|
503
|
-
const resolvedAgents = await resolveAgents(
|
|
504
|
-
agents,
|
|
505
|
-
skills,
|
|
506
|
-
compileConfig,
|
|
507
|
-
projectRoot,
|
|
508
|
-
newStack,
|
|
509
|
-
skillAliases
|
|
510
|
-
);
|
|
511
|
-
const pluginDir = path2.join(outputDir, stackId);
|
|
512
|
-
const agentsDir = path2.join(pluginDir, "agents");
|
|
513
|
-
await ensureDir(pluginDir);
|
|
514
|
-
await ensureDir(agentsDir);
|
|
515
|
-
const pluginSkillsDir = path2.join(pluginDir, "skills");
|
|
516
|
-
await ensureDir(pluginSkillsDir);
|
|
517
|
-
const copiedSourcePaths = /* @__PURE__ */ new Set();
|
|
518
|
-
for (const [, resolvedSkill] of Object.entries(skills)) {
|
|
519
|
-
const sourceSkillDir = path2.join(projectRoot, resolvedSkill.path);
|
|
520
|
-
if (copiedSourcePaths.has(resolvedSkill.path)) {
|
|
521
|
-
continue;
|
|
522
|
-
}
|
|
523
|
-
const destSkillDir = path2.join(pluginSkillsDir, resolvedSkill.canonicalId);
|
|
524
|
-
if (await directoryExists(sourceSkillDir)) {
|
|
525
|
-
await copy(sourceSkillDir, destSkillDir);
|
|
526
|
-
copiedSourcePaths.add(resolvedSkill.path);
|
|
527
|
-
verbose(` Copied skill: ${resolvedSkill.canonicalId}`);
|
|
528
|
-
} else {
|
|
529
|
-
verbose(` Warning: Skill directory not found: ${sourceSkillDir}`);
|
|
530
|
-
}
|
|
531
|
-
}
|
|
532
|
-
const engine = await createLiquidEngine();
|
|
533
|
-
const compiledAgentNames = [];
|
|
534
|
-
const allSkillPlugins = [];
|
|
535
|
-
for (const [name, agent] of Object.entries(resolvedAgents)) {
|
|
536
|
-
const output = await compileAgentForPlugin(name, agent, PROJECT_ROOT, engine);
|
|
537
|
-
await writeFile(path2.join(agentsDir, `${name}.md`), output);
|
|
538
|
-
compiledAgentNames.push(name);
|
|
539
|
-
for (const skill of agent.skills) {
|
|
540
|
-
allSkillPlugins.push(skill.id);
|
|
541
|
-
}
|
|
542
|
-
verbose(` Compiled agent: ${name}`);
|
|
543
|
-
}
|
|
544
|
-
const stackDir = path2.join(projectRoot, DIRS.stacks, stackId);
|
|
545
|
-
const claudeMdPath = path2.join(stackDir, "CLAUDE.md");
|
|
546
|
-
if (await fileExists(claudeMdPath)) {
|
|
547
|
-
const claudeContent = await readFile(claudeMdPath);
|
|
548
|
-
await writeFile(path2.join(pluginDir, "CLAUDE.md"), claudeContent);
|
|
549
|
-
verbose(` Copied CLAUDE.md`);
|
|
550
|
-
}
|
|
551
|
-
const hasHooks = stackHasHooks(stack);
|
|
552
|
-
if (hasHooks && stack.hooks) {
|
|
553
|
-
const hooksDir = path2.join(pluginDir, "hooks");
|
|
554
|
-
await ensureDir(hooksDir);
|
|
555
|
-
const hooksJson = generateHooksJson(stack.hooks);
|
|
556
|
-
await writeFile(path2.join(hooksDir, "hooks.json"), hooksJson);
|
|
557
|
-
verbose(` Generated hooks/hooks.json`);
|
|
558
|
-
}
|
|
559
|
-
const { version, contentHash } = await determineStackVersion(stack, pluginDir);
|
|
560
|
-
const uniqueSkillPlugins = [...new Set(allSkillPlugins)];
|
|
561
|
-
const manifest = generateStackPluginManifest({
|
|
562
|
-
stackName: stackId,
|
|
563
|
-
description: stack.description,
|
|
564
|
-
author: stack.author,
|
|
565
|
-
version,
|
|
566
|
-
keywords: stack.tags,
|
|
567
|
-
hasAgents: true,
|
|
568
|
-
hasHooks,
|
|
569
|
-
hasSkills: true
|
|
570
|
-
});
|
|
571
|
-
await writePluginManifest(pluginDir, manifest);
|
|
572
|
-
const hashFilePath = getPluginManifestPath(pluginDir).replace("plugin.json", CONTENT_HASH_FILE);
|
|
573
|
-
await writeFile(hashFilePath, contentHash);
|
|
574
|
-
verbose(` Wrote plugin.json (v${version})`);
|
|
575
|
-
const readme = generateStackReadme(stackId, stack, compiledAgentNames, uniqueSkillPlugins);
|
|
576
|
-
await writeFile(path2.join(pluginDir, "README.md"), readme);
|
|
577
|
-
verbose(` Generated README.md`);
|
|
578
|
-
return {
|
|
579
|
-
pluginPath: pluginDir,
|
|
580
|
-
manifest,
|
|
581
|
-
stackName: stack.name,
|
|
582
|
-
agents: compiledAgentNames,
|
|
583
|
-
skillPlugins: uniqueSkillPlugins,
|
|
584
|
-
hasHooks
|
|
585
|
-
};
|
|
586
|
-
}
|
|
587
|
-
function printStackCompilationSummary(result) {
|
|
588
|
-
console.log(`
|
|
589
|
-
Stack plugin compiled: ${result.stackName}`);
|
|
590
|
-
console.log(` Path: ${result.pluginPath}`);
|
|
591
|
-
console.log(` Agents: ${result.agents.length}`);
|
|
592
|
-
for (const agent of result.agents) {
|
|
593
|
-
console.log(` - ${agent}`);
|
|
594
|
-
}
|
|
595
|
-
if (result.skillPlugins.length > 0) {
|
|
596
|
-
console.log(` Skills included: ${result.skillPlugins.length}`);
|
|
597
|
-
for (const skill of result.skillPlugins) {
|
|
598
|
-
console.log(` - ${skill}`);
|
|
599
|
-
}
|
|
600
|
-
}
|
|
601
|
-
if (result.hasHooks) {
|
|
602
|
-
console.log(` Hooks: enabled`);
|
|
603
|
-
}
|
|
604
|
-
}
|
|
605
|
-
|
|
606
|
-
export {
|
|
607
|
-
resolveAgentSkillsFromStack,
|
|
608
|
-
resolveStackSkills,
|
|
609
|
-
resolveAgents,
|
|
610
|
-
createLiquidEngine,
|
|
611
|
-
compileAgentForPlugin,
|
|
612
|
-
compileStackPlugin,
|
|
613
|
-
printStackCompilationSummary
|
|
614
|
-
};
|
|
615
|
-
//# sourceMappingURL=chunk-7SLV7CMF.js.map
|