@claude-collective/cli 0.29.4 → 0.30.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 +35 -0
- package/config/skills-matrix.yaml +1 -1
- package/config/stacks.yaml +1 -1
- package/dist/{chunk-XPMEGGJK.js → chunk-34E7MWJI.js} +13 -38
- package/dist/chunk-34E7MWJI.js.map +1 -0
- package/dist/{chunk-IFODQTCX.js → chunk-52XVP55K.js} +6 -3
- package/dist/chunk-52XVP55K.js.map +1 -0
- package/dist/{chunk-N73GQTCK.js → chunk-5P6RUVA7.js} +6 -6
- package/dist/{chunk-ZX5DM4D5.js → chunk-AGNT3FUE.js} +3 -3
- package/dist/{chunk-A4T4YSV4.js → chunk-AGQRRJSY.js} +2 -2
- package/dist/{chunk-6F3ZKDVE.js → chunk-AXND7NCM.js} +3 -3
- package/dist/{chunk-EP6J44I4.js → chunk-DH6F7EOJ.js} +5 -5
- package/dist/{chunk-AG5YGYJT.js → chunk-DTFEFLUU.js} +2 -2
- package/dist/chunk-EOJTMX7T.js +183 -0
- package/dist/chunk-EOJTMX7T.js.map +1 -0
- package/dist/{chunk-AJFSCLJ7.js → chunk-F23LEXMC.js} +2 -2
- package/dist/{chunk-G5WXKKQM.js → chunk-FFZSN5C5.js} +5 -5
- package/dist/chunk-FFZSN5C5.js.map +1 -0
- package/dist/{chunk-FY5D4KIC.js → chunk-H2NM6BDH.js} +2 -2
- package/dist/{chunk-56ERY7H7.js → chunk-HMZPUOWU.js} +4 -4
- package/dist/{chunk-RI5QEK5W.js → chunk-I6YQDA2J.js} +2 -2
- package/dist/{chunk-MQAYAISQ.js → chunk-JWIH7YQE.js} +2 -2
- package/dist/{chunk-VTUPUKFD.js → chunk-KFL72CWK.js} +2 -2
- package/dist/{chunk-OA5RCL2L.js → chunk-LY5HM34M.js} +2 -2
- package/dist/{chunk-XZKVOPCR.js → chunk-MYLRA7NI.js} +4 -4
- package/dist/{chunk-EUPMWSM3.js → chunk-QR2ONHDW.js} +5 -5
- package/dist/{chunk-SSHG7MEE.js → chunk-QUL7R35E.js} +307 -504
- package/dist/chunk-QUL7R35E.js.map +1 -0
- package/dist/{chunk-7UKQZSWT.js → chunk-RFW2RIM7.js} +2 -2
- package/dist/{chunk-PNXFJPXF.js → chunk-URUSBWWI.js} +2 -2
- package/dist/{chunk-GVVEPVR7.js → chunk-VHVRPLDY.js} +4 -4
- package/dist/{chunk-IRG52AN5.js → chunk-VIBOSHRL.js} +2 -2
- package/dist/{chunk-IQUBOWWU.js → chunk-WWLEF4MQ.js} +3 -3
- package/dist/{chunk-WLQUQXWO.js → chunk-WXW6SQ5K.js} +3 -3
- package/dist/{chunk-DUIYVKFK.js → chunk-X5AD7WWC.js} +12 -12
- package/dist/commands/build/marketplace.js +1 -1
- package/dist/commands/build/plugins.js +3 -3
- package/dist/commands/build/stack.js +3 -3
- package/dist/commands/compile.js +21 -70
- package/dist/commands/compile.js.map +1 -1
- package/dist/commands/config/get.js +2 -2
- package/dist/commands/config/index.js +3 -3
- package/dist/commands/config/path.js +2 -2
- package/dist/commands/config/set-project.js +2 -2
- package/dist/commands/config/show.js +3 -3
- package/dist/commands/config/unset-project.js +2 -2
- package/dist/commands/diff.js +2 -2
- package/dist/commands/doctor.js +2 -2
- package/dist/commands/edit.js +40 -71
- package/dist/commands/edit.js.map +1 -1
- package/dist/commands/eject.js +2 -2
- package/dist/commands/import/skill.js +2 -2
- package/dist/commands/info.js +2 -2
- package/dist/commands/init.js +79 -109
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/list.js +2 -2
- package/dist/commands/new/agent.js +5 -3
- package/dist/commands/new/agent.js.map +1 -1
- package/dist/commands/new/skill.js +2 -2
- package/dist/commands/outdated.js +2 -2
- package/dist/commands/search.js +4 -4
- package/dist/commands/uninstall.js +41 -29
- package/dist/commands/uninstall.js.map +1 -1
- package/dist/commands/update.js +4 -6
- package/dist/commands/update.js.map +1 -1
- package/dist/commands/validate.js +2 -2
- package/dist/commands/version/bump.js +2 -2
- package/dist/commands/version/index.js +2 -2
- package/dist/commands/version/set.js +2 -2
- package/dist/commands/version/show.js +2 -2
- 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 +2 -2
- package/dist/components/wizard/domain-selection.js +4 -4
- package/dist/components/wizard/help-modal.js +2 -2
- package/dist/components/wizard/menu-item.js +2 -2
- package/dist/components/wizard/search-modal.js +2 -2
- package/dist/components/wizard/search-modal.test.js +2 -2
- package/dist/components/wizard/section-progress.js +2 -2
- package/dist/components/wizard/section-progress.test.js +2 -2
- package/dist/components/wizard/source-grid.js +3 -3
- package/dist/components/wizard/source-grid.test.js +3 -3
- package/dist/components/wizard/stack-selection.js +6 -6
- package/dist/components/wizard/step-approach.js +6 -6
- package/dist/components/wizard/step-approach.test.js +6 -6
- package/dist/components/wizard/step-build.js +5 -5
- package/dist/components/wizard/step-build.test.js +5 -5
- package/dist/components/wizard/step-confirm.js +2 -2
- package/dist/components/wizard/step-confirm.test.js +4 -4
- package/dist/components/wizard/step-refine.js +2 -2
- package/dist/components/wizard/step-refine.test.js +2 -2
- package/dist/components/wizard/step-settings.js +4 -4
- package/dist/components/wizard/step-settings.test.js +8 -8
- package/dist/components/wizard/step-settings.test.js.map +1 -1
- package/dist/components/wizard/step-sources.js +7 -7
- package/dist/components/wizard/step-sources.test.js +7 -7
- package/dist/components/wizard/step-stack.js +8 -8
- package/dist/components/wizard/step-stack.test.js +8 -8
- package/dist/components/wizard/view-title.js +2 -2
- package/dist/components/wizard/wizard-layout.js +6 -6
- package/dist/components/wizard/wizard-tabs.js +2 -2
- package/dist/components/wizard/wizard-tabs.test.js +2 -2
- package/dist/components/wizard/wizard.js +21 -21
- package/dist/config/skills-matrix.yaml +1 -1
- package/dist/config/stacks.yaml +1 -1
- package/dist/hooks/init.js +2 -2
- package/dist/{source-manager-TV2YGPAN.js → source-manager-S5XTC6RW.js} +3 -3
- 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/meta/skill-summoner/output-format.md +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 +3 -3
- package/dist/stores/wizard-store.test.js +3 -3
- package/package.json +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/meta/skill-summoner/output-format.md +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-G5WXKKQM.js.map +0 -1
- package/dist/chunk-IFODQTCX.js.map +0 -1
- package/dist/chunk-SSHG7MEE.js.map +0 -1
- package/dist/chunk-XPMEGGJK.js.map +0 -1
- /package/dist/{chunk-N73GQTCK.js.map → chunk-5P6RUVA7.js.map} +0 -0
- /package/dist/{chunk-ZX5DM4D5.js.map → chunk-AGNT3FUE.js.map} +0 -0
- /package/dist/{chunk-A4T4YSV4.js.map → chunk-AGQRRJSY.js.map} +0 -0
- /package/dist/{chunk-6F3ZKDVE.js.map → chunk-AXND7NCM.js.map} +0 -0
- /package/dist/{chunk-EP6J44I4.js.map → chunk-DH6F7EOJ.js.map} +0 -0
- /package/dist/{chunk-AG5YGYJT.js.map → chunk-DTFEFLUU.js.map} +0 -0
- /package/dist/{chunk-AJFSCLJ7.js.map → chunk-F23LEXMC.js.map} +0 -0
- /package/dist/{chunk-FY5D4KIC.js.map → chunk-H2NM6BDH.js.map} +0 -0
- /package/dist/{chunk-56ERY7H7.js.map → chunk-HMZPUOWU.js.map} +0 -0
- /package/dist/{chunk-RI5QEK5W.js.map → chunk-I6YQDA2J.js.map} +0 -0
- /package/dist/{chunk-MQAYAISQ.js.map → chunk-JWIH7YQE.js.map} +0 -0
- /package/dist/{chunk-VTUPUKFD.js.map → chunk-KFL72CWK.js.map} +0 -0
- /package/dist/{chunk-OA5RCL2L.js.map → chunk-LY5HM34M.js.map} +0 -0
- /package/dist/{chunk-XZKVOPCR.js.map → chunk-MYLRA7NI.js.map} +0 -0
- /package/dist/{chunk-EUPMWSM3.js.map → chunk-QR2ONHDW.js.map} +0 -0
- /package/dist/{chunk-7UKQZSWT.js.map → chunk-RFW2RIM7.js.map} +0 -0
- /package/dist/{chunk-PNXFJPXF.js.map → chunk-URUSBWWI.js.map} +0 -0
- /package/dist/{chunk-GVVEPVR7.js.map → chunk-VHVRPLDY.js.map} +0 -0
- /package/dist/{chunk-IRG52AN5.js.map → chunk-VIBOSHRL.js.map} +0 -0
- /package/dist/{chunk-IQUBOWWU.js.map → chunk-WWLEF4MQ.js.map} +0 -0
- /package/dist/{chunk-WLQUQXWO.js.map → chunk-WXW6SQ5K.js.map} +0 -0
- /package/dist/{chunk-DUIYVKFK.js.map → chunk-X5AD7WWC.js.map} +0 -0
- /package/dist/{source-manager-TV2YGPAN.js.map → source-manager-S5XTC6RW.js.map} +0 -0
|
@@ -68,7 +68,7 @@ import {
|
|
|
68
68
|
STANDARD_FILES,
|
|
69
69
|
YAML_FORMATTING,
|
|
70
70
|
yamlSchemaComment
|
|
71
|
-
} from "./chunk-
|
|
71
|
+
} from "./chunk-52XVP55K.js";
|
|
72
72
|
import {
|
|
73
73
|
init_esm_shims
|
|
74
74
|
} from "./chunk-AWKZ5BDL.js";
|
|
@@ -363,8 +363,8 @@ Examples:
|
|
|
363
363
|
}
|
|
364
364
|
}
|
|
365
365
|
function validateLocalPath(source, flagName) {
|
|
366
|
-
const
|
|
367
|
-
if (
|
|
366
|
+
const CONTROL_CHAR_PATTERN = /[\x00-\x08\x0E-\x1F\x7F]/u;
|
|
367
|
+
if (CONTROL_CHAR_PATTERN.test(source)) {
|
|
368
368
|
throw new Error(
|
|
369
369
|
`${flagName} contains invalid characters: "${source}"
|
|
370
370
|
|
|
@@ -682,11 +682,6 @@ function resolveSkillPath(basePath, skillPath) {
|
|
|
682
682
|
validateSkillPath(resolved, basePath, skillPath);
|
|
683
683
|
return resolved;
|
|
684
684
|
}
|
|
685
|
-
function getSkillDestPath(skill, stackDir) {
|
|
686
|
-
const skillRelativePath = skill.path.replace(/^skills\//, "");
|
|
687
|
-
const skillsDir = path4.join(stackDir, "skills");
|
|
688
|
-
return resolveSkillPath(skillsDir, skillRelativePath);
|
|
689
|
-
}
|
|
690
685
|
async function generateSkillHash(skillSourcePath) {
|
|
691
686
|
const skillMdPath = path4.join(skillSourcePath, STANDARD_FILES.SKILL_MD);
|
|
692
687
|
return computeFileHash(skillMdPath);
|
|
@@ -695,55 +690,6 @@ function getSkillSourcePathFromSource(skill, sourceResult) {
|
|
|
695
690
|
const srcDir = path4.join(sourceResult.sourcePath, "src");
|
|
696
691
|
return resolveSkillPath(srcDir, skill.path);
|
|
697
692
|
}
|
|
698
|
-
async function copySkillFromSource(skill, stackDir, sourceResult) {
|
|
699
|
-
const sourcePath = getSkillSourcePathFromSource(skill, sourceResult);
|
|
700
|
-
const destPath = getSkillDestPath(skill, stackDir);
|
|
701
|
-
const contentHash = await generateSkillHash(sourcePath);
|
|
702
|
-
await ensureDir(path4.dirname(destPath));
|
|
703
|
-
await copy(sourcePath, destPath);
|
|
704
|
-
await injectForkedFromMetadata(destPath, skill.id, contentHash);
|
|
705
|
-
return {
|
|
706
|
-
skillId: skill.id,
|
|
707
|
-
contentHash,
|
|
708
|
-
sourcePath,
|
|
709
|
-
destPath
|
|
710
|
-
};
|
|
711
|
-
}
|
|
712
|
-
async function copySkillsToPluginFromSource(selectedSkillIds, pluginDir, matrix, sourceResult, sourceSelections, onProgress) {
|
|
713
|
-
const total = selectedSkillIds.length;
|
|
714
|
-
let completed = 0;
|
|
715
|
-
const results = await Promise.all(
|
|
716
|
-
selectedSkillIds.map(async (skillId) => {
|
|
717
|
-
const skill = matrix.skills[skillId];
|
|
718
|
-
if (!skill) {
|
|
719
|
-
warn(`Skill not found in matrix: '${skillId}'`);
|
|
720
|
-
completed++;
|
|
721
|
-
onProgress?.(completed, total);
|
|
722
|
-
return null;
|
|
723
|
-
}
|
|
724
|
-
const selectedSource = sourceSelections?.[skillId];
|
|
725
|
-
const userSelectedRemote = selectedSource && selectedSource !== "local";
|
|
726
|
-
let result;
|
|
727
|
-
if (skill.local && skill.localPath && !userSelectedRemote) {
|
|
728
|
-
const localSkillPath = path4.join(process.cwd(), skill.localPath);
|
|
729
|
-
const contentHash = await generateSkillHash(localSkillPath);
|
|
730
|
-
result = {
|
|
731
|
-
skillId: skill.id,
|
|
732
|
-
sourcePath: skill.localPath,
|
|
733
|
-
destPath: skill.localPath,
|
|
734
|
-
contentHash,
|
|
735
|
-
local: true
|
|
736
|
-
};
|
|
737
|
-
} else {
|
|
738
|
-
result = await copySkillFromSource(skill, pluginDir, sourceResult);
|
|
739
|
-
}
|
|
740
|
-
completed++;
|
|
741
|
-
onProgress?.(completed, total);
|
|
742
|
-
return result;
|
|
743
|
-
})
|
|
744
|
-
);
|
|
745
|
-
return results.filter((r) => r !== null);
|
|
746
|
-
}
|
|
747
693
|
function getFlattenedSkillDestPath(skill, localSkillsDir) {
|
|
748
694
|
return resolveSkillPath(localSkillsDir, skill.id);
|
|
749
695
|
}
|
|
@@ -1840,106 +1786,20 @@ async function findPluginManifest(startDir) {
|
|
|
1840
1786
|
init_esm_shims();
|
|
1841
1787
|
import path9 from "path";
|
|
1842
1788
|
import { last, zip } from "remeda";
|
|
1843
|
-
var MAX_SKILL_NAME_LENGTH = 100;
|
|
1844
|
-
function getCollectivePluginDir(projectDir) {
|
|
1845
|
-
const dir = projectDir ?? process.cwd();
|
|
1846
|
-
return path9.join(dir, CLAUDE_DIR, PLUGINS_SUBDIR, DEFAULT_PLUGIN_NAME);
|
|
1847
|
-
}
|
|
1848
1789
|
function getProjectPluginsDir(projectDir) {
|
|
1849
1790
|
const dir = projectDir ?? process.cwd();
|
|
1850
1791
|
return path9.join(dir, CLAUDE_DIR, PLUGINS_SUBDIR);
|
|
1851
1792
|
}
|
|
1852
|
-
function getPluginSkillsDir(pluginDir) {
|
|
1853
|
-
return path9.join(pluginDir, "skills");
|
|
1854
|
-
}
|
|
1855
1793
|
function getPluginAgentsDir(pluginDir) {
|
|
1856
1794
|
return path9.join(pluginDir, "agents");
|
|
1857
1795
|
}
|
|
1858
1796
|
function getPluginManifestPath(pluginDir) {
|
|
1859
1797
|
return path9.join(pluginDir, PLUGIN_MANIFEST_DIR, PLUGIN_MANIFEST_FILE);
|
|
1860
1798
|
}
|
|
1861
|
-
async function readPluginManifest(pluginDir) {
|
|
1862
|
-
const manifestPath = getPluginManifestPath(pluginDir);
|
|
1863
|
-
if (!await fileExists(manifestPath)) {
|
|
1864
|
-
verbose(` No manifest at ${manifestPath}`);
|
|
1865
|
-
return null;
|
|
1866
|
-
}
|
|
1867
|
-
try {
|
|
1868
|
-
const content = await readFileSafe(manifestPath, MAX_PLUGIN_FILE_SIZE);
|
|
1869
|
-
const manifest = pluginManifestSchema.parse(JSON.parse(content));
|
|
1870
|
-
if (!manifest.name || typeof manifest.name !== "string") {
|
|
1871
|
-
verbose(` Invalid manifest at ${manifestPath}: missing name`);
|
|
1872
|
-
return null;
|
|
1873
|
-
}
|
|
1874
|
-
return manifest;
|
|
1875
|
-
} catch (error) {
|
|
1876
|
-
verbose(` Failed to parse manifest at ${manifestPath}: ${error}`);
|
|
1877
|
-
return null;
|
|
1878
|
-
}
|
|
1879
|
-
}
|
|
1880
|
-
async function getPluginSkillIds(pluginSkillsDir, matrix) {
|
|
1881
|
-
const skillFiles = await glob("**/SKILL.md", pluginSkillsDir);
|
|
1882
|
-
const skillIds = [];
|
|
1883
|
-
const aliasToId = /* @__PURE__ */ new Map();
|
|
1884
|
-
for (const [id, skill] of typedEntries(matrix.skills)) {
|
|
1885
|
-
if (!skill) continue;
|
|
1886
|
-
if (skill.displayName) {
|
|
1887
|
-
aliasToId.set(skill.displayName.toLowerCase(), id);
|
|
1888
|
-
}
|
|
1889
|
-
}
|
|
1890
|
-
const dirToId = /* @__PURE__ */ new Map();
|
|
1891
|
-
for (const [id] of typedEntries(matrix.skills)) {
|
|
1892
|
-
const idParts = id.split("/");
|
|
1893
|
-
const lastPart = last(idParts);
|
|
1894
|
-
if (lastPart) {
|
|
1895
|
-
dirToId.set(lastPart.toLowerCase(), id);
|
|
1896
|
-
}
|
|
1897
|
-
}
|
|
1898
|
-
const fileContents = await Promise.all(
|
|
1899
|
-
skillFiles.map((skillFile) => readFile(path9.join(pluginSkillsDir, skillFile)))
|
|
1900
|
-
);
|
|
1901
|
-
for (const [skillFile, content] of zip(skillFiles, fileContents)) {
|
|
1902
|
-
const frontmatterMatch = content.match(/^---\n([\s\S]*?)\n---/);
|
|
1903
|
-
if (frontmatterMatch) {
|
|
1904
|
-
const frontmatter = frontmatterMatch[1];
|
|
1905
|
-
const nameMatch = frontmatter.match(/^name:\s*["']?(.+?)["']?\s*$/m);
|
|
1906
|
-
if (nameMatch) {
|
|
1907
|
-
const skillName = nameMatch[1].trim();
|
|
1908
|
-
if (skillName.length === 0) {
|
|
1909
|
-
warn(`Skipping plugin skill '${skillFile}': empty name in frontmatter`);
|
|
1910
|
-
continue;
|
|
1911
|
-
}
|
|
1912
|
-
if (skillName.length > MAX_SKILL_NAME_LENGTH) {
|
|
1913
|
-
warn(
|
|
1914
|
-
`Skipping plugin skill '${skillFile}': name exceeds ${MAX_SKILL_NAME_LENGTH} characters`
|
|
1915
|
-
);
|
|
1916
|
-
continue;
|
|
1917
|
-
}
|
|
1918
|
-
if (matrix.skills[skillName]) {
|
|
1919
|
-
skillIds.push(skillName);
|
|
1920
|
-
continue;
|
|
1921
|
-
}
|
|
1922
|
-
const skillId2 = aliasToId.get(skillName.toLowerCase());
|
|
1923
|
-
if (skillId2) {
|
|
1924
|
-
skillIds.push(skillId2);
|
|
1925
|
-
continue;
|
|
1926
|
-
}
|
|
1927
|
-
}
|
|
1928
|
-
}
|
|
1929
|
-
const dirPath = path9.dirname(skillFile);
|
|
1930
|
-
const dirName = path9.basename(dirPath);
|
|
1931
|
-
const skillId = dirToId.get(dirName.toLowerCase());
|
|
1932
|
-
if (skillId) {
|
|
1933
|
-
skillIds.push(skillId);
|
|
1934
|
-
}
|
|
1935
|
-
}
|
|
1936
|
-
return skillIds;
|
|
1937
|
-
}
|
|
1938
1799
|
|
|
1939
1800
|
// src/cli/lib/plugins/plugin-info.ts
|
|
1940
1801
|
init_esm_shims();
|
|
1941
1802
|
import { readdir } from "fs/promises";
|
|
1942
|
-
import { countBy } from "remeda";
|
|
1943
1803
|
|
|
1944
1804
|
// src/cli/lib/installation/index.ts
|
|
1945
1805
|
init_esm_shims();
|
|
@@ -1951,36 +1811,32 @@ async function detectInstallation(projectDir = process.cwd()) {
|
|
|
1951
1811
|
const srcConfigPath = path10.join(projectDir, CLAUDE_SRC_DIR, STANDARD_FILES.CONFIG_YAML);
|
|
1952
1812
|
const legacyConfigPath = path10.join(projectDir, CLAUDE_DIR, STANDARD_FILES.CONFIG_YAML);
|
|
1953
1813
|
const localConfigPath = await fileExists(srcConfigPath) ? srcConfigPath : await fileExists(legacyConfigPath) ? legacyConfigPath : null;
|
|
1954
|
-
if (localConfigPath) {
|
|
1955
|
-
|
|
1956
|
-
const mode = loaded?.config?.installMode ?? "local";
|
|
1957
|
-
if (mode === "local") {
|
|
1958
|
-
return {
|
|
1959
|
-
mode: "local",
|
|
1960
|
-
configPath: localConfigPath,
|
|
1961
|
-
agentsDir: path10.join(projectDir, CLAUDE_DIR, "agents"),
|
|
1962
|
-
skillsDir: path10.join(projectDir, CLAUDE_DIR, "skills"),
|
|
1963
|
-
projectDir
|
|
1964
|
-
};
|
|
1965
|
-
}
|
|
1814
|
+
if (!localConfigPath) {
|
|
1815
|
+
return null;
|
|
1966
1816
|
}
|
|
1967
|
-
const
|
|
1968
|
-
const
|
|
1969
|
-
if (
|
|
1817
|
+
const loaded = await loadProjectConfig(projectDir);
|
|
1818
|
+
const mode = loaded?.config?.installMode ?? "local";
|
|
1819
|
+
if (mode === "local") {
|
|
1970
1820
|
return {
|
|
1971
|
-
mode: "
|
|
1972
|
-
configPath:
|
|
1973
|
-
agentsDir: path10.join(
|
|
1974
|
-
skillsDir: path10.join(
|
|
1821
|
+
mode: "local",
|
|
1822
|
+
configPath: localConfigPath,
|
|
1823
|
+
agentsDir: path10.join(projectDir, CLAUDE_DIR, "agents"),
|
|
1824
|
+
skillsDir: path10.join(projectDir, CLAUDE_DIR, "skills"),
|
|
1975
1825
|
projectDir
|
|
1976
1826
|
};
|
|
1977
1827
|
}
|
|
1978
|
-
return
|
|
1828
|
+
return {
|
|
1829
|
+
mode: "plugin",
|
|
1830
|
+
configPath: localConfigPath,
|
|
1831
|
+
agentsDir: path10.join(projectDir, CLAUDE_DIR, "agents"),
|
|
1832
|
+
skillsDir: path10.join(projectDir, CLAUDE_DIR, "plugins"),
|
|
1833
|
+
projectDir
|
|
1834
|
+
};
|
|
1979
1835
|
}
|
|
1980
1836
|
|
|
1981
1837
|
// src/cli/lib/installation/local-installer.ts
|
|
1982
1838
|
init_esm_shims();
|
|
1983
|
-
import
|
|
1839
|
+
import path14 from "path";
|
|
1984
1840
|
import { stringify as stringifyYaml3 } from "yaml";
|
|
1985
1841
|
|
|
1986
1842
|
// src/cli/lib/stacks/index.ts
|
|
@@ -2078,11 +1934,6 @@ function getStackSkillIds(stack) {
|
|
|
2078
1934
|
);
|
|
2079
1935
|
}
|
|
2080
1936
|
|
|
2081
|
-
// src/cli/lib/stacks/stack-installer.ts
|
|
2082
|
-
init_esm_shims();
|
|
2083
|
-
import os from "os";
|
|
2084
|
-
import path14 from "path";
|
|
2085
|
-
|
|
2086
1937
|
// src/cli/lib/stacks/stack-plugin-compiler.ts
|
|
2087
1938
|
init_esm_shims();
|
|
2088
1939
|
import path13 from "path";
|
|
@@ -2528,265 +2379,18 @@ Stack plugin compiled: ${result.stackName}`);
|
|
|
2528
2379
|
}
|
|
2529
2380
|
}
|
|
2530
2381
|
|
|
2531
|
-
// src/cli/utils/exec.ts
|
|
2532
|
-
init_esm_shims();
|
|
2533
|
-
import { spawn } from "child_process";
|
|
2534
|
-
var MAX_PLUGIN_PATH_LENGTH = 1024;
|
|
2535
|
-
var MAX_GITHUB_REPO_LENGTH = 256;
|
|
2536
|
-
var MAX_MARKETPLACE_NAME_LENGTH = 128;
|
|
2537
|
-
var MAX_PLUGIN_NAME_LENGTH = 256;
|
|
2538
|
-
var GITHUB_REPO_PATTERN = /^[a-zA-Z0-9._-]+\/[a-zA-Z0-9._-]+$/;
|
|
2539
|
-
var SAFE_NAME_PATTERN = /^[a-zA-Z0-9._@/-]+$/;
|
|
2540
|
-
var SAFE_PLUGIN_PATH_PATTERN = /^[a-zA-Z0-9._@/:~-]+$/;
|
|
2541
|
-
var CONTROL_CHAR_PATTERN = /[\x00-\x08\x0E-\x1F\x7F]/u;
|
|
2542
|
-
function validatePluginPath(pluginPath) {
|
|
2543
|
-
if (!pluginPath || pluginPath.trim().length === 0) {
|
|
2544
|
-
throw new Error("Plugin path must not be empty.");
|
|
2545
|
-
}
|
|
2546
|
-
if (pluginPath.length > MAX_PLUGIN_PATH_LENGTH) {
|
|
2547
|
-
throw new Error(
|
|
2548
|
-
`Plugin path is too long (${pluginPath.length} characters, max ${MAX_PLUGIN_PATH_LENGTH}).`
|
|
2549
|
-
);
|
|
2550
|
-
}
|
|
2551
|
-
if (CONTROL_CHAR_PATTERN.test(pluginPath)) {
|
|
2552
|
-
throw new Error("Plugin path contains invalid control characters.");
|
|
2553
|
-
}
|
|
2554
|
-
if (!SAFE_PLUGIN_PATH_PATTERN.test(pluginPath)) {
|
|
2555
|
-
throw new Error(
|
|
2556
|
-
`Plugin path contains invalid characters: "${pluginPath}"
|
|
2557
|
-
Plugin paths may only contain alphanumeric characters, dashes, underscores, dots, slashes, @, and colons.`
|
|
2558
|
-
);
|
|
2559
|
-
}
|
|
2560
|
-
}
|
|
2561
|
-
function validateGithubRepo(githubRepo) {
|
|
2562
|
-
if (!githubRepo || githubRepo.trim().length === 0) {
|
|
2563
|
-
throw new Error("GitHub repository must not be empty.");
|
|
2564
|
-
}
|
|
2565
|
-
if (githubRepo.length > MAX_GITHUB_REPO_LENGTH) {
|
|
2566
|
-
throw new Error(
|
|
2567
|
-
`GitHub repository is too long (${githubRepo.length} characters, max ${MAX_GITHUB_REPO_LENGTH}).`
|
|
2568
|
-
);
|
|
2569
|
-
}
|
|
2570
|
-
if (CONTROL_CHAR_PATTERN.test(githubRepo)) {
|
|
2571
|
-
throw new Error("GitHub repository contains invalid control characters.");
|
|
2572
|
-
}
|
|
2573
|
-
if (!GITHUB_REPO_PATTERN.test(githubRepo)) {
|
|
2574
|
-
throw new Error(
|
|
2575
|
-
`Invalid GitHub repository format: "${githubRepo}"
|
|
2576
|
-
Expected format: owner/repo (e.g., 'my-org/my-skills').`
|
|
2577
|
-
);
|
|
2578
|
-
}
|
|
2579
|
-
}
|
|
2580
|
-
function validateMarketplaceName(name) {
|
|
2581
|
-
if (!name || name.trim().length === 0) {
|
|
2582
|
-
throw new Error("Marketplace name must not be empty.");
|
|
2583
|
-
}
|
|
2584
|
-
if (name.length > MAX_MARKETPLACE_NAME_LENGTH) {
|
|
2585
|
-
throw new Error(
|
|
2586
|
-
`Marketplace name is too long (${name.length} characters, max ${MAX_MARKETPLACE_NAME_LENGTH}).`
|
|
2587
|
-
);
|
|
2588
|
-
}
|
|
2589
|
-
if (CONTROL_CHAR_PATTERN.test(name)) {
|
|
2590
|
-
throw new Error("Marketplace name contains invalid control characters.");
|
|
2591
|
-
}
|
|
2592
|
-
if (!SAFE_NAME_PATTERN.test(name)) {
|
|
2593
|
-
throw new Error(
|
|
2594
|
-
`Marketplace name contains invalid characters: "${name}"
|
|
2595
|
-
Names may only contain alphanumeric characters, dashes, underscores, dots, @, and slashes.`
|
|
2596
|
-
);
|
|
2597
|
-
}
|
|
2598
|
-
}
|
|
2599
|
-
function validatePluginName(pluginName) {
|
|
2600
|
-
if (!pluginName || pluginName.trim().length === 0) {
|
|
2601
|
-
throw new Error("Plugin name must not be empty.");
|
|
2602
|
-
}
|
|
2603
|
-
if (pluginName.length > MAX_PLUGIN_NAME_LENGTH) {
|
|
2604
|
-
throw new Error(
|
|
2605
|
-
`Plugin name is too long (${pluginName.length} characters, max ${MAX_PLUGIN_NAME_LENGTH}).`
|
|
2606
|
-
);
|
|
2607
|
-
}
|
|
2608
|
-
if (CONTROL_CHAR_PATTERN.test(pluginName)) {
|
|
2609
|
-
throw new Error("Plugin name contains invalid control characters.");
|
|
2610
|
-
}
|
|
2611
|
-
if (!SAFE_NAME_PATTERN.test(pluginName)) {
|
|
2612
|
-
throw new Error(
|
|
2613
|
-
`Plugin name contains invalid characters: "${pluginName}"
|
|
2614
|
-
Names may only contain alphanumeric characters, dashes, underscores, dots, @, and slashes.`
|
|
2615
|
-
);
|
|
2616
|
-
}
|
|
2617
|
-
}
|
|
2618
|
-
async function execCommand(command, args, options) {
|
|
2619
|
-
return new Promise((resolve, reject) => {
|
|
2620
|
-
const proc = spawn(command, args, {
|
|
2621
|
-
cwd: options?.cwd,
|
|
2622
|
-
env: { ...process.env, ...options?.env },
|
|
2623
|
-
stdio: ["ignore", "pipe", "pipe"]
|
|
2624
|
-
});
|
|
2625
|
-
let stdout = "";
|
|
2626
|
-
let stderr = "";
|
|
2627
|
-
proc.stdout.on("data", (data) => {
|
|
2628
|
-
stdout += data.toString();
|
|
2629
|
-
});
|
|
2630
|
-
proc.stderr.on("data", (data) => {
|
|
2631
|
-
stderr += data.toString();
|
|
2632
|
-
});
|
|
2633
|
-
proc.on("close", (code) => {
|
|
2634
|
-
resolve({
|
|
2635
|
-
stdout,
|
|
2636
|
-
stderr,
|
|
2637
|
-
exitCode: code ?? 1
|
|
2638
|
-
});
|
|
2639
|
-
});
|
|
2640
|
-
proc.on("error", (err) => {
|
|
2641
|
-
reject(err);
|
|
2642
|
-
});
|
|
2643
|
-
});
|
|
2644
|
-
}
|
|
2645
|
-
async function claudePluginInstall(pluginPath, scope, projectDir) {
|
|
2646
|
-
validatePluginPath(pluginPath);
|
|
2647
|
-
const args = ["plugin", "install", pluginPath, "--scope", scope];
|
|
2648
|
-
const result = await execCommand("claude", args, { cwd: projectDir });
|
|
2649
|
-
if (result.exitCode !== 0) {
|
|
2650
|
-
const errorMessage = result.stderr || result.stdout || "Unknown error";
|
|
2651
|
-
throw new Error(`Plugin installation failed: ${errorMessage.trim()}`);
|
|
2652
|
-
}
|
|
2653
|
-
}
|
|
2654
|
-
async function isClaudeCLIAvailable() {
|
|
2655
|
-
try {
|
|
2656
|
-
const result = await execCommand("claude", ["--version"], {});
|
|
2657
|
-
return result.exitCode === 0;
|
|
2658
|
-
} catch {
|
|
2659
|
-
return false;
|
|
2660
|
-
}
|
|
2661
|
-
}
|
|
2662
|
-
async function claudePluginMarketplaceList() {
|
|
2663
|
-
try {
|
|
2664
|
-
const result = await execCommand("claude", ["plugin", "marketplace", "list", "--json"], {});
|
|
2665
|
-
if (result.exitCode !== 0) {
|
|
2666
|
-
return [];
|
|
2667
|
-
}
|
|
2668
|
-
let parsed;
|
|
2669
|
-
try {
|
|
2670
|
-
parsed = JSON.parse(result.stdout);
|
|
2671
|
-
} catch {
|
|
2672
|
-
warn("Failed to parse marketplace list output as JSON");
|
|
2673
|
-
return [];
|
|
2674
|
-
}
|
|
2675
|
-
if (!Array.isArray(parsed)) {
|
|
2676
|
-
warn("Unexpected marketplace list format \u2014 expected an array");
|
|
2677
|
-
return [];
|
|
2678
|
-
}
|
|
2679
|
-
return parsed;
|
|
2680
|
-
} catch {
|
|
2681
|
-
return [];
|
|
2682
|
-
}
|
|
2683
|
-
}
|
|
2684
|
-
async function claudePluginMarketplaceExists(name) {
|
|
2685
|
-
const marketplaces = await claudePluginMarketplaceList();
|
|
2686
|
-
return marketplaces.some((m) => m.name === name);
|
|
2687
|
-
}
|
|
2688
|
-
async function claudePluginMarketplaceAdd(githubRepo, name) {
|
|
2689
|
-
validateGithubRepo(githubRepo);
|
|
2690
|
-
validateMarketplaceName(name);
|
|
2691
|
-
const args = ["plugin", "marketplace", "add", githubRepo, "--name", name];
|
|
2692
|
-
let result;
|
|
2693
|
-
try {
|
|
2694
|
-
result = await execCommand("claude", args, {});
|
|
2695
|
-
} catch (err) {
|
|
2696
|
-
throw new Error(`Failed to add marketplace: ${getErrorMessage(err)}`);
|
|
2697
|
-
}
|
|
2698
|
-
if (result.exitCode !== 0) {
|
|
2699
|
-
const errorMessage = result.stderr || result.stdout || "Unknown error";
|
|
2700
|
-
if (errorMessage.includes("already installed")) {
|
|
2701
|
-
return;
|
|
2702
|
-
}
|
|
2703
|
-
throw new Error(`Failed to add marketplace: ${errorMessage.trim()}`);
|
|
2704
|
-
}
|
|
2705
|
-
}
|
|
2706
|
-
async function claudePluginUninstall(pluginName, scope, projectDir) {
|
|
2707
|
-
validatePluginName(pluginName);
|
|
2708
|
-
const args = ["plugin", "uninstall", pluginName, "--scope", scope];
|
|
2709
|
-
const result = await execCommand("claude", args, { cwd: projectDir });
|
|
2710
|
-
if (result.exitCode !== 0) {
|
|
2711
|
-
const errorMessage = result.stderr || result.stdout || "Unknown error";
|
|
2712
|
-
if (errorMessage.includes("not installed") || errorMessage.includes("not found")) {
|
|
2713
|
-
return;
|
|
2714
|
-
}
|
|
2715
|
-
throw new Error(`Plugin uninstall failed: ${errorMessage.trim()}`);
|
|
2716
|
-
}
|
|
2717
|
-
}
|
|
2718
|
-
|
|
2719
|
-
// src/cli/lib/stacks/stack-installer.ts
|
|
2720
|
-
async function compileStackToTemp(options) {
|
|
2721
|
-
const tempDir = path14.join(os.tmpdir(), `cc-stack-${Date.now()}`);
|
|
2722
|
-
await ensureDir(tempDir);
|
|
2723
|
-
const result = await compileStackPlugin({
|
|
2724
|
-
stackId: options.stackId,
|
|
2725
|
-
outputDir: tempDir,
|
|
2726
|
-
projectRoot: options.projectRoot,
|
|
2727
|
-
agentSourcePath: options.agentSourcePath
|
|
2728
|
-
});
|
|
2729
|
-
return {
|
|
2730
|
-
result,
|
|
2731
|
-
cleanup: async () => {
|
|
2732
|
-
await remove(tempDir);
|
|
2733
|
-
}
|
|
2734
|
-
};
|
|
2735
|
-
}
|
|
2736
|
-
async function installStackAsPlugin(options) {
|
|
2737
|
-
const { stackId, projectDir, sourcePath, agentSourcePath, marketplace } = options;
|
|
2738
|
-
const claudeAvailable = await isClaudeCLIAvailable();
|
|
2739
|
-
if (!claudeAvailable) {
|
|
2740
|
-
throw new Error(
|
|
2741
|
-
"Claude CLI not found. Please install Claude Code first: https://claude.ai/code"
|
|
2742
|
-
);
|
|
2743
|
-
}
|
|
2744
|
-
if (marketplace) {
|
|
2745
|
-
verbose(`Installing from marketplace: ${stackId}@${marketplace}`);
|
|
2746
|
-
const pluginRef = `${stackId}@${marketplace}`;
|
|
2747
|
-
await claudePluginInstall(pluginRef, "project", projectDir);
|
|
2748
|
-
return {
|
|
2749
|
-
pluginName: stackId,
|
|
2750
|
-
stackName: stackId,
|
|
2751
|
-
agents: [],
|
|
2752
|
-
skills: [],
|
|
2753
|
-
pluginPath: pluginRef,
|
|
2754
|
-
fromMarketplace: true
|
|
2755
|
-
};
|
|
2756
|
-
}
|
|
2757
|
-
verbose(`Compiling stack locally: ${stackId}`);
|
|
2758
|
-
const { result, cleanup } = await compileStackToTemp({
|
|
2759
|
-
stackId,
|
|
2760
|
-
projectRoot: sourcePath,
|
|
2761
|
-
agentSourcePath
|
|
2762
|
-
});
|
|
2763
|
-
try {
|
|
2764
|
-
await claudePluginInstall(result.pluginPath, "project", projectDir);
|
|
2765
|
-
return {
|
|
2766
|
-
pluginName: `stack-${stackId}`,
|
|
2767
|
-
stackName: result.stackName,
|
|
2768
|
-
agents: result.agents,
|
|
2769
|
-
skills: result.skillPlugins,
|
|
2770
|
-
pluginPath: result.pluginPath,
|
|
2771
|
-
fromMarketplace: false
|
|
2772
|
-
};
|
|
2773
|
-
} finally {
|
|
2774
|
-
await cleanup();
|
|
2775
|
-
}
|
|
2776
|
-
}
|
|
2777
|
-
|
|
2778
2382
|
// src/cli/lib/installation/local-installer.ts
|
|
2779
2383
|
function resolveInstallPaths(projectDir) {
|
|
2780
2384
|
return {
|
|
2781
|
-
skillsDir:
|
|
2782
|
-
agentsDir:
|
|
2783
|
-
configPath:
|
|
2385
|
+
skillsDir: path14.join(projectDir, LOCAL_SKILLS_PATH),
|
|
2386
|
+
agentsDir: path14.join(projectDir, CLAUDE_DIR, "agents"),
|
|
2387
|
+
configPath: path14.join(projectDir, CLAUDE_SRC_DIR, STANDARD_FILES.CONFIG_YAML)
|
|
2784
2388
|
};
|
|
2785
2389
|
}
|
|
2786
2390
|
async function prepareDirectories(paths) {
|
|
2787
2391
|
await ensureDir(paths.skillsDir);
|
|
2788
2392
|
await ensureDir(paths.agentsDir);
|
|
2789
|
-
await ensureDir(
|
|
2393
|
+
await ensureDir(path14.dirname(paths.configPath));
|
|
2790
2394
|
}
|
|
2791
2395
|
async function archiveAndCopySkills(wizardResult, sourceResult, projectDir, skillsDir) {
|
|
2792
2396
|
for (const skillId of wizardResult.selectedSkills) {
|
|
@@ -2915,11 +2519,49 @@ async function compileAndWriteAgents(compileConfig, agents, localSkills, sourceR
|
|
|
2915
2519
|
engine,
|
|
2916
2520
|
installMode
|
|
2917
2521
|
);
|
|
2918
|
-
await writeFile(
|
|
2522
|
+
await writeFile(path14.join(agentsDir, `${name}.md`), output);
|
|
2919
2523
|
compiledAgentNames.push(name);
|
|
2920
2524
|
}
|
|
2921
2525
|
return compiledAgentNames;
|
|
2922
2526
|
}
|
|
2527
|
+
async function installPluginConfig(options) {
|
|
2528
|
+
const { wizardResult, sourceResult, projectDir, sourceFlag } = options;
|
|
2529
|
+
const paths = resolveInstallPaths(projectDir);
|
|
2530
|
+
await ensureDir(paths.agentsDir);
|
|
2531
|
+
await ensureDir(path14.dirname(paths.configPath));
|
|
2532
|
+
const agents = await loadMergedAgents(sourceResult.sourcePath);
|
|
2533
|
+
const mergeResult = await buildAndMergeConfig(wizardResult, sourceResult, projectDir, sourceFlag);
|
|
2534
|
+
const finalConfig = mergeResult.config;
|
|
2535
|
+
await writeConfigFile(finalConfig, paths.configPath);
|
|
2536
|
+
const compileAgentsConfig = buildCompileAgents(finalConfig, agents);
|
|
2537
|
+
const compileConfig = {
|
|
2538
|
+
name: DEFAULT_PLUGIN_NAME,
|
|
2539
|
+
description: finalConfig.description || `Plugin setup with ${wizardResult.selectedSkills.length} skills`,
|
|
2540
|
+
agents: compileAgentsConfig
|
|
2541
|
+
};
|
|
2542
|
+
const stackSkillIds = finalConfig.stack ? getStackSkillIds(finalConfig.stack) : [];
|
|
2543
|
+
const skillsForCompilation = await loadSkillsByIds(
|
|
2544
|
+
stackSkillIds.map((id) => ({ id })),
|
|
2545
|
+
sourceResult.sourcePath
|
|
2546
|
+
);
|
|
2547
|
+
const compiledAgentNames = await compileAndWriteAgents(
|
|
2548
|
+
compileConfig,
|
|
2549
|
+
agents,
|
|
2550
|
+
skillsForCompilation,
|
|
2551
|
+
sourceResult,
|
|
2552
|
+
projectDir,
|
|
2553
|
+
paths.agentsDir,
|
|
2554
|
+
wizardResult.installMode
|
|
2555
|
+
);
|
|
2556
|
+
return {
|
|
2557
|
+
config: finalConfig,
|
|
2558
|
+
configPath: paths.configPath,
|
|
2559
|
+
compiledAgents: compiledAgentNames,
|
|
2560
|
+
wasMerged: mergeResult.merged,
|
|
2561
|
+
mergedConfigPath: mergeResult.existingConfigPath,
|
|
2562
|
+
agentsDir: paths.agentsDir
|
|
2563
|
+
};
|
|
2564
|
+
}
|
|
2923
2565
|
async function installLocal(options) {
|
|
2924
2566
|
const { wizardResult, sourceResult, projectDir, sourceFlag } = options;
|
|
2925
2567
|
const paths = resolveInstallPaths(projectDir);
|
|
@@ -2962,6 +2604,174 @@ async function installLocal(options) {
|
|
|
2962
2604
|
};
|
|
2963
2605
|
}
|
|
2964
2606
|
|
|
2607
|
+
// src/cli/lib/plugins/plugin-discovery.ts
|
|
2608
|
+
init_esm_shims();
|
|
2609
|
+
|
|
2610
|
+
// src/cli/lib/plugins/plugin-settings.ts
|
|
2611
|
+
init_esm_shims();
|
|
2612
|
+
import path15 from "path";
|
|
2613
|
+
import os from "os";
|
|
2614
|
+
import { z as z2 } from "zod";
|
|
2615
|
+
var pluginSettingsSchema = z2.object({
|
|
2616
|
+
enabledPlugins: z2.record(z2.string(), z2.unknown()).optional()
|
|
2617
|
+
}).passthrough();
|
|
2618
|
+
var pluginInstallationSchema = z2.object({
|
|
2619
|
+
scope: z2.enum(["user", "project", "local"]),
|
|
2620
|
+
projectPath: z2.string().optional(),
|
|
2621
|
+
installPath: z2.string(),
|
|
2622
|
+
version: z2.string(),
|
|
2623
|
+
installedAt: z2.string(),
|
|
2624
|
+
lastUpdated: z2.string().optional(),
|
|
2625
|
+
gitCommitSha: z2.string().optional()
|
|
2626
|
+
});
|
|
2627
|
+
var installedPluginsSchema = z2.object({
|
|
2628
|
+
version: z2.number(),
|
|
2629
|
+
plugins: z2.record(z2.string(), z2.array(pluginInstallationSchema))
|
|
2630
|
+
}).passthrough();
|
|
2631
|
+
var SETTINGS_FILE = "settings.json";
|
|
2632
|
+
var INSTALLED_PLUGINS_FILE = "installed_plugins.json";
|
|
2633
|
+
async function getEnabledPluginKeys(projectDir) {
|
|
2634
|
+
const settingsPath = path15.join(projectDir, CLAUDE_DIR, SETTINGS_FILE);
|
|
2635
|
+
if (!await fileExists(settingsPath)) {
|
|
2636
|
+
verbose(`No settings.json found at '${settingsPath}'`);
|
|
2637
|
+
return [];
|
|
2638
|
+
}
|
|
2639
|
+
try {
|
|
2640
|
+
const content = await readFileSafe(settingsPath, MAX_CONFIG_FILE_SIZE);
|
|
2641
|
+
const raw = JSON.parse(content);
|
|
2642
|
+
const result = pluginSettingsSchema.safeParse(raw);
|
|
2643
|
+
if (!result.success) {
|
|
2644
|
+
verbose(`Invalid settings.json structure: ${getErrorMessage(result.error)}`);
|
|
2645
|
+
return [];
|
|
2646
|
+
}
|
|
2647
|
+
const settings = result.data;
|
|
2648
|
+
if (!settings.enabledPlugins) {
|
|
2649
|
+
verbose(`No enabledPlugins found in '${settingsPath}'`);
|
|
2650
|
+
return [];
|
|
2651
|
+
}
|
|
2652
|
+
const enabledKeys = typedEntries(settings.enabledPlugins).filter(([, enabled]) => enabled === true).map(([key]) => key);
|
|
2653
|
+
verbose(`Found ${enabledKeys.length} enabled plugins in settings.json`);
|
|
2654
|
+
return enabledKeys;
|
|
2655
|
+
} catch (error) {
|
|
2656
|
+
verbose(`Failed to read settings.json: ${getErrorMessage(error)}`);
|
|
2657
|
+
return [];
|
|
2658
|
+
}
|
|
2659
|
+
}
|
|
2660
|
+
async function resolvePluginInstallPaths(pluginKeys, projectDir) {
|
|
2661
|
+
if (pluginKeys.length === 0) {
|
|
2662
|
+
return [];
|
|
2663
|
+
}
|
|
2664
|
+
const registryPath = path15.join(os.homedir(), CLAUDE_DIR, PLUGINS_SUBDIR, INSTALLED_PLUGINS_FILE);
|
|
2665
|
+
if (!await fileExists(registryPath)) {
|
|
2666
|
+
verbose(`Plugin registry not found at '${registryPath}'`);
|
|
2667
|
+
return [];
|
|
2668
|
+
}
|
|
2669
|
+
try {
|
|
2670
|
+
const content = await readFileSafe(registryPath, MAX_CONFIG_FILE_SIZE);
|
|
2671
|
+
const raw = JSON.parse(content);
|
|
2672
|
+
const result = installedPluginsSchema.safeParse(raw);
|
|
2673
|
+
if (!result.success) {
|
|
2674
|
+
verbose(`Invalid plugin registry structure: ${getErrorMessage(result.error)}`);
|
|
2675
|
+
return [];
|
|
2676
|
+
}
|
|
2677
|
+
const registry = result.data;
|
|
2678
|
+
const resolvedPaths = [];
|
|
2679
|
+
for (const pluginKey of pluginKeys) {
|
|
2680
|
+
const installations = registry.plugins[pluginKey];
|
|
2681
|
+
if (!installations || installations.length === 0) {
|
|
2682
|
+
verbose(`Plugin '${pluginKey}' not found in registry`);
|
|
2683
|
+
continue;
|
|
2684
|
+
}
|
|
2685
|
+
const projectInstall = installations.find(
|
|
2686
|
+
(install) => install.scope === "project" && install.projectPath === projectDir
|
|
2687
|
+
);
|
|
2688
|
+
if (projectInstall) {
|
|
2689
|
+
resolvedPaths.push({
|
|
2690
|
+
pluginKey,
|
|
2691
|
+
installPath: projectInstall.installPath
|
|
2692
|
+
});
|
|
2693
|
+
verbose(`Resolved '${pluginKey}' to '${projectInstall.installPath}'`);
|
|
2694
|
+
continue;
|
|
2695
|
+
}
|
|
2696
|
+
const userInstall = installations.find((install) => install.scope === "user");
|
|
2697
|
+
if (userInstall) {
|
|
2698
|
+
resolvedPaths.push({
|
|
2699
|
+
pluginKey,
|
|
2700
|
+
installPath: userInstall.installPath
|
|
2701
|
+
});
|
|
2702
|
+
verbose(`Resolved '${pluginKey}' to '${userInstall.installPath}' (user scope)`);
|
|
2703
|
+
continue;
|
|
2704
|
+
}
|
|
2705
|
+
verbose(`No matching installation found for '${pluginKey}'`);
|
|
2706
|
+
}
|
|
2707
|
+
return resolvedPaths;
|
|
2708
|
+
} catch (error) {
|
|
2709
|
+
verbose(`Failed to read plugin registry: ${getErrorMessage(error)}`);
|
|
2710
|
+
return [];
|
|
2711
|
+
}
|
|
2712
|
+
}
|
|
2713
|
+
async function getVerifiedPluginInstallPaths(projectDir) {
|
|
2714
|
+
const enabledKeys = await getEnabledPluginKeys(projectDir);
|
|
2715
|
+
const resolvedPaths = await resolvePluginInstallPaths(enabledKeys, projectDir);
|
|
2716
|
+
const verified = [];
|
|
2717
|
+
for (const { pluginKey, installPath } of resolvedPaths) {
|
|
2718
|
+
const pluginJsonPath = path15.join(installPath, PLUGIN_MANIFEST_DIR, PLUGIN_MANIFEST_FILE);
|
|
2719
|
+
if (await fileExists(pluginJsonPath)) {
|
|
2720
|
+
verified.push({ pluginKey, installPath });
|
|
2721
|
+
} else {
|
|
2722
|
+
verbose(`Plugin '${pluginKey}' manifest does not exist at: '${pluginJsonPath}'`);
|
|
2723
|
+
}
|
|
2724
|
+
}
|
|
2725
|
+
verbose(`Verified ${verified.length} plugin install paths`);
|
|
2726
|
+
return verified;
|
|
2727
|
+
}
|
|
2728
|
+
|
|
2729
|
+
// src/cli/lib/plugins/plugin-discovery.ts
|
|
2730
|
+
async function discoverAllPluginSkills(projectDir) {
|
|
2731
|
+
const allSkills = {};
|
|
2732
|
+
try {
|
|
2733
|
+
const pluginPaths = await getVerifiedPluginInstallPaths(projectDir);
|
|
2734
|
+
if (pluginPaths.length === 0) {
|
|
2735
|
+
verbose(`No enabled plugins found in settings.json`);
|
|
2736
|
+
return allSkills;
|
|
2737
|
+
}
|
|
2738
|
+
for (const { pluginKey, installPath } of pluginPaths) {
|
|
2739
|
+
verbose(`Discovering skills from plugin: '${pluginKey}'`);
|
|
2740
|
+
try {
|
|
2741
|
+
const pluginSkills = await loadPluginSkills(installPath);
|
|
2742
|
+
for (const [id, skill] of typedEntries(pluginSkills)) {
|
|
2743
|
+
if (skill) {
|
|
2744
|
+
allSkills[id] = skill;
|
|
2745
|
+
}
|
|
2746
|
+
}
|
|
2747
|
+
} catch (error) {
|
|
2748
|
+
verbose(`Failed to load skills from '${pluginKey}': ${getErrorMessage(error)}`);
|
|
2749
|
+
}
|
|
2750
|
+
}
|
|
2751
|
+
} catch (error) {
|
|
2752
|
+
verbose(`Plugin discovery failed: ${getErrorMessage(error)}`);
|
|
2753
|
+
}
|
|
2754
|
+
return allSkills;
|
|
2755
|
+
}
|
|
2756
|
+
async function hasIndividualPlugins(projectDir) {
|
|
2757
|
+
try {
|
|
2758
|
+
const pluginPaths = await getVerifiedPluginInstallPaths(projectDir);
|
|
2759
|
+
return pluginPaths.length > 0;
|
|
2760
|
+
} catch (error) {
|
|
2761
|
+
verbose(`Failed to check for individual plugins: ${getErrorMessage(error)}`);
|
|
2762
|
+
return false;
|
|
2763
|
+
}
|
|
2764
|
+
}
|
|
2765
|
+
async function listPluginNames(projectDir) {
|
|
2766
|
+
try {
|
|
2767
|
+
const pluginPaths = await getVerifiedPluginInstallPaths(projectDir);
|
|
2768
|
+
return pluginPaths.map(({ pluginKey }) => pluginKey);
|
|
2769
|
+
} catch (error) {
|
|
2770
|
+
verbose(`Failed to list plugin names: ${getErrorMessage(error)}`);
|
|
2771
|
+
return [];
|
|
2772
|
+
}
|
|
2773
|
+
}
|
|
2774
|
+
|
|
2965
2775
|
// src/cli/lib/plugins/plugin-info.ts
|
|
2966
2776
|
async function getInstallationInfo() {
|
|
2967
2777
|
const installation = await detectInstallation();
|
|
@@ -2972,7 +2782,13 @@ async function getInstallationInfo() {
|
|
|
2972
2782
|
let agentCount = 0;
|
|
2973
2783
|
let name = DEFAULT_PLUGIN_NAME;
|
|
2974
2784
|
let version = DEFAULT_DISPLAY_VERSION;
|
|
2975
|
-
if (
|
|
2785
|
+
if (installation.mode === "plugin") {
|
|
2786
|
+
try {
|
|
2787
|
+
const pluginSkills = await discoverAllPluginSkills(installation.projectDir);
|
|
2788
|
+
skillCount = Object.keys(pluginSkills).length;
|
|
2789
|
+
} catch {
|
|
2790
|
+
}
|
|
2791
|
+
} else if (await directoryExists(installation.skillsDir)) {
|
|
2976
2792
|
try {
|
|
2977
2793
|
const skills = await readdir(installation.skillsDir, {
|
|
2978
2794
|
withFileTypes: true
|
|
@@ -2990,19 +2806,10 @@ async function getInstallationInfo() {
|
|
|
2990
2806
|
} catch {
|
|
2991
2807
|
}
|
|
2992
2808
|
}
|
|
2993
|
-
|
|
2994
|
-
|
|
2995
|
-
|
|
2996
|
-
|
|
2997
|
-
version = "local";
|
|
2998
|
-
}
|
|
2999
|
-
} else {
|
|
3000
|
-
const pluginDir = getCollectivePluginDir(installation.projectDir);
|
|
3001
|
-
const manifest = await readPluginManifest(pluginDir);
|
|
3002
|
-
if (manifest) {
|
|
3003
|
-
name = manifest.name || DEFAULT_PLUGIN_NAME;
|
|
3004
|
-
version = manifest.version || DEFAULT_DISPLAY_VERSION;
|
|
3005
|
-
}
|
|
2809
|
+
const loaded = await loadProjectConfig(installation.projectDir);
|
|
2810
|
+
if (loaded?.config) {
|
|
2811
|
+
name = loaded.config.name || DEFAULT_PLUGIN_NAME;
|
|
2812
|
+
version = installation.mode === "local" ? "local" : "plugin";
|
|
3006
2813
|
}
|
|
3007
2814
|
return {
|
|
3008
2815
|
mode: installation.mode,
|
|
@@ -3067,24 +2874,24 @@ async function getPluginVersion(pluginDir) {
|
|
|
3067
2874
|
|
|
3068
2875
|
// src/cli/lib/plugins/plugin-validator.ts
|
|
3069
2876
|
init_esm_shims();
|
|
3070
|
-
import { z as
|
|
2877
|
+
import { z as z3 } from "zod";
|
|
3071
2878
|
import path17 from "path";
|
|
3072
2879
|
import fg from "fast-glob";
|
|
3073
|
-
import { countBy
|
|
2880
|
+
import { countBy } from "remeda";
|
|
3074
2881
|
var PLUGIN_DIR = PLUGIN_MANIFEST_DIR;
|
|
3075
2882
|
var PLUGIN_MANIFEST = STANDARD_FILES.PLUGIN_JSON;
|
|
3076
2883
|
var KEBAB_CASE_REGEX = /^[a-z][a-z0-9]*(-[a-z0-9]+)*$/;
|
|
3077
2884
|
var SEMVER_REGEX = /^(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-]+)*))?$/;
|
|
3078
|
-
var pluginManifestValidationSchema =
|
|
3079
|
-
name:
|
|
3080
|
-
version:
|
|
3081
|
-
description:
|
|
2885
|
+
var pluginManifestValidationSchema = z3.object({
|
|
2886
|
+
name: z3.string(),
|
|
2887
|
+
version: z3.string().optional(),
|
|
2888
|
+
description: z3.string().optional(),
|
|
3082
2889
|
author: pluginAuthorSchema.optional(),
|
|
3083
|
-
keywords:
|
|
3084
|
-
commands:
|
|
3085
|
-
agents:
|
|
3086
|
-
skills:
|
|
3087
|
-
hooks:
|
|
2890
|
+
keywords: z3.array(z3.string()).optional(),
|
|
2891
|
+
commands: z3.union([z3.string(), z3.array(z3.string())]).optional(),
|
|
2892
|
+
agents: z3.union([z3.string(), z3.array(z3.string())]).optional(),
|
|
2893
|
+
skills: z3.union([z3.string(), z3.array(z3.string())]).optional(),
|
|
2894
|
+
hooks: z3.union([z3.string(), hooksRecordSchema]).optional()
|
|
3088
2895
|
}).strict();
|
|
3089
2896
|
function formatZodErrors2(error) {
|
|
3090
2897
|
return error.issues.map((issue) => {
|
|
@@ -3370,9 +3177,9 @@ async function validateAllPlugins(pluginsDir) {
|
|
|
3370
3177
|
}
|
|
3371
3178
|
const summary = {
|
|
3372
3179
|
total: results.length,
|
|
3373
|
-
valid:
|
|
3374
|
-
invalid:
|
|
3375
|
-
withWarnings:
|
|
3180
|
+
valid: countBy(results, (r) => String(r.result.valid))["true"] ?? 0,
|
|
3181
|
+
invalid: countBy(results, (r) => String(r.result.valid))["false"] ?? 0,
|
|
3182
|
+
withWarnings: countBy(results, (r) => String(r.result.warnings.length > 0))["true"] ?? 0
|
|
3376
3183
|
};
|
|
3377
3184
|
return {
|
|
3378
3185
|
valid: summary.invalid === 0,
|
|
@@ -3437,40 +3244,37 @@ function tagLocalSkills(matrix) {
|
|
|
3437
3244
|
verbose(`Tagged ${count} local skills with local source`);
|
|
3438
3245
|
}
|
|
3439
3246
|
async function tagPluginSkills(matrix, projectDir) {
|
|
3440
|
-
const
|
|
3441
|
-
if (
|
|
3442
|
-
verbose("No plugin directory found, skipping plugin skill tagging");
|
|
3443
|
-
return;
|
|
3444
|
-
}
|
|
3445
|
-
const pluginSkillsDir = getPluginSkillsDir(pluginDir);
|
|
3446
|
-
if (!await directoryExists(pluginSkillsDir)) {
|
|
3447
|
-
verbose("No plugin skills directory found, skipping plugin skill tagging");
|
|
3247
|
+
const allPluginSkillIds = await collectPluginSkillIds(matrix, projectDir);
|
|
3248
|
+
if (allPluginSkillIds.length === 0) {
|
|
3448
3249
|
return;
|
|
3449
3250
|
}
|
|
3450
|
-
|
|
3451
|
-
const
|
|
3452
|
-
|
|
3453
|
-
|
|
3454
|
-
|
|
3455
|
-
|
|
3456
|
-
|
|
3457
|
-
|
|
3458
|
-
|
|
3459
|
-
|
|
3460
|
-
|
|
3461
|
-
|
|
3462
|
-
|
|
3463
|
-
|
|
3464
|
-
|
|
3465
|
-
|
|
3466
|
-
installMode: "plugin"
|
|
3467
|
-
});
|
|
3468
|
-
}
|
|
3251
|
+
for (const skillId of allPluginSkillIds) {
|
|
3252
|
+
const skill = matrix.skills[skillId];
|
|
3253
|
+
if (!skill) continue;
|
|
3254
|
+
skill.availableSources = skill.availableSources ?? [];
|
|
3255
|
+
const existingSource = skill.availableSources.find((s) => s.type === "public");
|
|
3256
|
+
if (existingSource && !existingSource.installMode) {
|
|
3257
|
+
existingSource.installed = true;
|
|
3258
|
+
existingSource.installMode = "plugin";
|
|
3259
|
+
} else if (!skill.availableSources.some((s) => s.installMode === "plugin")) {
|
|
3260
|
+
skill.availableSources.push({
|
|
3261
|
+
name: PUBLIC_SOURCE_NAME,
|
|
3262
|
+
type: "public",
|
|
3263
|
+
version: skill.version,
|
|
3264
|
+
installed: true,
|
|
3265
|
+
installMode: "plugin"
|
|
3266
|
+
});
|
|
3469
3267
|
}
|
|
3470
|
-
verbose(`Tagged ${pluginSkillIds.length} plugin-installed skills`);
|
|
3471
|
-
} catch (error) {
|
|
3472
|
-
verbose(`Failed to detect plugin skills: ${error}`);
|
|
3473
3268
|
}
|
|
3269
|
+
verbose(`Tagged ${allPluginSkillIds.length} plugin-installed skills`);
|
|
3270
|
+
}
|
|
3271
|
+
async function collectPluginSkillIds(_matrix, projectDir) {
|
|
3272
|
+
const pluginSkills = await discoverAllPluginSkills(projectDir);
|
|
3273
|
+
const skillIds = Object.keys(pluginSkills);
|
|
3274
|
+
if (skillIds.length === 0) {
|
|
3275
|
+
verbose("No plugin skills discovered from settings.json");
|
|
3276
|
+
}
|
|
3277
|
+
return skillIds;
|
|
3474
3278
|
}
|
|
3475
3279
|
async function tagExtraSources(matrix, projectDir) {
|
|
3476
3280
|
let allSources;
|
|
@@ -3598,12 +3402,22 @@ async function loadFromRemote(source, sourceConfig, forceRefresh) {
|
|
|
3598
3402
|
const fetchResult = await fetchFromSource(source, { forceRefresh });
|
|
3599
3403
|
verbose(`Fetched to: ${fetchResult.path}`);
|
|
3600
3404
|
const mergedMatrix = await loadAndMergeFromBasePath(fetchResult.path);
|
|
3405
|
+
let marketplace = sourceConfig.marketplace;
|
|
3406
|
+
if (!marketplace) {
|
|
3407
|
+
try {
|
|
3408
|
+
const marketplaceResult = await fetchMarketplace(source, { forceRefresh });
|
|
3409
|
+
marketplace = marketplaceResult.marketplace.name;
|
|
3410
|
+
verbose(`Using marketplace name from marketplace.json: ${marketplace}`);
|
|
3411
|
+
} catch {
|
|
3412
|
+
warn(`Source does not have a marketplace.json - falling back to local mode`);
|
|
3413
|
+
}
|
|
3414
|
+
}
|
|
3601
3415
|
return {
|
|
3602
3416
|
matrix: mergedMatrix,
|
|
3603
3417
|
sourceConfig,
|
|
3604
3418
|
sourcePath: fetchResult.path,
|
|
3605
3419
|
isLocal: false,
|
|
3606
|
-
marketplace
|
|
3420
|
+
marketplace
|
|
3607
3421
|
};
|
|
3608
3422
|
}
|
|
3609
3423
|
async function loadAndMergeFromBasePath(basePath) {
|
|
@@ -4385,7 +4199,7 @@ async function saveSourceToProjectConfig(projectDir, source) {
|
|
|
4385
4199
|
}
|
|
4386
4200
|
|
|
4387
4201
|
// src/cli/lib/loading/source-fetcher.ts
|
|
4388
|
-
var
|
|
4202
|
+
var SAFE_NAME_PATTERN = /^[a-zA-Z0-9@._/ -]+$/;
|
|
4389
4203
|
var MAX_NAME_LENGTH = 200;
|
|
4390
4204
|
function sanitizeSourceForCache(source) {
|
|
4391
4205
|
const hash = createHash2("sha256").update(source).digest("hex").slice(0, CACHE_HASH_LENGTH);
|
|
@@ -4561,7 +4375,7 @@ Too many plugins: ${marketplace.plugins.length} (limit: ${MAX_MARKETPLACE_PLUGIN
|
|
|
4561
4375
|
`Marketplace plugin name too long (${plugin.name.length} chars): '${plugin.name.slice(0, 50)}...'`
|
|
4562
4376
|
);
|
|
4563
4377
|
}
|
|
4564
|
-
if (!
|
|
4378
|
+
if (!SAFE_NAME_PATTERN.test(plugin.name)) {
|
|
4565
4379
|
warn(`Marketplace plugin name contains unsafe characters: '${plugin.name.slice(0, 50)}'`);
|
|
4566
4380
|
}
|
|
4567
4381
|
}
|
|
@@ -4605,7 +4419,7 @@ async function removeSource(projectDir, name) {
|
|
|
4605
4419
|
await saveProjectConfig(projectDir, config);
|
|
4606
4420
|
verbose(`Removed source "${name}"`);
|
|
4607
4421
|
}
|
|
4608
|
-
async function getSourceSummary(projectDir
|
|
4422
|
+
async function getSourceSummary(projectDir) {
|
|
4609
4423
|
const config = await loadProjectSourceConfig(projectDir) ?? {};
|
|
4610
4424
|
const sources = [
|
|
4611
4425
|
{
|
|
@@ -4629,15 +4443,11 @@ async function getSourceSummary(projectDir, matrix) {
|
|
|
4629
4443
|
verbose("Failed to discover local skills for source summary");
|
|
4630
4444
|
}
|
|
4631
4445
|
let pluginSkillCount = 0;
|
|
4632
|
-
|
|
4633
|
-
|
|
4634
|
-
|
|
4635
|
-
|
|
4636
|
-
|
|
4637
|
-
pluginSkillCount = skillIds.length;
|
|
4638
|
-
} catch {
|
|
4639
|
-
verbose("Failed to count plugin skills for source summary");
|
|
4640
|
-
}
|
|
4446
|
+
try {
|
|
4447
|
+
const discoveredSkills = await discoverAllPluginSkills(projectDir);
|
|
4448
|
+
pluginSkillCount = Object.keys(discoveredSkills).length;
|
|
4449
|
+
} catch {
|
|
4450
|
+
verbose("Failed to discover plugin skills for source summary");
|
|
4641
4451
|
}
|
|
4642
4452
|
return { sources, localSkillCount, pluginSkillCount };
|
|
4643
4453
|
}
|
|
@@ -4648,12 +4458,9 @@ export {
|
|
|
4648
4458
|
findPluginManifest,
|
|
4649
4459
|
typedEntries,
|
|
4650
4460
|
typedKeys,
|
|
4651
|
-
getCollectivePluginDir,
|
|
4652
4461
|
getProjectPluginsDir,
|
|
4653
|
-
getPluginSkillsDir,
|
|
4654
4462
|
getPluginAgentsDir,
|
|
4655
4463
|
getPluginManifestPath,
|
|
4656
|
-
getPluginSkillIds,
|
|
4657
4464
|
DEFAULT_SOURCE,
|
|
4658
4465
|
SOURCE_ENV_VAR,
|
|
4659
4466
|
getProjectConfigPath,
|
|
@@ -4674,12 +4481,10 @@ export {
|
|
|
4674
4481
|
readForkedFromMetadata,
|
|
4675
4482
|
compareLocalSkillsWithSource,
|
|
4676
4483
|
injectForkedFromMetadata,
|
|
4677
|
-
copySkillsToPluginFromSource,
|
|
4678
4484
|
copySkillsToLocalFlattened,
|
|
4679
4485
|
parseFrontmatter,
|
|
4680
4486
|
loadAllAgents,
|
|
4681
4487
|
loadProjectAgents,
|
|
4682
|
-
loadPluginSkills,
|
|
4683
4488
|
resolveAlias,
|
|
4684
4489
|
validateSelection,
|
|
4685
4490
|
getAvailableSkills,
|
|
@@ -4695,12 +4500,6 @@ export {
|
|
|
4695
4500
|
compileAgentForPlugin,
|
|
4696
4501
|
compileStackPlugin,
|
|
4697
4502
|
printStackCompilationSummary,
|
|
4698
|
-
claudePluginInstall,
|
|
4699
|
-
isClaudeCLIAvailable,
|
|
4700
|
-
claudePluginMarketplaceExists,
|
|
4701
|
-
claudePluginMarketplaceAdd,
|
|
4702
|
-
claudePluginUninstall,
|
|
4703
|
-
installStackAsPlugin,
|
|
4704
4503
|
loadSkillsMatrixFromSource,
|
|
4705
4504
|
getMarketplaceLabel,
|
|
4706
4505
|
compileSkillPlugin,
|
|
@@ -4712,10 +4511,14 @@ export {
|
|
|
4712
4511
|
loadProjectConfig,
|
|
4713
4512
|
validateProjectConfig,
|
|
4714
4513
|
saveSourceToProjectConfig,
|
|
4514
|
+
discoverAllPluginSkills,
|
|
4515
|
+
hasIndividualPlugins,
|
|
4516
|
+
listPluginNames,
|
|
4715
4517
|
addSource,
|
|
4716
4518
|
removeSource,
|
|
4717
4519
|
getSourceSummary,
|
|
4718
4520
|
detectInstallation,
|
|
4521
|
+
installPluginConfig,
|
|
4719
4522
|
installLocal,
|
|
4720
4523
|
getInstallationInfo,
|
|
4721
4524
|
formatInstallationDisplay,
|
|
@@ -4725,4 +4528,4 @@ export {
|
|
|
4725
4528
|
validateAllPlugins,
|
|
4726
4529
|
printPluginValidationResult
|
|
4727
4530
|
};
|
|
4728
|
-
//# sourceMappingURL=chunk-
|
|
4531
|
+
//# sourceMappingURL=chunk-QUL7R35E.js.map
|