@claude-collective/cli 0.13.4 → 0.21.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 +183 -0
- package/config/skills-matrix.yaml +180 -113
- package/config/stacks.yaml +6 -6
- package/dist/{chunk-K3NB6DSG.js → chunk-2LSGX6R4.js} +54 -114
- package/dist/chunk-2LSGX6R4.js.map +1 -0
- package/dist/chunk-2OKUEELH.js +32 -0
- package/dist/chunk-2OKUEELH.js.map +1 -0
- package/dist/{chunk-V46GGCCI.js → chunk-374JNMR6.js} +14 -96
- package/dist/chunk-374JNMR6.js.map +1 -0
- package/dist/chunk-3EHUF54X.js +133 -0
- package/dist/chunk-3EHUF54X.js.map +1 -0
- package/dist/{chunk-7Q44DMSP.js → chunk-3XR4PALU.js} +92 -145
- package/dist/chunk-3XR4PALU.js.map +1 -0
- package/dist/{chunk-IAUAQJQ2.js → chunk-5K2ZLUO5.js} +5 -5
- package/dist/{chunk-IAUAQJQ2.js.map → chunk-5K2ZLUO5.js.map} +1 -1
- package/dist/{chunk-ACNBKXXJ.js → chunk-5KXUDHAB.js} +8 -36
- package/dist/chunk-5KXUDHAB.js.map +1 -0
- package/dist/chunk-7SLV7CMF.js +615 -0
- package/dist/chunk-7SLV7CMF.js.map +1 -0
- package/dist/{chunk-CDX4W4DM.js → chunk-A46TPNBJ.js} +61 -32
- package/dist/chunk-A46TPNBJ.js.map +1 -0
- package/dist/{chunk-TKFPKEV3.js → chunk-AL74GBW4.js} +1 -1
- package/dist/chunk-AL74GBW4.js.map +1 -0
- package/dist/chunk-BQX23RBV.js +191 -0
- package/dist/chunk-BQX23RBV.js.map +1 -0
- package/dist/{chunk-IMDW5ZUP.js → chunk-CA4LH4LI.js} +5 -5
- package/dist/chunk-CA4LH4LI.js.map +1 -0
- package/dist/{chunk-D237EVNB.js → chunk-CBLPAMZO.js} +5 -8
- package/dist/chunk-CBLPAMZO.js.map +1 -0
- package/dist/{chunk-B7CCVP6Q.js → chunk-CKPQHGXR.js} +52 -274
- package/dist/chunk-CKPQHGXR.js.map +1 -0
- package/dist/{chunk-SVYPSDWY.js → chunk-CXOFOJCN.js} +6 -10
- package/dist/chunk-CXOFOJCN.js.map +1 -0
- package/dist/{chunk-UQTEPWU7.js → chunk-EHGD7HIE.js} +2 -6
- package/dist/chunk-EHGD7HIE.js.map +1 -0
- package/dist/{chunk-76DWXGQE.js → chunk-FJFEKPXF.js} +1 -1
- package/dist/chunk-FJFEKPXF.js.map +1 -0
- package/dist/{chunk-E3FJH4TF.js → chunk-HEOHU5EZ.js} +2 -13
- package/dist/chunk-HEOHU5EZ.js.map +1 -0
- package/dist/{chunk-JIPWV2FX.js → chunk-HGCBZUH5.js} +6 -27
- package/dist/chunk-HGCBZUH5.js.map +1 -0
- package/dist/{chunk-ED4E6Q2T.js → chunk-HPGFY5ZN.js} +4 -4
- package/dist/chunk-HPGFY5ZN.js.map +1 -0
- package/dist/chunk-INJ2EFRW.js +127 -0
- package/dist/chunk-INJ2EFRW.js.map +1 -0
- package/dist/{chunk-KAAEN2PO.js → chunk-IOBFMF6X.js} +6 -2
- package/dist/{chunk-KAAEN2PO.js.map → chunk-IOBFMF6X.js.map} +1 -1
- package/dist/{chunk-K7EVM5LY.js → chunk-KH3HA7J7.js} +8 -33
- package/dist/chunk-KH3HA7J7.js.map +1 -0
- package/dist/{chunk-4K4ZXQRM.js → chunk-N6JNE326.js} +38 -94
- package/dist/chunk-N6JNE326.js.map +1 -0
- package/dist/chunk-NAGU7TVZ.js +36 -0
- package/dist/chunk-NAGU7TVZ.js.map +1 -0
- package/dist/{chunk-Z7G4B5HJ.js → chunk-OQYYMQJR.js} +68 -142
- package/dist/chunk-OQYYMQJR.js.map +1 -0
- package/dist/{chunk-RFTSZDHV.js → chunk-PLZOUVDD.js} +159 -53
- package/dist/chunk-PLZOUVDD.js.map +1 -0
- package/dist/chunk-Q3J43SF3.js +21 -0
- package/dist/chunk-Q3J43SF3.js.map +1 -0
- package/dist/{chunk-3U3R4NCG.js → chunk-T25OEQFI.js} +6 -2
- package/dist/chunk-T25OEQFI.js.map +1 -0
- package/dist/chunk-UMORK7OK.js +29 -0
- package/dist/chunk-UMORK7OK.js.map +1 -0
- package/dist/{chunk-ZFPSUQOU.js → chunk-VFHWU7JU.js} +12 -121
- package/dist/chunk-VFHWU7JU.js.map +1 -0
- package/dist/{chunk-GDH553MV.js → chunk-VS4GVTZE.js} +3 -3
- package/dist/chunk-VS4GVTZE.js.map +1 -0
- package/dist/chunk-WFEFICFM.js +67 -0
- package/dist/chunk-WFEFICFM.js.map +1 -0
- package/dist/{chunk-P26A2K5N.js → chunk-WG6KIAPK.js} +6 -16
- package/dist/chunk-WG6KIAPK.js.map +1 -0
- package/dist/{chunk-X6QONICW.js → chunk-ZEI3ZUDU.js} +3 -7
- package/dist/chunk-ZEI3ZUDU.js.map +1 -0
- package/dist/chunk-ZNIDWLL5.js +68 -0
- package/dist/chunk-ZNIDWLL5.js.map +1 -0
- package/dist/chunk-ZSVMS677.js +45 -0
- package/dist/chunk-ZSVMS677.js.map +1 -0
- package/dist/cli/defaults/agent-mappings.yaml +13 -13
- package/dist/commands/build/marketplace.js +8 -14
- package/dist/commands/build/marketplace.js.map +1 -1
- package/dist/commands/build/plugins.js +10 -21
- package/dist/commands/build/plugins.js.map +1 -1
- package/dist/commands/build/stack.js +13 -18
- package/dist/commands/build/stack.js.map +1 -1
- package/dist/commands/compile.js +25 -40
- package/dist/commands/compile.js.map +1 -1
- package/dist/commands/config/get.js +7 -7
- package/dist/commands/config/get.js.map +1 -1
- package/dist/commands/config/index.js +6 -6
- package/dist/commands/config/index.js.map +1 -1
- package/dist/commands/config/path.js +5 -7
- package/dist/commands/config/path.js.map +1 -1
- package/dist/commands/config/set-project.js +8 -9
- package/dist/commands/config/set-project.js.map +1 -1
- package/dist/commands/config/show.js +5 -5
- package/dist/commands/config/unset-project.js +8 -9
- package/dist/commands/config/unset-project.js.map +1 -1
- package/dist/commands/diff.js +17 -40
- package/dist/commands/diff.js.map +1 -1
- package/dist/commands/doctor.js +14 -25
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/edit.js +41 -54
- package/dist/commands/edit.js.map +1 -1
- package/dist/commands/eject.js +24 -44
- package/dist/commands/eject.js.map +1 -1
- package/dist/commands/import/skill.js +19 -39
- package/dist/commands/import/skill.js.map +1 -1
- package/dist/commands/info.js +10 -15
- package/dist/commands/info.js.map +1 -1
- package/dist/commands/init.js +452 -451
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/list.js +85 -9
- package/dist/commands/list.js.map +1 -1
- package/dist/commands/new/agent.js +9 -10
- package/dist/commands/new/agent.js.map +1 -1
- package/dist/commands/new/skill.js +12 -16
- package/dist/commands/new/skill.js.map +1 -1
- package/dist/commands/outdated.js +12 -89
- package/dist/commands/outdated.js.map +1 -1
- package/dist/commands/search.js +12 -18
- package/dist/commands/search.js.map +1 -1
- package/dist/commands/uninstall.js +12 -21
- package/dist/commands/uninstall.js.map +1 -1
- package/dist/commands/update.js +26 -146
- package/dist/commands/update.js.map +1 -1
- package/dist/commands/validate.js +407 -15
- package/dist/commands/validate.js.map +1 -1
- package/dist/commands/version/bump.js +7 -23
- package/dist/commands/version/bump.js.map +1 -1
- package/dist/commands/version/index.js +6 -21
- package/dist/commands/version/index.js.map +1 -1
- package/dist/commands/version/set.js +6 -23
- package/dist/commands/version/set.js.map +1 -1
- package/dist/commands/version/show.js +6 -21
- package/dist/commands/version/show.js.map +1 -1
- package/dist/components/common/message.js +2 -6
- package/dist/components/common/message.js.map +1 -1
- package/dist/components/common/spinner.js.map +1 -1
- package/dist/components/skill-search/skill-search.js +1 -1
- package/dist/components/wizard/category-grid.js +1 -1
- package/dist/components/wizard/category-grid.test.js +20 -92
- package/dist/components/wizard/category-grid.test.js.map +1 -1
- package/dist/components/wizard/menu-item.js +9 -0
- package/dist/components/wizard/section-progress.js +1 -1
- package/dist/components/wizard/section-progress.test.js +13 -103
- package/dist/components/wizard/section-progress.test.js.map +1 -1
- package/dist/components/wizard/step-approach.js +5 -4
- package/dist/components/wizard/step-build.js +3 -4
- package/dist/components/wizard/step-build.test.js +81 -186
- package/dist/components/wizard/step-build.test.js.map +1 -1
- package/dist/components/wizard/step-confirm.js +1 -2
- package/dist/components/wizard/step-refine.js +1 -2
- package/dist/components/wizard/step-refine.test.js +6 -14
- package/dist/components/wizard/step-refine.test.js.map +1 -1
- package/dist/components/wizard/step-stack.js +5 -3
- package/dist/components/wizard/view-title.js +9 -0
- package/dist/components/wizard/wizard-layout.js +16 -0
- package/dist/components/wizard/wizard-layout.js.map +1 -0
- package/dist/components/wizard/wizard-tabs.js +1 -1
- package/dist/components/wizard/wizard.js +12 -13
- package/dist/config/skills-matrix.yaml +180 -113
- package/dist/config/stacks.yaml +6 -6
- package/dist/hooks/init.js +5 -7
- package/dist/hooks/init.js.map +1 -1
- package/dist/src/agents/developer/web-developer/examples.md +1 -6
- package/dist/src/agents/meta/documentor/workflow.md +1 -5
- package/dist/src/agents/migration/cli-migrator/anti-patterns.md +1 -3
- package/dist/src/agents/tester/web-tester/output-format.md +1 -3
- package/dist/stores/wizard-store.js +2 -2
- package/dist/stores/wizard-store.test.js +60 -23
- package/dist/stores/wizard-store.test.js.map +1 -1
- package/package.json +1 -1
- package/src/agents/developer/web-developer/examples.md +1 -6
- package/src/agents/meta/documentor/workflow.md +1 -5
- package/src/agents/migration/cli-migrator/anti-patterns.md +1 -3
- package/src/agents/tester/web-tester/output-format.md +1 -3
- package/dist/chunk-3U3R4NCG.js.map +0 -1
- package/dist/chunk-4K4ZXQRM.js.map +0 -1
- package/dist/chunk-76DWXGQE.js.map +0 -1
- package/dist/chunk-7Q44DMSP.js.map +0 -1
- package/dist/chunk-ACNBKXXJ.js.map +0 -1
- package/dist/chunk-B7CCVP6Q.js.map +0 -1
- package/dist/chunk-BDLUZVKU.js +0 -54
- package/dist/chunk-BDLUZVKU.js.map +0 -1
- package/dist/chunk-CDX4W4DM.js.map +0 -1
- package/dist/chunk-D237EVNB.js.map +0 -1
- package/dist/chunk-DRXPNNPB.js +0 -393
- package/dist/chunk-DRXPNNPB.js.map +0 -1
- package/dist/chunk-E3FJH4TF.js.map +0 -1
- package/dist/chunk-ED4E6Q2T.js.map +0 -1
- package/dist/chunk-GDH553MV.js.map +0 -1
- package/dist/chunk-HLJX2FTL.js +0 -95
- package/dist/chunk-HLJX2FTL.js.map +0 -1
- package/dist/chunk-I2DSLOXZ.js +0 -75
- package/dist/chunk-I2DSLOXZ.js.map +0 -1
- package/dist/chunk-I4TPKIYX.js +0 -493
- package/dist/chunk-I4TPKIYX.js.map +0 -1
- package/dist/chunk-IBE7JIAG.js +0 -129
- package/dist/chunk-IBE7JIAG.js.map +0 -1
- package/dist/chunk-IMDW5ZUP.js.map +0 -1
- package/dist/chunk-JIPWV2FX.js.map +0 -1
- package/dist/chunk-K3NB6DSG.js.map +0 -1
- package/dist/chunk-K7EVM5LY.js.map +0 -1
- package/dist/chunk-NDY25DTL.js +0 -453
- package/dist/chunk-NDY25DTL.js.map +0 -1
- package/dist/chunk-P26A2K5N.js.map +0 -1
- package/dist/chunk-RFTSZDHV.js.map +0 -1
- package/dist/chunk-SVYPSDWY.js.map +0 -1
- package/dist/chunk-TKFPKEV3.js.map +0 -1
- package/dist/chunk-UQTEPWU7.js.map +0 -1
- package/dist/chunk-V46GGCCI.js.map +0 -1
- package/dist/chunk-X6QONICW.js.map +0 -1
- package/dist/chunk-Y2LW7R3Y.js +0 -23
- package/dist/chunk-Y2LW7R3Y.js.map +0 -1
- package/dist/chunk-Z7G4B5HJ.js.map +0 -1
- package/dist/chunk-ZENYS6KW.js +0 -90
- package/dist/chunk-ZENYS6KW.js.map +0 -1
- package/dist/chunk-ZFPSUQOU.js.map +0 -1
- package/dist/commands/config/set.js +0 -61
- package/dist/commands/config/set.js.map +0 -1
- package/dist/commands/config/unset.js +0 -57
- package/dist/commands/config/unset.js.map +0 -1
- package/dist/commands/test-imports.js +0 -92
- package/dist/commands/test-imports.js.map +0 -1
- package/dist/components/wizard/step-stack-options.js +0 -11
- package/dist/components/wizard/wizard-footer.js +0 -9
- /package/dist/components/wizard/{step-stack-options.js.map → menu-item.js.map} +0 -0
- /package/dist/components/wizard/{wizard-footer.js.map → view-title.js.map} +0 -0
package/dist/chunk-NDY25DTL.js
DELETED
|
@@ -1,453 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
directoryExists,
|
|
4
|
-
fileExists,
|
|
5
|
-
listDirectories,
|
|
6
|
-
readFile
|
|
7
|
-
} from "./chunk-TKFPKEV3.js";
|
|
8
|
-
import {
|
|
9
|
-
PROJECT_ROOT
|
|
10
|
-
} from "./chunk-76DWXGQE.js";
|
|
11
|
-
import {
|
|
12
|
-
init_esm_shims
|
|
13
|
-
} from "./chunk-DHET7RCE.js";
|
|
14
|
-
|
|
15
|
-
// src/cli/lib/plugin-validator.ts
|
|
16
|
-
init_esm_shims();
|
|
17
|
-
import Ajv from "ajv";
|
|
18
|
-
import addFormats from "ajv-formats";
|
|
19
|
-
import path from "path";
|
|
20
|
-
import { parse as parseYaml } from "yaml";
|
|
21
|
-
import fg from "fast-glob";
|
|
22
|
-
var PLUGIN_DIR = ".claude-plugin";
|
|
23
|
-
var PLUGIN_MANIFEST = "plugin.json";
|
|
24
|
-
var KEBAB_CASE_REGEX = /^[a-z][a-z0-9]*(-[a-z0-9]+)*$/;
|
|
25
|
-
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-]+)*))?$/;
|
|
26
|
-
var schemaCache = /* @__PURE__ */ new Map();
|
|
27
|
-
var validatorCache = /* @__PURE__ */ new Map();
|
|
28
|
-
var REMOTE_SCHEMAS = {
|
|
29
|
-
"skill-frontmatter.schema.json": "https://raw.githubusercontent.com/claude-collective/skills/main/src/schemas/skill-frontmatter.schema.json"
|
|
30
|
-
};
|
|
31
|
-
async function loadSchema(schemaName) {
|
|
32
|
-
if (schemaCache.has(schemaName)) {
|
|
33
|
-
return schemaCache.get(schemaName);
|
|
34
|
-
}
|
|
35
|
-
const locations = [
|
|
36
|
-
path.join(PROJECT_ROOT, "src", "schemas", schemaName),
|
|
37
|
-
path.join(process.cwd(), "src", "schemas", schemaName)
|
|
38
|
-
];
|
|
39
|
-
for (const schemaPath of locations) {
|
|
40
|
-
if (await fileExists(schemaPath)) {
|
|
41
|
-
const content = await readFile(schemaPath);
|
|
42
|
-
const schema = JSON.parse(content);
|
|
43
|
-
schemaCache.set(schemaName, schema);
|
|
44
|
-
return schema;
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
const remoteUrl = REMOTE_SCHEMAS[schemaName];
|
|
48
|
-
if (remoteUrl) {
|
|
49
|
-
try {
|
|
50
|
-
const response = await fetch(remoteUrl);
|
|
51
|
-
if (response.ok) {
|
|
52
|
-
const schema = await response.json();
|
|
53
|
-
schemaCache.set(schemaName, schema);
|
|
54
|
-
return schema;
|
|
55
|
-
}
|
|
56
|
-
} catch {
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
throw new Error(
|
|
60
|
-
`Schema not found: ${schemaName}. Searched: ${locations.join(", ")}${remoteUrl ? ` and ${remoteUrl}` : ""}`
|
|
61
|
-
);
|
|
62
|
-
}
|
|
63
|
-
async function getValidator(schemaName) {
|
|
64
|
-
if (validatorCache.has(schemaName)) {
|
|
65
|
-
return validatorCache.get(schemaName);
|
|
66
|
-
}
|
|
67
|
-
const ajv = new Ajv({ allErrors: true, strict: false });
|
|
68
|
-
addFormats(ajv);
|
|
69
|
-
const schema = await loadSchema(schemaName);
|
|
70
|
-
const validate = ajv.compile(schema);
|
|
71
|
-
validatorCache.set(schemaName, validate);
|
|
72
|
-
return validate;
|
|
73
|
-
}
|
|
74
|
-
function formatAjvErrors(errors) {
|
|
75
|
-
if (!errors) return [];
|
|
76
|
-
return errors.map((err) => {
|
|
77
|
-
const errorPath = err.instancePath ? err.instancePath.replace(/^\//, "").replace(/\//g, ".") : "";
|
|
78
|
-
const message = err.message || "Unknown error";
|
|
79
|
-
if (err.keyword === "additionalProperties") {
|
|
80
|
-
const prop = err.params.additionalProperty;
|
|
81
|
-
return `Unrecognized key: "${prop}"`;
|
|
82
|
-
}
|
|
83
|
-
if (err.keyword === "enum") {
|
|
84
|
-
const allowed = err.params.allowedValues;
|
|
85
|
-
return errorPath ? `${errorPath}: ${message}. Allowed: ${allowed?.join(", ")}` : `${message}. Allowed: ${allowed?.join(", ")}`;
|
|
86
|
-
}
|
|
87
|
-
if (err.keyword === "pattern") {
|
|
88
|
-
let hint = "";
|
|
89
|
-
if (errorPath === "name") {
|
|
90
|
-
hint = " (must be kebab-case)";
|
|
91
|
-
} else if (errorPath === "version") {
|
|
92
|
-
hint = " (must be semver: x.y.z)";
|
|
93
|
-
}
|
|
94
|
-
return errorPath ? `${errorPath}: ${message}${hint}` : `${message}${hint}`;
|
|
95
|
-
}
|
|
96
|
-
return errorPath ? `${errorPath}: ${message}` : message;
|
|
97
|
-
});
|
|
98
|
-
}
|
|
99
|
-
function extractFrontmatter(content) {
|
|
100
|
-
const frontmatterRegex = /^---\r?\n([\s\S]*?)\r?\n---/;
|
|
101
|
-
const match = content.match(frontmatterRegex);
|
|
102
|
-
if (!match || !match[1]) {
|
|
103
|
-
return null;
|
|
104
|
-
}
|
|
105
|
-
try {
|
|
106
|
-
return parseYaml(match[1]);
|
|
107
|
-
} catch {
|
|
108
|
-
return null;
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
function isKebabCase(str) {
|
|
112
|
-
return KEBAB_CASE_REGEX.test(str);
|
|
113
|
-
}
|
|
114
|
-
function isValidSemver(str) {
|
|
115
|
-
return SEMVER_REGEX.test(str);
|
|
116
|
-
}
|
|
117
|
-
async function validatePluginStructure(pluginPath) {
|
|
118
|
-
const errors = [];
|
|
119
|
-
const warnings = [];
|
|
120
|
-
if (!await directoryExists(pluginPath)) {
|
|
121
|
-
return {
|
|
122
|
-
valid: false,
|
|
123
|
-
errors: [`Plugin directory does not exist: ${pluginPath}`],
|
|
124
|
-
warnings: []
|
|
125
|
-
};
|
|
126
|
-
}
|
|
127
|
-
const pluginDir = path.join(pluginPath, PLUGIN_DIR);
|
|
128
|
-
if (!await directoryExists(pluginDir)) {
|
|
129
|
-
errors.push(`Missing ${PLUGIN_DIR}/ directory`);
|
|
130
|
-
}
|
|
131
|
-
const manifestPath = path.join(pluginDir, PLUGIN_MANIFEST);
|
|
132
|
-
if (!await fileExists(manifestPath)) {
|
|
133
|
-
errors.push(`Missing ${PLUGIN_DIR}/${PLUGIN_MANIFEST}`);
|
|
134
|
-
}
|
|
135
|
-
const readmePath = path.join(pluginPath, "README.md");
|
|
136
|
-
if (!await fileExists(readmePath)) {
|
|
137
|
-
warnings.push("Missing README.md (recommended for documentation)");
|
|
138
|
-
}
|
|
139
|
-
return {
|
|
140
|
-
valid: errors.length === 0,
|
|
141
|
-
errors,
|
|
142
|
-
warnings
|
|
143
|
-
};
|
|
144
|
-
}
|
|
145
|
-
async function validatePluginManifest(manifestPath) {
|
|
146
|
-
const errors = [];
|
|
147
|
-
const warnings = [];
|
|
148
|
-
if (!await fileExists(manifestPath)) {
|
|
149
|
-
return {
|
|
150
|
-
valid: false,
|
|
151
|
-
errors: [`Manifest file not found: ${manifestPath}`],
|
|
152
|
-
warnings: []
|
|
153
|
-
};
|
|
154
|
-
}
|
|
155
|
-
let manifest;
|
|
156
|
-
try {
|
|
157
|
-
const content = await readFile(manifestPath);
|
|
158
|
-
manifest = JSON.parse(content);
|
|
159
|
-
} catch (err) {
|
|
160
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
161
|
-
return {
|
|
162
|
-
valid: false,
|
|
163
|
-
errors: [`Invalid JSON in ${PLUGIN_MANIFEST}: ${message}`],
|
|
164
|
-
warnings: []
|
|
165
|
-
};
|
|
166
|
-
}
|
|
167
|
-
const validate = await getValidator("plugin.schema.json");
|
|
168
|
-
const isValid = validate(manifest);
|
|
169
|
-
if (!isValid) {
|
|
170
|
-
errors.push(...formatAjvErrors(validate.errors));
|
|
171
|
-
}
|
|
172
|
-
if (manifest.name && typeof manifest.name === "string") {
|
|
173
|
-
if (!isKebabCase(manifest.name)) {
|
|
174
|
-
errors.push(`name must be kebab-case: "${manifest.name}"`);
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
if (manifest.version && typeof manifest.version === "string") {
|
|
178
|
-
if (!isValidSemver(manifest.version)) {
|
|
179
|
-
warnings.push(
|
|
180
|
-
`version "${manifest.version}" is not valid semver (expected: major.minor.patch)`
|
|
181
|
-
);
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
if (!manifest.description) {
|
|
185
|
-
warnings.push(
|
|
186
|
-
"Missing description field (recommended for discoverability)"
|
|
187
|
-
);
|
|
188
|
-
}
|
|
189
|
-
const pluginDir = path.dirname(path.dirname(manifestPath));
|
|
190
|
-
if (manifest.skills && typeof manifest.skills === "string") {
|
|
191
|
-
const skillsPath = path.join(pluginDir, manifest.skills);
|
|
192
|
-
if (!await directoryExists(skillsPath)) {
|
|
193
|
-
errors.push(`Skills path does not exist: ${manifest.skills}`);
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
if (manifest.agents && typeof manifest.agents === "string") {
|
|
197
|
-
const agentsPath = path.join(pluginDir, manifest.agents);
|
|
198
|
-
if (!await directoryExists(agentsPath)) {
|
|
199
|
-
errors.push(`Agents path does not exist: ${manifest.agents}`);
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
return {
|
|
203
|
-
valid: errors.length === 0,
|
|
204
|
-
errors,
|
|
205
|
-
warnings
|
|
206
|
-
};
|
|
207
|
-
}
|
|
208
|
-
async function validateSkillFrontmatter(skillPath) {
|
|
209
|
-
const errors = [];
|
|
210
|
-
const warnings = [];
|
|
211
|
-
if (!await fileExists(skillPath)) {
|
|
212
|
-
return {
|
|
213
|
-
valid: false,
|
|
214
|
-
errors: [`Skill file not found: ${skillPath}`],
|
|
215
|
-
warnings: []
|
|
216
|
-
};
|
|
217
|
-
}
|
|
218
|
-
const content = await readFile(skillPath);
|
|
219
|
-
const frontmatter = extractFrontmatter(content);
|
|
220
|
-
if (frontmatter === null) {
|
|
221
|
-
return {
|
|
222
|
-
valid: false,
|
|
223
|
-
errors: ["Missing or invalid YAML frontmatter"],
|
|
224
|
-
warnings: []
|
|
225
|
-
};
|
|
226
|
-
}
|
|
227
|
-
const validate = await getValidator("skill-frontmatter.schema.json");
|
|
228
|
-
const isValid = validate(frontmatter);
|
|
229
|
-
if (!isValid) {
|
|
230
|
-
errors.push(...formatAjvErrors(validate.errors));
|
|
231
|
-
}
|
|
232
|
-
const fm = frontmatter;
|
|
233
|
-
if (fm.category) {
|
|
234
|
-
warnings.push(
|
|
235
|
-
'Deprecated field: "category" - use metadata.yaml for category information'
|
|
236
|
-
);
|
|
237
|
-
}
|
|
238
|
-
if (fm.author) {
|
|
239
|
-
warnings.push(
|
|
240
|
-
'Deprecated field: "author" - use metadata.yaml for author information'
|
|
241
|
-
);
|
|
242
|
-
}
|
|
243
|
-
if (fm.version) {
|
|
244
|
-
warnings.push(
|
|
245
|
-
'Deprecated field: "version" - use metadata.yaml for version information'
|
|
246
|
-
);
|
|
247
|
-
}
|
|
248
|
-
return {
|
|
249
|
-
valid: errors.length === 0,
|
|
250
|
-
errors,
|
|
251
|
-
warnings
|
|
252
|
-
};
|
|
253
|
-
}
|
|
254
|
-
async function validateAgentFrontmatter(agentPath) {
|
|
255
|
-
const errors = [];
|
|
256
|
-
const warnings = [];
|
|
257
|
-
if (!await fileExists(agentPath)) {
|
|
258
|
-
return {
|
|
259
|
-
valid: false,
|
|
260
|
-
errors: [`Agent file not found: ${agentPath}`],
|
|
261
|
-
warnings: []
|
|
262
|
-
};
|
|
263
|
-
}
|
|
264
|
-
const content = await readFile(agentPath);
|
|
265
|
-
const frontmatter = extractFrontmatter(content);
|
|
266
|
-
if (frontmatter === null) {
|
|
267
|
-
return {
|
|
268
|
-
valid: false,
|
|
269
|
-
errors: ["Missing or invalid YAML frontmatter"],
|
|
270
|
-
warnings: []
|
|
271
|
-
};
|
|
272
|
-
}
|
|
273
|
-
const validate = await getValidator("agent-frontmatter.schema.json");
|
|
274
|
-
const isValid = validate(frontmatter);
|
|
275
|
-
if (!isValid) {
|
|
276
|
-
errors.push(...formatAjvErrors(validate.errors));
|
|
277
|
-
}
|
|
278
|
-
const fm = frontmatter;
|
|
279
|
-
if (fm.name && typeof fm.name === "string") {
|
|
280
|
-
if (!isKebabCase(fm.name)) {
|
|
281
|
-
errors.push(`name must be kebab-case: "${fm.name}"`);
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
return {
|
|
285
|
-
valid: errors.length === 0,
|
|
286
|
-
errors,
|
|
287
|
-
warnings
|
|
288
|
-
};
|
|
289
|
-
}
|
|
290
|
-
async function validatePlugin(pluginPath) {
|
|
291
|
-
const errors = [];
|
|
292
|
-
const warnings = [];
|
|
293
|
-
const structureResult = await validatePluginStructure(pluginPath);
|
|
294
|
-
errors.push(...structureResult.errors);
|
|
295
|
-
warnings.push(...structureResult.warnings);
|
|
296
|
-
if (!structureResult.valid) {
|
|
297
|
-
return { valid: false, errors, warnings };
|
|
298
|
-
}
|
|
299
|
-
const manifestPath = path.join(pluginPath, PLUGIN_DIR, PLUGIN_MANIFEST);
|
|
300
|
-
const manifestResult = await validatePluginManifest(manifestPath);
|
|
301
|
-
errors.push(...manifestResult.errors);
|
|
302
|
-
warnings.push(...manifestResult.warnings);
|
|
303
|
-
let manifest = null;
|
|
304
|
-
try {
|
|
305
|
-
const content = await readFile(manifestPath);
|
|
306
|
-
manifest = JSON.parse(content);
|
|
307
|
-
} catch {
|
|
308
|
-
}
|
|
309
|
-
if (manifest) {
|
|
310
|
-
if (manifest.skills && typeof manifest.skills === "string") {
|
|
311
|
-
const skillsDir = path.join(pluginPath, manifest.skills);
|
|
312
|
-
if (await directoryExists(skillsDir)) {
|
|
313
|
-
const skillFiles = await fg("**/SKILL.md", {
|
|
314
|
-
cwd: skillsDir,
|
|
315
|
-
absolute: true
|
|
316
|
-
});
|
|
317
|
-
if (skillFiles.length === 0) {
|
|
318
|
-
warnings.push(
|
|
319
|
-
`Skills directory exists but contains no SKILL.md files: ${manifest.skills}`
|
|
320
|
-
);
|
|
321
|
-
}
|
|
322
|
-
for (const skillFile of skillFiles) {
|
|
323
|
-
const relativePath = path.relative(pluginPath, skillFile);
|
|
324
|
-
const skillResult = await validateSkillFrontmatter(skillFile);
|
|
325
|
-
if (!skillResult.valid) {
|
|
326
|
-
errors.push(
|
|
327
|
-
...skillResult.errors.map((e) => `${relativePath}: ${e}`)
|
|
328
|
-
);
|
|
329
|
-
}
|
|
330
|
-
warnings.push(
|
|
331
|
-
...skillResult.warnings.map((w) => `${relativePath}: ${w}`)
|
|
332
|
-
);
|
|
333
|
-
}
|
|
334
|
-
}
|
|
335
|
-
}
|
|
336
|
-
if (manifest.agents && typeof manifest.agents === "string") {
|
|
337
|
-
const agentsDir = path.join(pluginPath, manifest.agents);
|
|
338
|
-
if (await directoryExists(agentsDir)) {
|
|
339
|
-
const agentFiles = await fg("*.md", {
|
|
340
|
-
cwd: agentsDir,
|
|
341
|
-
absolute: true
|
|
342
|
-
});
|
|
343
|
-
if (agentFiles.length === 0) {
|
|
344
|
-
warnings.push(
|
|
345
|
-
`Agents directory exists but contains no .md files: ${manifest.agents}`
|
|
346
|
-
);
|
|
347
|
-
}
|
|
348
|
-
for (const agentFile of agentFiles) {
|
|
349
|
-
const relativePath = path.relative(pluginPath, agentFile);
|
|
350
|
-
const agentResult = await validateAgentFrontmatter(agentFile);
|
|
351
|
-
if (!agentResult.valid) {
|
|
352
|
-
errors.push(
|
|
353
|
-
...agentResult.errors.map((e) => `${relativePath}: ${e}`)
|
|
354
|
-
);
|
|
355
|
-
}
|
|
356
|
-
warnings.push(
|
|
357
|
-
...agentResult.warnings.map((w) => `${relativePath}: ${w}`)
|
|
358
|
-
);
|
|
359
|
-
}
|
|
360
|
-
}
|
|
361
|
-
}
|
|
362
|
-
}
|
|
363
|
-
return {
|
|
364
|
-
valid: errors.length === 0,
|
|
365
|
-
errors,
|
|
366
|
-
warnings
|
|
367
|
-
};
|
|
368
|
-
}
|
|
369
|
-
async function validateAllPlugins(pluginsDir) {
|
|
370
|
-
const results = [];
|
|
371
|
-
if (!await directoryExists(pluginsDir)) {
|
|
372
|
-
return {
|
|
373
|
-
valid: false,
|
|
374
|
-
results: [
|
|
375
|
-
{
|
|
376
|
-
name: pluginsDir,
|
|
377
|
-
result: {
|
|
378
|
-
valid: false,
|
|
379
|
-
errors: [`Directory does not exist: ${pluginsDir}`],
|
|
380
|
-
warnings: []
|
|
381
|
-
}
|
|
382
|
-
}
|
|
383
|
-
],
|
|
384
|
-
summary: { total: 0, valid: 0, invalid: 1, withWarnings: 0 }
|
|
385
|
-
};
|
|
386
|
-
}
|
|
387
|
-
const allDirs = await listDirectories(pluginsDir);
|
|
388
|
-
const pluginDirs = [];
|
|
389
|
-
for (const dirName of allDirs) {
|
|
390
|
-
const potentialPluginDir = path.join(pluginsDir, dirName, PLUGIN_DIR);
|
|
391
|
-
if (await directoryExists(potentialPluginDir)) {
|
|
392
|
-
pluginDirs.push(dirName);
|
|
393
|
-
}
|
|
394
|
-
}
|
|
395
|
-
if (pluginDirs.length === 0) {
|
|
396
|
-
return {
|
|
397
|
-
valid: false,
|
|
398
|
-
results: [
|
|
399
|
-
{
|
|
400
|
-
name: pluginsDir,
|
|
401
|
-
result: {
|
|
402
|
-
valid: false,
|
|
403
|
-
errors: [
|
|
404
|
-
`No plugins found in directory: ${pluginsDir}. Plugins must contain a ${PLUGIN_DIR}/ directory.`
|
|
405
|
-
],
|
|
406
|
-
warnings: []
|
|
407
|
-
}
|
|
408
|
-
}
|
|
409
|
-
],
|
|
410
|
-
summary: { total: 0, valid: 0, invalid: 1, withWarnings: 0 }
|
|
411
|
-
};
|
|
412
|
-
}
|
|
413
|
-
for (const pluginName of pluginDirs) {
|
|
414
|
-
const pluginPath = path.join(pluginsDir, pluginName);
|
|
415
|
-
const result = await validatePlugin(pluginPath);
|
|
416
|
-
results.push({ name: pluginName, result });
|
|
417
|
-
}
|
|
418
|
-
const summary = {
|
|
419
|
-
total: results.length,
|
|
420
|
-
valid: results.filter((r) => r.result.valid).length,
|
|
421
|
-
invalid: results.filter((r) => !r.result.valid).length,
|
|
422
|
-
withWarnings: results.filter((r) => r.result.warnings.length > 0).length
|
|
423
|
-
};
|
|
424
|
-
return {
|
|
425
|
-
valid: summary.invalid === 0,
|
|
426
|
-
results,
|
|
427
|
-
summary
|
|
428
|
-
};
|
|
429
|
-
}
|
|
430
|
-
function printPluginValidationResult(name, result, verbose = false) {
|
|
431
|
-
const status = result.valid ? "\u2713" : "\u2717";
|
|
432
|
-
if (result.valid && result.warnings.length === 0 && !verbose) {
|
|
433
|
-
return;
|
|
434
|
-
}
|
|
435
|
-
console.log(`
|
|
436
|
-
${status} ${name}`);
|
|
437
|
-
if (result.errors.length > 0) {
|
|
438
|
-
console.log(" Errors:");
|
|
439
|
-
result.errors.forEach((e) => console.log(` - ${e}`));
|
|
440
|
-
}
|
|
441
|
-
if (result.warnings.length > 0) {
|
|
442
|
-
console.log(" Warnings:");
|
|
443
|
-
result.warnings.forEach((w) => console.log(` - ${w}`));
|
|
444
|
-
}
|
|
445
|
-
}
|
|
446
|
-
|
|
447
|
-
export {
|
|
448
|
-
validatePluginManifest,
|
|
449
|
-
validatePlugin,
|
|
450
|
-
validateAllPlugins,
|
|
451
|
-
printPluginValidationResult
|
|
452
|
-
};
|
|
453
|
-
//# sourceMappingURL=chunk-NDY25DTL.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cli/lib/plugin-validator.ts"],"sourcesContent":["import Ajv, { type ValidateFunction, type ErrorObject } from \"ajv\";\nimport addFormats from \"ajv-formats\";\nimport path from \"path\";\nimport { parse as parseYaml } from \"yaml\";\nimport fg from \"fast-glob\";\nimport {\n fileExists,\n readFile,\n directoryExists,\n listDirectories,\n} from \"../utils/fs\";\nimport { PROJECT_ROOT } from \"../consts\";\nimport type { ValidationResult } from \"../../types\";\n\nconst PLUGIN_DIR = \".claude-plugin\";\nconst PLUGIN_MANIFEST = \"plugin.json\";\nconst SKILL_FILE = \"SKILL.md\";\nconst KEBAB_CASE_REGEX = /^[a-z][a-z0-9]*(-[a-z0-9]+)*$/;\nconst SEMVER_REGEX =\n /^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?$/;\n\nconst schemaCache = new Map<string, object>();\nconst validatorCache = new Map<string, ValidateFunction>();\n\n// Remote schemas hosted on GitHub (source of truth for skill schemas)\nconst REMOTE_SCHEMAS: Record<string, string> = {\n \"skill-frontmatter.schema.json\":\n \"https://raw.githubusercontent.com/claude-collective/skills/main/src/schemas/skill-frontmatter.schema.json\",\n};\n\nasync function loadSchema(schemaName: string): Promise<object> {\n if (schemaCache.has(schemaName)) {\n return schemaCache.get(schemaName)!;\n }\n\n // Try local locations first for CLI-owned schemas\n const locations = [\n path.join(PROJECT_ROOT, \"src\", \"schemas\", schemaName),\n path.join(process.cwd(), \"src\", \"schemas\", schemaName),\n ];\n\n for (const schemaPath of locations) {\n if (await fileExists(schemaPath)) {\n const content = await readFile(schemaPath);\n const schema = JSON.parse(content);\n schemaCache.set(schemaName, schema);\n return schema;\n }\n }\n\n // Fall back to remote schema from GitHub (for skill schemas)\n const remoteUrl = REMOTE_SCHEMAS[schemaName];\n if (remoteUrl) {\n try {\n const response = await fetch(remoteUrl);\n if (response.ok) {\n const schema = await response.json();\n schemaCache.set(schemaName, schema);\n return schema;\n }\n } catch {\n // Fall through to error\n }\n }\n\n throw new Error(\n `Schema not found: ${schemaName}. Searched: ${locations.join(\", \")}${remoteUrl ? ` and ${remoteUrl}` : \"\"}`,\n );\n}\n\nasync function getValidator(schemaName: string): Promise<ValidateFunction> {\n if (validatorCache.has(schemaName)) {\n return validatorCache.get(schemaName)!;\n }\n\n const ajv = new Ajv({ allErrors: true, strict: false });\n addFormats(ajv);\n const schema = await loadSchema(schemaName);\n const validate = ajv.compile(schema);\n validatorCache.set(schemaName, validate);\n return validate;\n}\n\nfunction formatAjvErrors(errors: ErrorObject[] | null | undefined): string[] {\n if (!errors) return [];\n\n return errors.map((err) => {\n const errorPath = err.instancePath\n ? err.instancePath.replace(/^\\//, \"\").replace(/\\//g, \".\")\n : \"\";\n const message = err.message || \"Unknown error\";\n\n if (err.keyword === \"additionalProperties\") {\n const prop = (err.params as { additionalProperty?: string })\n .additionalProperty;\n return `Unrecognized key: \"${prop}\"`;\n }\n\n if (err.keyword === \"enum\") {\n const allowed = (err.params as { allowedValues?: string[] })\n .allowedValues;\n return errorPath\n ? `${errorPath}: ${message}. Allowed: ${allowed?.join(\", \")}`\n : `${message}. Allowed: ${allowed?.join(\", \")}`;\n }\n\n if (err.keyword === \"pattern\") {\n let hint = \"\";\n if (errorPath === \"name\") {\n hint = \" (must be kebab-case)\";\n } else if (errorPath === \"version\") {\n hint = \" (must be semver: x.y.z)\";\n }\n return errorPath\n ? `${errorPath}: ${message}${hint}`\n : `${message}${hint}`;\n }\n\n return errorPath ? `${errorPath}: ${message}` : message;\n });\n}\n\nfunction extractFrontmatter(content: string): unknown | null {\n const frontmatterRegex = /^---\\r?\\n([\\s\\S]*?)\\r?\\n---/;\n const match = content.match(frontmatterRegex);\n\n if (!match || !match[1]) {\n return null;\n }\n\n try {\n return parseYaml(match[1]);\n } catch {\n return null;\n }\n}\n\nfunction isKebabCase(str: string): boolean {\n return KEBAB_CASE_REGEX.test(str);\n}\n\nfunction isValidSemver(str: string): boolean {\n return SEMVER_REGEX.test(str);\n}\n\nexport async function validatePluginStructure(\n pluginPath: string,\n): Promise<ValidationResult> {\n const errors: string[] = [];\n const warnings: string[] = [];\n\n if (!(await directoryExists(pluginPath))) {\n return {\n valid: false,\n errors: [`Plugin directory does not exist: ${pluginPath}`],\n warnings: [],\n };\n }\n\n const pluginDir = path.join(pluginPath, PLUGIN_DIR);\n if (!(await directoryExists(pluginDir))) {\n errors.push(`Missing ${PLUGIN_DIR}/ directory`);\n }\n\n const manifestPath = path.join(pluginDir, PLUGIN_MANIFEST);\n if (!(await fileExists(manifestPath))) {\n errors.push(`Missing ${PLUGIN_DIR}/${PLUGIN_MANIFEST}`);\n }\n\n const readmePath = path.join(pluginPath, \"README.md\");\n if (!(await fileExists(readmePath))) {\n warnings.push(\"Missing README.md (recommended for documentation)\");\n }\n\n return {\n valid: errors.length === 0,\n errors,\n warnings,\n };\n}\n\nexport async function validatePluginManifest(\n manifestPath: string,\n): Promise<ValidationResult> {\n const errors: string[] = [];\n const warnings: string[] = [];\n\n if (!(await fileExists(manifestPath))) {\n return {\n valid: false,\n errors: [`Manifest file not found: ${manifestPath}`],\n warnings: [],\n };\n }\n\n let manifest: Record<string, unknown>;\n try {\n const content = await readFile(manifestPath);\n manifest = JSON.parse(content);\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n return {\n valid: false,\n errors: [`Invalid JSON in ${PLUGIN_MANIFEST}: ${message}`],\n warnings: [],\n };\n }\n\n const validate = await getValidator(\"plugin.schema.json\");\n const isValid = validate(manifest);\n\n if (!isValid) {\n errors.push(...formatAjvErrors(validate.errors));\n }\n\n if (manifest.name && typeof manifest.name === \"string\") {\n if (!isKebabCase(manifest.name)) {\n errors.push(`name must be kebab-case: \"${manifest.name}\"`);\n }\n }\n\n if (manifest.version && typeof manifest.version === \"string\") {\n if (!isValidSemver(manifest.version)) {\n warnings.push(\n `version \"${manifest.version}\" is not valid semver (expected: major.minor.patch)`,\n );\n }\n }\n\n if (!manifest.description) {\n warnings.push(\n \"Missing description field (recommended for discoverability)\",\n );\n }\n\n const pluginDir = path.dirname(path.dirname(manifestPath));\n\n if (manifest.skills && typeof manifest.skills === \"string\") {\n const skillsPath = path.join(pluginDir, manifest.skills);\n if (!(await directoryExists(skillsPath))) {\n errors.push(`Skills path does not exist: ${manifest.skills}`);\n }\n }\n\n if (manifest.agents && typeof manifest.agents === \"string\") {\n const agentsPath = path.join(pluginDir, manifest.agents);\n if (!(await directoryExists(agentsPath))) {\n errors.push(`Agents path does not exist: ${manifest.agents}`);\n }\n }\n\n return {\n valid: errors.length === 0,\n errors,\n warnings,\n };\n}\n\nexport async function validateSkillFrontmatter(\n skillPath: string,\n): Promise<ValidationResult> {\n const errors: string[] = [];\n const warnings: string[] = [];\n\n if (!(await fileExists(skillPath))) {\n return {\n valid: false,\n errors: [`Skill file not found: ${skillPath}`],\n warnings: [],\n };\n }\n\n const content = await readFile(skillPath);\n const frontmatter = extractFrontmatter(content);\n\n if (frontmatter === null) {\n return {\n valid: false,\n errors: [\"Missing or invalid YAML frontmatter\"],\n warnings: [],\n };\n }\n\n const validate = await getValidator(\"skill-frontmatter.schema.json\");\n const isValid = validate(frontmatter);\n\n if (!isValid) {\n errors.push(...formatAjvErrors(validate.errors));\n }\n\n const fm = frontmatter as Record<string, unknown>;\n\n if (fm.category) {\n warnings.push(\n 'Deprecated field: \"category\" - use metadata.yaml for category information',\n );\n }\n if (fm.author) {\n warnings.push(\n 'Deprecated field: \"author\" - use metadata.yaml for author information',\n );\n }\n if (fm.version) {\n warnings.push(\n 'Deprecated field: \"version\" - use metadata.yaml for version information',\n );\n }\n\n return {\n valid: errors.length === 0,\n errors,\n warnings,\n };\n}\n\nexport async function validateAgentFrontmatter(\n agentPath: string,\n): Promise<ValidationResult> {\n const errors: string[] = [];\n const warnings: string[] = [];\n\n if (!(await fileExists(agentPath))) {\n return {\n valid: false,\n errors: [`Agent file not found: ${agentPath}`],\n warnings: [],\n };\n }\n\n const content = await readFile(agentPath);\n const frontmatter = extractFrontmatter(content);\n\n if (frontmatter === null) {\n return {\n valid: false,\n errors: [\"Missing or invalid YAML frontmatter\"],\n warnings: [],\n };\n }\n\n const validate = await getValidator(\"agent-frontmatter.schema.json\");\n const isValid = validate(frontmatter);\n\n if (!isValid) {\n errors.push(...formatAjvErrors(validate.errors));\n }\n\n const fm = frontmatter as Record<string, unknown>;\n\n if (fm.name && typeof fm.name === \"string\") {\n if (!isKebabCase(fm.name)) {\n errors.push(`name must be kebab-case: \"${fm.name}\"`);\n }\n }\n\n return {\n valid: errors.length === 0,\n errors,\n warnings,\n };\n}\n\nexport async function validatePlugin(\n pluginPath: string,\n): Promise<ValidationResult> {\n const errors: string[] = [];\n const warnings: string[] = [];\n\n const structureResult = await validatePluginStructure(pluginPath);\n errors.push(...structureResult.errors);\n warnings.push(...structureResult.warnings);\n\n if (!structureResult.valid) {\n return { valid: false, errors, warnings };\n }\n\n const manifestPath = path.join(pluginPath, PLUGIN_DIR, PLUGIN_MANIFEST);\n const manifestResult = await validatePluginManifest(manifestPath);\n errors.push(...manifestResult.errors);\n warnings.push(...manifestResult.warnings);\n\n let manifest: Record<string, unknown> | null = null;\n try {\n const content = await readFile(manifestPath);\n manifest = JSON.parse(content);\n } catch {}\n\n if (manifest) {\n if (manifest.skills && typeof manifest.skills === \"string\") {\n const skillsDir = path.join(pluginPath, manifest.skills);\n if (await directoryExists(skillsDir)) {\n const skillFiles = await fg(\"**/SKILL.md\", {\n cwd: skillsDir,\n absolute: true,\n });\n\n if (skillFiles.length === 0) {\n warnings.push(\n `Skills directory exists but contains no SKILL.md files: ${manifest.skills}`,\n );\n }\n\n for (const skillFile of skillFiles) {\n const relativePath = path.relative(pluginPath, skillFile);\n const skillResult = await validateSkillFrontmatter(skillFile);\n\n if (!skillResult.valid) {\n errors.push(\n ...skillResult.errors.map((e) => `${relativePath}: ${e}`),\n );\n }\n warnings.push(\n ...skillResult.warnings.map((w) => `${relativePath}: ${w}`),\n );\n }\n }\n }\n\n if (manifest.agents && typeof manifest.agents === \"string\") {\n const agentsDir = path.join(pluginPath, manifest.agents);\n if (await directoryExists(agentsDir)) {\n const agentFiles = await fg(\"*.md\", {\n cwd: agentsDir,\n absolute: true,\n });\n\n if (agentFiles.length === 0) {\n warnings.push(\n `Agents directory exists but contains no .md files: ${manifest.agents}`,\n );\n }\n\n for (const agentFile of agentFiles) {\n const relativePath = path.relative(pluginPath, agentFile);\n const agentResult = await validateAgentFrontmatter(agentFile);\n\n if (!agentResult.valid) {\n errors.push(\n ...agentResult.errors.map((e) => `${relativePath}: ${e}`),\n );\n }\n warnings.push(\n ...agentResult.warnings.map((w) => `${relativePath}: ${w}`),\n );\n }\n }\n }\n }\n\n return {\n valid: errors.length === 0,\n errors,\n warnings,\n };\n}\n\nexport async function validateAllPlugins(pluginsDir: string): Promise<{\n valid: boolean;\n results: Array<{ name: string; result: ValidationResult }>;\n summary: {\n total: number;\n valid: number;\n invalid: number;\n withWarnings: number;\n };\n}> {\n const results: Array<{ name: string; result: ValidationResult }> = [];\n\n if (!(await directoryExists(pluginsDir))) {\n return {\n valid: false,\n results: [\n {\n name: pluginsDir,\n result: {\n valid: false,\n errors: [`Directory does not exist: ${pluginsDir}`],\n warnings: [],\n },\n },\n ],\n summary: { total: 0, valid: 0, invalid: 1, withWarnings: 0 },\n };\n }\n\n const allDirs = await listDirectories(pluginsDir);\n const pluginDirs: string[] = [];\n\n for (const dirName of allDirs) {\n const potentialPluginDir = path.join(pluginsDir, dirName, PLUGIN_DIR);\n if (await directoryExists(potentialPluginDir)) {\n pluginDirs.push(dirName);\n }\n }\n\n if (pluginDirs.length === 0) {\n return {\n valid: false,\n results: [\n {\n name: pluginsDir,\n result: {\n valid: false,\n errors: [\n `No plugins found in directory: ${pluginsDir}. Plugins must contain a ${PLUGIN_DIR}/ directory.`,\n ],\n warnings: [],\n },\n },\n ],\n summary: { total: 0, valid: 0, invalid: 1, withWarnings: 0 },\n };\n }\n\n for (const pluginName of pluginDirs) {\n const pluginPath = path.join(pluginsDir, pluginName);\n const result = await validatePlugin(pluginPath);\n results.push({ name: pluginName, result });\n }\n\n const summary = {\n total: results.length,\n valid: results.filter((r) => r.result.valid).length,\n invalid: results.filter((r) => !r.result.valid).length,\n withWarnings: results.filter((r) => r.result.warnings.length > 0).length,\n };\n\n return {\n valid: summary.invalid === 0,\n results,\n summary,\n };\n}\n\nexport function printPluginValidationResult(\n name: string,\n result: ValidationResult,\n verbose = false,\n): void {\n const status = result.valid ? \"\\u2713\" : \"\\u2717\";\n\n if (result.valid && result.warnings.length === 0 && !verbose) {\n return;\n }\n\n console.log(`\\n ${status} ${name}`);\n\n if (result.errors.length > 0) {\n console.log(\" Errors:\");\n result.errors.forEach((e) => console.log(` - ${e}`));\n }\n\n if (result.warnings.length > 0) {\n console.log(\" Warnings:\");\n result.warnings.forEach((w) => console.log(` - ${w}`));\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cli/lib/plugin-version.ts"],"sourcesContent":["import path from \"path\";\nimport { readFile, writeFile } from \"../utils/fs\";\nimport {\n PLUGIN_MANIFEST_DIR,\n PLUGIN_MANIFEST_FILE,\n DEFAULT_VERSION,\n} from \"../consts\";\nimport type { PluginManifest } from \"../../types\";\n\nexport type VersionBumpType = \"major\" | \"minor\" | \"patch\";\n\nfunction parseVersion(version: string): [number, number, number] {\n const parts = version.split(\".\").map(Number);\n return [parts[0] || 1, parts[1] || 0, parts[2] || 0];\n}\n\nexport async function bumpPluginVersion(\n pluginDir: string,\n type: VersionBumpType,\n): Promise<string> {\n const manifestPath = path.join(\n pluginDir,\n PLUGIN_MANIFEST_DIR,\n PLUGIN_MANIFEST_FILE,\n );\n const content = await readFile(manifestPath);\n const manifest = JSON.parse(content) as PluginManifest;\n\n const [major, minor, patch] = parseVersion(\n manifest.version || DEFAULT_VERSION,\n );\n\n let newVersion: string;\n switch (type) {\n case \"major\":\n newVersion = `${major + 1}.0.0`;\n break;\n case \"minor\":\n newVersion = `${major}.${minor + 1}.0`;\n break;\n case \"patch\":\n newVersion = `${major}.${minor}.${patch + 1}`;\n break;\n }\n\n manifest.version = newVersion;\n await writeFile(manifestPath, JSON.stringify(manifest, null, 2));\n\n return newVersion;\n}\n\nexport async function getPluginVersion(pluginDir: string): Promise<string> {\n const manifestPath = path.join(\n pluginDir,\n PLUGIN_MANIFEST_DIR,\n PLUGIN_MANIFEST_FILE,\n );\n const content = await readFile(manifestPath);\n const manifest = JSON.parse(content) as PluginManifest;\n return manifest.version || DEFAULT_VERSION;\n}\n"],"mappings":";;;;;;;;;;;;;;;AAAA;AAAA,OAAO,UAAU;AAWjB,SAAS,aAAa,SAA2C;AAC/D,QAAM,QAAQ,QAAQ,MAAM,GAAG,EAAE,IAAI,MAAM;AAC3C,SAAO,CAAC,MAAM,CAAC,KAAK,GAAG,MAAM,CAAC,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC;AACrD;AAEA,eAAsB,kBACpB,WACA,MACiB;AACjB,QAAM,eAAe,KAAK;AAAA,IACxB;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACA,QAAM,UAAU,MAAM,SAAS,YAAY;AAC3C,QAAM,WAAW,KAAK,MAAM,OAAO;AAEnC,QAAM,CAAC,OAAO,OAAO,KAAK,IAAI;AAAA,IAC5B,SAAS,WAAW;AAAA,EACtB;AAEA,MAAI;AACJ,UAAQ,MAAM;AAAA,IACZ,KAAK;AACH,mBAAa,GAAG,QAAQ,CAAC;AACzB;AAAA,IACF,KAAK;AACH,mBAAa,GAAG,KAAK,IAAI,QAAQ,CAAC;AAClC;AAAA,IACF,KAAK;AACH,mBAAa,GAAG,KAAK,IAAI,KAAK,IAAI,QAAQ,CAAC;AAC3C;AAAA,EACJ;AAEA,WAAS,UAAU;AACnB,QAAM,UAAU,cAAc,KAAK,UAAU,UAAU,MAAM,CAAC,CAAC;AAE/D,SAAO;AACT;AAEA,eAAsB,iBAAiB,WAAoC;AACzE,QAAM,eAAe,KAAK;AAAA,IACxB;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACA,QAAM,UAAU,MAAM,SAAS,YAAY;AAC3C,QAAM,WAAW,KAAK,MAAM,OAAO;AACnC,SAAO,SAAS,WAAW;AAC7B;","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cli/lib/local-skill-loader.ts","../src/cli/lib/source-loader.ts"],"sourcesContent":["import { parse as parseYaml } from \"yaml\";\nimport path from \"path\";\nimport {\n directoryExists,\n listDirectories,\n fileExists,\n readFile,\n} from \"../utils/fs\";\nimport { verbose } from \"../utils/logger\";\nimport { LOCAL_SKILLS_PATH } from \"../consts\";\nimport { parseFrontmatter } from \"./loader\";\nimport type { ExtractedSkillMetadata } from \"../types-matrix\";\n\nconst LOCAL_CATEGORY = \"local\";\nconst LOCAL_AUTHOR = \"@local\";\n\ninterface LocalRawMetadata {\n cli_name: string;\n cli_description?: string;\n /** Original skill category from source (e.g., \"framework\", \"styling\", \"api\") */\n category?: string;\n category_exclusive?: boolean;\n usage_guidance?: string;\n tags?: string[];\n compatible_with?: string[];\n conflicts_with?: string[];\n requires?: string[];\n requires_setup?: string[];\n provides_setup_for?: string[];\n}\n\nexport interface LocalSkillDiscoveryResult {\n skills: ExtractedSkillMetadata[];\n localSkillsPath: string;\n}\n\nexport async function discoverLocalSkills(\n projectDir: string,\n): Promise<LocalSkillDiscoveryResult | null> {\n const localSkillsPath = path.join(projectDir, LOCAL_SKILLS_PATH);\n\n if (!(await directoryExists(localSkillsPath))) {\n verbose(`Local skills directory not found: ${localSkillsPath}`);\n return null;\n }\n\n const skills: ExtractedSkillMetadata[] = [];\n const skillDirs = await listDirectories(localSkillsPath);\n\n for (const skillDirName of skillDirs) {\n const skill = await extractLocalSkill(localSkillsPath, skillDirName);\n if (skill) {\n skills.push(skill);\n }\n }\n\n verbose(`Discovered ${skills.length} local skills from ${localSkillsPath}`);\n\n return {\n skills,\n localSkillsPath,\n };\n}\n\nasync function extractLocalSkill(\n localSkillsPath: string,\n skillDirName: string,\n): Promise<ExtractedSkillMetadata | null> {\n const skillDir = path.join(localSkillsPath, skillDirName);\n const metadataPath = path.join(skillDir, \"metadata.yaml\");\n const skillMdPath = path.join(skillDir, \"SKILL.md\");\n\n if (!(await fileExists(metadataPath))) {\n verbose(`Skipping local skill '${skillDirName}': No metadata.yaml found`);\n return null;\n }\n\n if (!(await fileExists(skillMdPath))) {\n verbose(`Skipping local skill '${skillDirName}': No SKILL.md found`);\n return null;\n }\n\n const metadataContent = await readFile(metadataPath);\n const metadata = parseYaml(metadataContent) as LocalRawMetadata;\n\n if (!metadata.cli_name) {\n verbose(\n `Skipping local skill '${skillDirName}': Missing required 'cli_name' in metadata.yaml`,\n );\n return null;\n }\n\n const skillMdContent = await readFile(skillMdPath);\n const frontmatter = parseFrontmatter(skillMdContent);\n\n if (!frontmatter) {\n verbose(\n `Skipping local skill '${skillDirName}': Invalid SKILL.md frontmatter`,\n );\n return null;\n }\n\n const relativePath = `${LOCAL_SKILLS_PATH}/${skillDirName}/`;\n const skillId = frontmatter.name;\n\n // Use category from metadata.yaml if available (preserved from source skill),\n // otherwise fall back to generic \"local\" category\n const category = metadata.category || LOCAL_CATEGORY;\n\n const extracted: ExtractedSkillMetadata = {\n id: skillId,\n directoryPath: skillDirName,\n name: `${metadata.cli_name} ${LOCAL_AUTHOR}`,\n description: metadata.cli_description || frontmatter.description,\n usageGuidance: metadata.usage_guidance,\n category,\n categoryExclusive: metadata.category_exclusive ?? false,\n author: LOCAL_AUTHOR,\n tags: metadata.tags ?? [],\n compatibleWith: metadata.compatible_with ?? [],\n conflictsWith: metadata.conflicts_with ?? [],\n requires: metadata.requires ?? [],\n requiresSetup: metadata.requires_setup ?? [],\n providesSetupFor: metadata.provides_setup_for ?? [],\n path: relativePath,\n local: true,\n localPath: relativePath,\n };\n\n verbose(`Extracted local skill: ${skillId}`);\n return extracted;\n}\n","import path from \"path\";\nimport { PROJECT_ROOT, SKILLS_DIR_PATH, SKILLS_MATRIX_PATH } from \"../consts\";\nimport type {\n CategoryDefinition,\n MergedSkillsMatrix,\n ResolvedSkill,\n ResolvedStack,\n} from \"../types-matrix\";\nimport type { Stack } from \"../types-stacks\";\nimport { fileExists } from \"../utils/fs\";\nimport { verbose } from \"../utils/logger\";\nimport { isLocalSource, resolveSource, type ResolvedConfig } from \"./config\";\nimport {\n discoverLocalSkills,\n type LocalSkillDiscoveryResult,\n} from \"./local-skill-loader\";\nimport {\n extractAllSkills,\n loadSkillsMatrix,\n mergeMatrixWithSkills,\n} from \"./matrix-loader\";\nimport { fetchFromSource } from \"./source-fetcher\";\nimport { loadStacks, resolveAgentConfigToSkills } from \"./stacks-loader\";\n\nexport interface SourceLoadOptions {\n sourceFlag?: string;\n projectDir?: string;\n forceRefresh?: boolean;\n devMode?: boolean;\n}\n\nexport interface SourceLoadResult {\n matrix: MergedSkillsMatrix;\n sourceConfig: ResolvedConfig;\n sourcePath: string;\n isLocal: boolean;\n marketplace?: string;\n}\n\nexport async function loadSkillsMatrixFromSource(\n options: SourceLoadOptions = {},\n): Promise<SourceLoadResult> {\n const {\n sourceFlag,\n projectDir,\n forceRefresh = false,\n devMode = false,\n } = options;\n\n const sourceConfig = await resolveSource(sourceFlag, projectDir);\n const { source } = sourceConfig;\n\n verbose(`Loading skills from source: ${source}`);\n\n const isLocal = isLocalSource(source) || devMode === true;\n\n let result: SourceLoadResult;\n if (isLocal) {\n result = await loadFromLocal(source, sourceConfig);\n } else {\n result = await loadFromRemote(source, sourceConfig, forceRefresh);\n }\n\n const resolvedProjectDir = projectDir || process.cwd();\n const localSkillsResult = await discoverLocalSkills(resolvedProjectDir);\n\n if (localSkillsResult && localSkillsResult.skills.length > 0) {\n verbose(\n `Found ${localSkillsResult.skills.length} local skill(s) in ${localSkillsResult.localSkillsPath}`,\n );\n result.matrix = mergeLocalSkillsIntoMatrix(\n result.matrix,\n localSkillsResult,\n );\n }\n\n return result;\n}\n\nasync function loadFromLocal(\n source: string,\n sourceConfig: ResolvedConfig,\n): Promise<SourceLoadResult> {\n let skillsPath: string;\n\n if (isLocalSource(source)) {\n skillsPath = path.isAbsolute(source)\n ? source\n : path.resolve(process.cwd(), source);\n } else {\n skillsPath = PROJECT_ROOT;\n }\n\n verbose(`Loading skills from local path: ${skillsPath}`);\n\n // Check if source has its own matrix, otherwise fallback to CLI matrix\n const sourceMatrixPath = path.join(skillsPath, SKILLS_MATRIX_PATH);\n const cliMatrixPath = path.join(PROJECT_ROOT, SKILLS_MATRIX_PATH);\n\n let matrixPath: string;\n if (await fileExists(sourceMatrixPath)) {\n matrixPath = sourceMatrixPath;\n verbose(`Matrix from source: ${matrixPath}`);\n } else {\n matrixPath = cliMatrixPath;\n verbose(`Matrix from CLI (source has no matrix): ${matrixPath}`);\n }\n\n const skillsDir = path.join(skillsPath, SKILLS_DIR_PATH);\n verbose(`Skills from source: ${skillsDir}`);\n\n const matrix = await loadSkillsMatrix(matrixPath);\n const skills = await extractAllSkills(skillsDir);\n const mergedMatrix = await mergeMatrixWithSkills(matrix, skills);\n\n // Load stacks from CLI's config/stacks.yaml (Phase 6: agent-centric config)\n const stacks = await loadStacks(PROJECT_ROOT);\n if (stacks.length > 0) {\n // Phase 7: Skills are defined in stacks (per agent, per subcategory), not in agent YAMLs\n // Use skill_aliases from the matrix to resolve technology aliases to full skill IDs\n mergedMatrix.suggestedStacks = stacks.map((stack) =>\n stackToResolvedStack(stack, mergedMatrix.aliases),\n );\n verbose(`Loaded ${stacks.length} stacks from config/stacks.yaml`);\n }\n\n return {\n matrix: mergedMatrix,\n sourceConfig,\n sourcePath: skillsPath,\n isLocal: true,\n marketplace: sourceConfig.marketplace,\n };\n}\n\nasync function loadFromRemote(\n source: string,\n sourceConfig: ResolvedConfig,\n forceRefresh: boolean,\n): Promise<SourceLoadResult> {\n verbose(`Fetching skills from remote source: ${source}`);\n\n const fetchResult = await fetchFromSource(source, { forceRefresh });\n\n verbose(`Fetched to: ${fetchResult.path}`);\n\n // Check if source has its own matrix, otherwise fallback to CLI matrix\n const sourceMatrixPath = path.join(fetchResult.path, SKILLS_MATRIX_PATH);\n const cliMatrixPath = path.join(PROJECT_ROOT, SKILLS_MATRIX_PATH);\n\n let matrixPath: string;\n if (await fileExists(sourceMatrixPath)) {\n matrixPath = sourceMatrixPath;\n verbose(`Matrix from source: ${matrixPath}`);\n } else {\n matrixPath = cliMatrixPath;\n verbose(`Matrix from CLI (source has no matrix): ${matrixPath}`);\n }\n\n const skillsDir = path.join(fetchResult.path, SKILLS_DIR_PATH);\n verbose(`Skills from source: ${skillsDir}`);\n\n const matrix = await loadSkillsMatrix(matrixPath);\n const skills = await extractAllSkills(skillsDir);\n const mergedMatrix = await mergeMatrixWithSkills(matrix, skills);\n\n // Load stacks from CLI's config/stacks.yaml (Phase 6: agent-centric config)\n const stacks = await loadStacks(PROJECT_ROOT);\n if (stacks.length > 0) {\n // Phase 7: Skills are defined in stacks (per agent, per subcategory), not in agent YAMLs\n // Use skill_aliases from the matrix to resolve technology aliases to full skill IDs\n mergedMatrix.suggestedStacks = stacks.map((stack) =>\n stackToResolvedStack(stack, mergedMatrix.aliases),\n );\n verbose(`Loaded ${stacks.length} stacks from config/stacks.yaml`);\n }\n\n return {\n matrix: mergedMatrix,\n sourceConfig,\n sourcePath: fetchResult.path,\n isLocal: false,\n marketplace: sourceConfig.marketplace,\n };\n}\n\n/**\n * Convert a Stack (from config/stacks.yaml) to ResolvedStack format\n * for compatibility with the wizard.\n *\n * Phase 7: Skills are defined in stacks per agent (subcategory -> technology alias).\n * Uses skill_aliases from the matrix to resolve aliases to full skill IDs.\n */\nfunction stackToResolvedStack(\n stack: Stack,\n skillAliases: Record<string, string>,\n): ResolvedStack {\n // Collect all unique skill IDs from agent configs in this stack\n const allSkillIds: string[] = [];\n const seenSkillIds = new Set<string>();\n\n // stack.agents is Record<string, StackAgentConfig> - iterate over agent IDs\n for (const agentId of Object.keys(stack.agents)) {\n const agentConfig = stack.agents[agentId];\n\n // Resolve this agent's technology selections to skill IDs\n const skillRefs = resolveAgentConfigToSkills(agentConfig, skillAliases);\n\n for (const ref of skillRefs) {\n if (!seenSkillIds.has(ref.id)) {\n seenSkillIds.add(ref.id);\n allSkillIds.push(ref.id);\n }\n }\n }\n\n const agentCount = Object.keys(stack.agents).length;\n verbose(\n `Stack '${stack.id}' has ${allSkillIds.length} skills from ${agentCount} agents`,\n );\n\n return {\n id: stack.id,\n name: stack.name,\n description: stack.description,\n audience: [], // Not used in new format\n skills: {}, // Skills come from stack agent configs, resolved at runtime\n allSkillIds,\n philosophy: stack.philosophy || \"\",\n };\n}\n\nconst LOCAL_CATEGORY_TOP: CategoryDefinition = {\n id: \"local\",\n name: \"Local Skills\",\n description: \"Project-specific skills from .claude/skills/\",\n exclusive: false,\n required: false,\n order: 0,\n};\n\nconst LOCAL_CATEGORY_CUSTOM: CategoryDefinition = {\n id: \"local/custom\",\n name: \"Custom\",\n description: \"Your project-specific skills\",\n exclusive: false,\n required: false,\n order: 0,\n parent: \"local\",\n};\n\nfunction mergeLocalSkillsIntoMatrix(\n matrix: MergedSkillsMatrix,\n localResult: LocalSkillDiscoveryResult,\n): MergedSkillsMatrix {\n if (!matrix.categories[\"local\"]) {\n matrix.categories[\"local\"] = LOCAL_CATEGORY_TOP;\n }\n if (!matrix.categories[\"local/custom\"]) {\n matrix.categories[\"local/custom\"] = LOCAL_CATEGORY_CUSTOM;\n }\n\n for (const metadata of localResult.skills) {\n // Use the skill's original category from metadata.yaml when available,\n // falling back to \"local/custom\" for truly new local skills\n const hasOriginalCategory =\n metadata.category !== \"local\" && matrix.categories[metadata.category];\n const category = hasOriginalCategory ? metadata.category : \"local/custom\";\n\n // Preserve alias from existing matrix entry (if skill was in source)\n const existingSkill = matrix.skills[metadata.id];\n const alias = existingSkill?.alias ?? matrix.aliasesReverse[metadata.id];\n\n const resolvedSkill: ResolvedSkill = {\n id: metadata.id,\n alias,\n name: metadata.name,\n description: metadata.description,\n usageGuidance: metadata.usageGuidance,\n\n category,\n categoryExclusive: metadata.categoryExclusive,\n tags: metadata.tags ?? [],\n\n author: \"@local\",\n\n conflictsWith: existingSkill?.conflictsWith ?? [],\n recommends: existingSkill?.recommends ?? [],\n recommendedBy: existingSkill?.recommendedBy ?? [],\n requires: existingSkill?.requires ?? [],\n requiredBy: existingSkill?.requiredBy ?? [],\n alternatives: existingSkill?.alternatives ?? [],\n discourages: existingSkill?.discourages ?? [],\n compatibleWith: existingSkill?.compatibleWith ?? [],\n\n requiresSetup: existingSkill?.requiresSetup ?? [],\n providesSetupFor: existingSkill?.providesSetupFor ?? [],\n\n path: metadata.path,\n\n local: true,\n localPath: metadata.localPath,\n };\n\n matrix.skills[metadata.id] = resolvedSkill;\n verbose(`Added local skill: ${metadata.id} (category: ${category})`);\n }\n\n return matrix;\n}\n"],"mappings":"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","names":["path","path"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cli/lib/agent-fetcher.ts"],"sourcesContent":["import path from \"path\";\nimport { directoryExists } from \"../utils/fs\";\nimport { verbose } from \"../utils/logger\";\nimport { PROJECT_ROOT, DIRS, CLAUDE_DIR } from \"../consts\";\nimport { fetchFromSource, type FetchOptions } from \"./source-fetcher\";\nimport type { AgentSourcePaths } from \"../../types\";\n\nexport interface AgentDefinitionOptions extends FetchOptions {\n /** Project directory to check for local templates */\n projectDir?: string;\n}\n\nexport async function getAgentDefinitions(\n remoteSource?: string,\n options: AgentDefinitionOptions = {},\n): Promise<AgentSourcePaths> {\n if (remoteSource) {\n return fetchAgentDefinitionsFromRemote(remoteSource, options);\n }\n return getLocalAgentDefinitions(options);\n}\n\nexport async function getLocalAgentDefinitions(\n options: AgentDefinitionOptions = {},\n): Promise<AgentSourcePaths> {\n const agentsDir = path.join(PROJECT_ROOT, DIRS.agents);\n let templatesDir = path.join(PROJECT_ROOT, DIRS.templates);\n\n if (!(await directoryExists(agentsDir))) {\n throw new Error(\n `Agent partials not found at: ${agentsDir}. ` +\n `Ensure the CLI is properly installed.`,\n );\n }\n\n // Check for local templates first (from eject templates)\n if (options.projectDir) {\n const localTemplatesDir = path.join(\n options.projectDir,\n CLAUDE_DIR,\n \"templates\",\n );\n if (await directoryExists(localTemplatesDir)) {\n verbose(`Using local templates from: ${localTemplatesDir}`);\n templatesDir = localTemplatesDir;\n }\n }\n\n if (!(await directoryExists(templatesDir))) {\n verbose(`Templates directory not found: ${templatesDir}`);\n }\n\n verbose(`Agent partials loaded from CLI: ${agentsDir}`);\n verbose(`Templates directory: ${templatesDir}`);\n\n return {\n agentsDir,\n templatesDir,\n sourcePath: PROJECT_ROOT,\n };\n}\n\nexport async function fetchAgentDefinitionsFromRemote(\n source: string,\n options: FetchOptions = {},\n): Promise<AgentSourcePaths> {\n verbose(`Fetching agent partials from remote: ${source}`);\n\n const result = await fetchFromSource(source, {\n forceRefresh: options.forceRefresh,\n subdir: \"\",\n });\n\n const agentsDir = path.join(result.path, \"src\", \"agents\");\n const templatesDir = path.join(agentsDir, \"_templates\");\n\n if (!(await directoryExists(agentsDir))) {\n throw new Error(`Agent partials not found at: ${agentsDir}`);\n }\n\n if (!(await directoryExists(templatesDir))) {\n verbose(`Templates directory not found: ${templatesDir}`);\n }\n\n verbose(`Agent partials fetched from: ${result.path}`);\n\n return {\n agentsDir,\n templatesDir,\n sourcePath: result.path,\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA,OAAO,UAAU;AAYjB,eAAsB,oBACpB,cACA,UAAkC,CAAC,GACR;AAC3B,MAAI,cAAc;AAChB,WAAO,gCAAgC,cAAc,OAAO;AAAA,EAC9D;AACA,SAAO,yBAAyB,OAAO;AACzC;AAEA,eAAsB,yBACpB,UAAkC,CAAC,GACR;AAC3B,QAAM,YAAY,KAAK,KAAK,cAAc,KAAK,MAAM;AACrD,MAAI,eAAe,KAAK,KAAK,cAAc,KAAK,SAAS;AAEzD,MAAI,CAAE,MAAM,gBAAgB,SAAS,GAAI;AACvC,UAAM,IAAI;AAAA,MACR,gCAAgC,SAAS;AAAA,IAE3C;AAAA,EACF;AAGA,MAAI,QAAQ,YAAY;AACtB,UAAM,oBAAoB,KAAK;AAAA,MAC7B,QAAQ;AAAA,MACR;AAAA,MACA;AAAA,IACF;AACA,QAAI,MAAM,gBAAgB,iBAAiB,GAAG;AAC5C,cAAQ,+BAA+B,iBAAiB,EAAE;AAC1D,qBAAe;AAAA,IACjB;AAAA,EACF;AAEA,MAAI,CAAE,MAAM,gBAAgB,YAAY,GAAI;AAC1C,YAAQ,kCAAkC,YAAY,EAAE;AAAA,EAC1D;AAEA,UAAQ,mCAAmC,SAAS,EAAE;AACtD,UAAQ,wBAAwB,YAAY,EAAE;AAE9C,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,YAAY;AAAA,EACd;AACF;AAEA,eAAsB,gCACpB,QACA,UAAwB,CAAC,GACE;AAC3B,UAAQ,wCAAwC,MAAM,EAAE;AAExD,QAAM,SAAS,MAAM,gBAAgB,QAAQ;AAAA,IAC3C,cAAc,QAAQ;AAAA,IACtB,QAAQ;AAAA,EACV,CAAC;AAED,QAAM,YAAY,KAAK,KAAK,OAAO,MAAM,OAAO,QAAQ;AACxD,QAAM,eAAe,KAAK,KAAK,WAAW,YAAY;AAEtD,MAAI,CAAE,MAAM,gBAAgB,SAAS,GAAI;AACvC,UAAM,IAAI,MAAM,gCAAgC,SAAS,EAAE;AAAA,EAC7D;AAEA,MAAI,CAAE,MAAM,gBAAgB,YAAY,GAAI;AAC1C,YAAQ,kCAAkC,YAAY,EAAE;AAAA,EAC1D;AAEA,UAAQ,gCAAgC,OAAO,IAAI,EAAE;AAErD,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,YAAY,OAAO;AAAA,EACrB;AACF;","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cli/utils/fs.ts"],"sourcesContent":["import fs from \"fs-extra\";\nimport fg from \"fast-glob\";\nimport path from \"path\";\n\nexport async function readFile(filePath: string): Promise<string> {\n return fs.readFile(filePath, \"utf-8\");\n}\n\nexport async function readFileOptional(\n filePath: string,\n fallback = \"\",\n): Promise<string> {\n try {\n return await fs.readFile(filePath, \"utf-8\");\n } catch {\n return fallback;\n }\n}\n\nexport async function fileExists(filePath: string): Promise<boolean> {\n return fs.pathExists(filePath);\n}\n\nexport async function directoryExists(dirPath: string): Promise<boolean> {\n try {\n const stat = await fs.stat(dirPath);\n return stat.isDirectory();\n } catch {\n return false;\n }\n}\n\nexport async function listDirectories(dirPath: string): Promise<string[]> {\n try {\n const entries = await fs.readdir(dirPath, { withFileTypes: true });\n return entries.filter((e) => e.isDirectory()).map((e) => e.name);\n } catch {\n return [];\n }\n}\n\nexport async function glob(pattern: string, cwd: string): Promise<string[]> {\n return fg(pattern, { cwd, onlyFiles: true });\n}\n\nexport async function writeFile(\n filePath: string,\n content: string,\n): Promise<void> {\n await fs.ensureDir(path.dirname(filePath));\n await fs.writeFile(filePath, content, \"utf-8\");\n}\n\nexport async function ensureDir(dirPath: string): Promise<void> {\n await fs.ensureDir(dirPath);\n}\n\nexport async function remove(filePath: string): Promise<void> {\n await fs.remove(filePath);\n}\n\nexport async function copy(src: string, dest: string): Promise<void> {\n await fs.copy(src, dest);\n}\n"],"mappings":";;;;;;AAAA;AAAA,OAAO,QAAQ;AACf,OAAO,QAAQ;AACf,OAAO,UAAU;AAEjB,eAAsB,SAAS,UAAmC;AAChE,SAAO,GAAG,SAAS,UAAU,OAAO;AACtC;AAEA,eAAsB,iBACpB,UACA,WAAW,IACM;AACjB,MAAI;AACF,WAAO,MAAM,GAAG,SAAS,UAAU,OAAO;AAAA,EAC5C,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,eAAsB,WAAW,UAAoC;AACnE,SAAO,GAAG,WAAW,QAAQ;AAC/B;AAEA,eAAsB,gBAAgB,SAAmC;AACvE,MAAI;AACF,UAAM,OAAO,MAAM,GAAG,KAAK,OAAO;AAClC,WAAO,KAAK,YAAY;AAAA,EAC1B,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,eAAsB,gBAAgB,SAAoC;AACxE,MAAI;AACF,UAAM,UAAU,MAAM,GAAG,QAAQ,SAAS,EAAE,eAAe,KAAK,CAAC;AACjE,WAAO,QAAQ,OAAO,CAAC,MAAM,EAAE,YAAY,CAAC,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI;AAAA,EACjE,QAAQ;AACN,WAAO,CAAC;AAAA,EACV;AACF;AAEA,eAAsB,KAAK,SAAiB,KAAgC;AAC1E,SAAO,GAAG,SAAS,EAAE,KAAK,WAAW,KAAK,CAAC;AAC7C;AAEA,eAAsB,UACpB,UACA,SACe;AACf,QAAM,GAAG,UAAU,KAAK,QAAQ,QAAQ,CAAC;AACzC,QAAM,GAAG,UAAU,UAAU,SAAS,OAAO;AAC/C;AAEA,eAAsB,UAAU,SAAgC;AAC9D,QAAM,GAAG,UAAU,OAAO;AAC5B;AAEA,eAAsB,OAAO,UAAiC;AAC5D,QAAM,GAAG,OAAO,QAAQ;AAC1B;AAEA,eAAsB,KAAK,KAAa,MAA6B;AACnE,QAAM,GAAG,KAAK,KAAK,IAAI;AACzB;","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cli/utils/exec.ts"],"sourcesContent":["import { spawn } from \"child_process\";\n\nexport interface ExecResult {\n stdout: string;\n stderr: string;\n exitCode: number;\n}\n\n/**\n * Execute a command and return the result\n */\nexport async function execCommand(\n command: string,\n args: string[],\n options?: { cwd?: string; env?: NodeJS.ProcessEnv },\n): Promise<ExecResult> {\n return new Promise((resolve, reject) => {\n const proc = spawn(command, args, {\n cwd: options?.cwd,\n env: { ...process.env, ...options?.env },\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n });\n\n let stdout = \"\";\n let stderr = \"\";\n\n proc.stdout.on(\"data\", (data) => {\n stdout += data.toString();\n });\n\n proc.stderr.on(\"data\", (data) => {\n stderr += data.toString();\n });\n\n proc.on(\"close\", (code) => {\n resolve({\n stdout,\n stderr,\n exitCode: code ?? 1,\n });\n });\n\n proc.on(\"error\", (err) => {\n reject(err);\n });\n });\n}\n\n/**\n * Install a plugin using the native claude CLI\n */\nexport async function claudePluginInstall(\n pluginPath: string,\n scope: \"project\" | \"user\",\n projectDir: string,\n): Promise<void> {\n const args = [\"plugin\", \"install\", pluginPath, \"--scope\", scope];\n const result = await execCommand(\"claude\", args, { cwd: projectDir });\n\n if (result.exitCode !== 0) {\n const errorMessage = result.stderr || result.stdout || \"Unknown error\";\n throw new Error(`Plugin installation failed: ${errorMessage.trim()}`);\n }\n}\n\n/**\n * Check if the claude CLI is available\n */\nexport async function isClaudeCLIAvailable(): Promise<boolean> {\n try {\n const result = await execCommand(\"claude\", [\"--version\"], {});\n return result.exitCode === 0;\n } catch {\n return false;\n }\n}\n\nexport interface MarketplaceInfo {\n name: string;\n source: string;\n repo?: string;\n path?: string;\n}\n\n/**\n * List configured marketplaces in Claude Code\n */\nexport async function claudePluginMarketplaceList(): Promise<\n MarketplaceInfo[]\n> {\n try {\n const result = await execCommand(\n \"claude\",\n [\"plugin\", \"marketplace\", \"list\", \"--json\"],\n {},\n );\n\n if (result.exitCode !== 0) {\n return [];\n }\n\n return JSON.parse(result.stdout);\n } catch {\n // Returns empty array if claude CLI is not available or parsing fails\n return [];\n }\n}\n\n/**\n * Check if a marketplace with the given name exists\n */\nexport async function claudePluginMarketplaceExists(\n name: string,\n): Promise<boolean> {\n const marketplaces = await claudePluginMarketplaceList();\n return marketplaces.some((m) => m.name === name);\n}\n\n/**\n * Add a marketplace to Claude Code from a GitHub repository\n */\nexport async function claudePluginMarketplaceAdd(\n githubRepo: string,\n name: string,\n): Promise<void> {\n const args = [\"plugin\", \"marketplace\", \"add\", githubRepo, \"--name\", name];\n let result;\n try {\n result = await execCommand(\"claude\", args, {});\n } catch (err) {\n throw new Error(\n `Failed to add marketplace: ${err instanceof Error ? err.message : \"Unknown error\"}`,\n );\n }\n\n if (result.exitCode !== 0) {\n const errorMessage = result.stderr || result.stdout || \"Unknown error\";\n if (errorMessage.includes(\"already installed\")) {\n return;\n }\n throw new Error(`Failed to add marketplace: ${errorMessage.trim()}`);\n }\n}\n\n/**\n * Uninstall a plugin using the native claude CLI\n */\nexport async function claudePluginUninstall(\n pluginName: string,\n scope: \"project\" | \"user\",\n projectDir: string,\n): Promise<void> {\n const args = [\"plugin\", \"uninstall\", pluginName, \"--scope\", scope];\n const result = await execCommand(\"claude\", args, { cwd: projectDir });\n\n if (result.exitCode !== 0) {\n const errorMessage = result.stderr || result.stdout || \"Unknown error\";\n // Ignore \"not installed\" errors - plugin may already be removed\n if (\n errorMessage.includes(\"not installed\") ||\n errorMessage.includes(\"not found\")\n ) {\n return;\n }\n throw new Error(`Plugin uninstall failed: ${errorMessage.trim()}`);\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cli/lib/config.ts"],"sourcesContent":["import path from \"path\";\nimport os from \"os\";\nimport { parse as parseYaml, stringify as stringifyYaml } from \"yaml\";\nimport { readFile, writeFile, fileExists, ensureDir } from \"../utils/fs\";\nimport { verbose } from \"../utils/logger\";\nimport { CLAUDE_DIR, CLAUDE_SRC_DIR } from \"../consts\";\n\nexport const DEFAULT_SOURCE = \"github:claude-collective/skills\";\nexport const SOURCE_ENV_VAR = \"CC_SOURCE\";\n/** Environment variable to override global config directory (used for testing) */\nexport const CONFIG_HOME_ENV_VAR = \"CC_CONFIG_HOME\";\nexport const GLOBAL_CONFIG_FILE = \"config.yaml\";\nexport const PROJECT_CONFIG_FILE = \"config.yaml\";\n\n/**\n * Get global config directory path.\n * Can be overridden via CC_CONFIG_HOME environment variable for testing isolation.\n * This is a function (not constant) to allow tests to set the env var after module load.\n */\nexport function getGlobalConfigDir(): string {\n return (\n process.env[CONFIG_HOME_ENV_VAR] ||\n path.join(os.homedir(), \".claude-collective\")\n );\n}\n\n/**\n * @deprecated Use getGlobalConfigDir() instead. This constant is kept for backwards compatibility\n * but won't respect CC_CONFIG_HOME set after module load.\n */\nexport const GLOBAL_CONFIG_DIR = path.join(os.homedir(), \".claude-collective\");\n\n/**\n * Extra source entry for third-party skill repositories.\n * Used in both global and project configs.\n */\nexport interface SourceEntry {\n /** Short name for the source (e.g., \"company\", \"team\") */\n name: string;\n /** GitHub URL or path (e.g., \"github:owner/repo\") */\n url: string;\n /** Optional description */\n description?: string;\n /** Optional ref to pin to (branch, tag, or commit) */\n ref?: string;\n}\n\nexport interface GlobalConfig {\n source?: string;\n author?: string;\n marketplace?: string;\n agents_source?: string;\n /** Extra sources for third-party skills */\n sources?: SourceEntry[];\n}\n\nexport interface ProjectConfig {\n source?: string;\n author?: string;\n marketplace?: string;\n agents_source?: string;\n /** Extra sources for third-party skills */\n sources?: SourceEntry[];\n}\n\nexport interface ResolvedConfig {\n source: string;\n sourceOrigin: \"flag\" | \"env\" | \"project\" | \"global\" | \"default\";\n marketplace?: string;\n}\n\nfunction isValidSourceEntry(entry: unknown): entry is SourceEntry {\n if (typeof entry !== \"object\" || entry === null) return false;\n const e = entry as Record<string, unknown>;\n if (typeof e.name !== \"string\" || typeof e.url !== \"string\") return false;\n if (e.description !== undefined && typeof e.description !== \"string\")\n return false;\n if (e.ref !== undefined && typeof e.ref !== \"string\") return false;\n return true;\n}\n\nfunction isValidSourcesArray(arr: unknown): arr is SourceEntry[] {\n if (!Array.isArray(arr)) return false;\n return arr.every(isValidSourceEntry);\n}\n\nfunction isValidGlobalConfig(obj: unknown): obj is GlobalConfig {\n if (typeof obj !== \"object\" || obj === null) return false;\n const config = obj as Record<string, unknown>;\n if (config.source !== undefined && typeof config.source !== \"string\")\n return false;\n if (config.author !== undefined && typeof config.author !== \"string\")\n return false;\n if (\n config.marketplace !== undefined &&\n typeof config.marketplace !== \"string\"\n )\n return false;\n if (\n config.agents_source !== undefined &&\n typeof config.agents_source !== \"string\"\n )\n return false;\n if (config.sources !== undefined && !isValidSourcesArray(config.sources))\n return false;\n return true;\n}\n\nfunction isValidProjectConfig(obj: unknown): obj is ProjectConfig {\n if (typeof obj !== \"object\" || obj === null) return false;\n const config = obj as Record<string, unknown>;\n if (config.source !== undefined && typeof config.source !== \"string\")\n return false;\n if (config.author !== undefined && typeof config.author !== \"string\")\n return false;\n if (\n config.marketplace !== undefined &&\n typeof config.marketplace !== \"string\"\n )\n return false;\n if (\n config.agents_source !== undefined &&\n typeof config.agents_source !== \"string\"\n )\n return false;\n if (config.sources !== undefined && !isValidSourcesArray(config.sources))\n return false;\n return true;\n}\n\nexport function getGlobalConfigPath(): string {\n return path.join(getGlobalConfigDir(), GLOBAL_CONFIG_FILE);\n}\n\nexport function getProjectConfigPath(projectDir: string): string {\n return path.join(projectDir, CLAUDE_SRC_DIR, PROJECT_CONFIG_FILE);\n}\n\n/**\n * @deprecated Global config is deprecated. Use project-level config at .claude/config.yaml instead.\n * This function is kept for backwards compatibility during migration.\n */\nexport async function loadGlobalConfig(): Promise<GlobalConfig | null> {\n const configPath = getGlobalConfigPath();\n\n if (!(await fileExists(configPath))) {\n verbose(`Global config not found at ${configPath}`);\n return null;\n }\n\n try {\n const content = await readFile(configPath);\n const parsed = parseYaml(content);\n if (!isValidGlobalConfig(parsed)) {\n verbose(`Invalid global config structure at ${configPath}`);\n return null;\n }\n verbose(`Loaded global config from ${configPath}`);\n return parsed;\n } catch (error) {\n verbose(`Failed to parse global config: ${error}`);\n return null;\n }\n}\n\nexport async function loadProjectConfig(\n projectDir: string,\n): Promise<ProjectConfig | null> {\n // Check .claude-src/config.yaml first (new location)\n const srcConfigPath = getProjectConfigPath(projectDir);\n // Fall back to .claude/config.yaml (legacy location)\n const legacyConfigPath = path.join(projectDir, CLAUDE_DIR, \"config.yaml\");\n\n let configPath = srcConfigPath;\n if (!(await fileExists(srcConfigPath))) {\n if (await fileExists(legacyConfigPath)) {\n configPath = legacyConfigPath;\n verbose(`Using legacy config location: ${legacyConfigPath}`);\n } else {\n verbose(\n `Project config not found at ${srcConfigPath} or ${legacyConfigPath}`,\n );\n return null;\n }\n }\n\n try {\n const content = await readFile(configPath);\n const parsed = parseYaml(content);\n if (!isValidProjectConfig(parsed)) {\n verbose(`Invalid project config structure at ${configPath}`);\n return null;\n }\n verbose(`Loaded project config from ${configPath}`);\n return parsed;\n } catch (error) {\n verbose(`Failed to parse project config: ${error}`);\n return null;\n }\n}\n\n/**\n * @deprecated Global config is deprecated. Use project-level config at .claude/config.yaml instead.\n * This function is kept for backwards compatibility during migration.\n */\nexport async function saveGlobalConfig(config: GlobalConfig): Promise<void> {\n const configPath = getGlobalConfigPath();\n await ensureDir(getGlobalConfigDir());\n const content = stringifyYaml(config, { lineWidth: 0 });\n await writeFile(configPath, content);\n verbose(`Saved global config to ${configPath}`);\n}\n\nexport async function saveProjectConfig(\n projectDir: string,\n config: ProjectConfig,\n): Promise<void> {\n const configPath = getProjectConfigPath(projectDir);\n await ensureDir(path.join(projectDir, CLAUDE_SRC_DIR));\n const content = stringifyYaml(config, { lineWidth: 0 });\n await writeFile(configPath, content);\n verbose(`Saved project config to ${configPath}`);\n}\n\n/** Resolve source with precedence: flag > env > project > default */\nexport async function resolveSource(\n flagValue?: string,\n projectDir?: string,\n): Promise<ResolvedConfig> {\n // Load project config for marketplace (marketplace is resolved separately from source)\n const projectConfig = projectDir ? await loadProjectConfig(projectDir) : null;\n\n // Resolve marketplace: project config only (no flag/env support for marketplace)\n const marketplace = projectConfig?.marketplace;\n\n if (flagValue !== undefined) {\n if (flagValue === \"\" || flagValue.trim() === \"\") {\n throw new Error(\"--source flag cannot be empty\");\n }\n verbose(`Source from --source flag: ${flagValue}`);\n return { source: flagValue, sourceOrigin: \"flag\", marketplace };\n }\n\n const envValue = process.env[SOURCE_ENV_VAR];\n if (envValue) {\n verbose(`Source from ${SOURCE_ENV_VAR} env var: ${envValue}`);\n return { source: envValue, sourceOrigin: \"env\", marketplace };\n }\n\n if (projectConfig?.source) {\n verbose(`Source from project config: ${projectConfig.source}`);\n return {\n source: projectConfig.source,\n sourceOrigin: \"project\",\n marketplace,\n };\n }\n\n verbose(`Using default source: ${DEFAULT_SOURCE}`);\n return { source: DEFAULT_SOURCE, sourceOrigin: \"default\", marketplace };\n}\n\nexport type AgentsSourceOrigin = \"flag\" | \"project\" | \"global\" | \"default\";\n\nexport interface ResolvedAgentsSource {\n agentsSource?: string;\n agentsSourceOrigin: AgentsSourceOrigin;\n}\n\n/** Resolve agents_source with precedence: flag > project > default (undefined) */\nexport async function resolveAgentsSource(\n flagValue?: string,\n projectDir?: string,\n): Promise<ResolvedAgentsSource> {\n if (flagValue !== undefined) {\n if (flagValue === \"\" || flagValue.trim() === \"\") {\n throw new Error(\"--agent-source flag cannot be empty\");\n }\n verbose(`Agents source from --agent-source flag: ${flagValue}`);\n return { agentsSource: flagValue, agentsSourceOrigin: \"flag\" };\n }\n\n const projectConfig = projectDir ? await loadProjectConfig(projectDir) : null;\n if (projectConfig?.agents_source) {\n verbose(\n `Agents source from project config: ${projectConfig.agents_source}`,\n );\n return {\n agentsSource: projectConfig.agents_source,\n agentsSourceOrigin: \"project\",\n };\n }\n\n verbose(\"Using default agents source (local CLI)\");\n return { agentsSource: undefined, agentsSourceOrigin: \"default\" };\n}\n\nexport function formatAgentsSourceOrigin(origin: AgentsSourceOrigin): string {\n switch (origin) {\n case \"flag\":\n return \"--agent-source flag\";\n case \"project\":\n return \"project config (.claude-src/config.yaml)\";\n case \"global\":\n return \"global config (~/.claude-collective/config.yaml)\";\n case \"default\":\n return \"default (local CLI)\";\n }\n}\n\n/** Resolve author from project config */\nexport async function resolveAuthor(\n projectDir?: string,\n): Promise<string | undefined> {\n const projectConfig = projectDir ? await loadProjectConfig(projectDir) : null;\n return projectConfig?.author;\n}\n\nexport function formatSourceOrigin(\n origin: ResolvedConfig[\"sourceOrigin\"],\n): string {\n switch (origin) {\n case \"flag\":\n return \"--source flag\";\n case \"env\":\n return `${SOURCE_ENV_VAR} environment variable`;\n case \"project\":\n return \"project config (.claude-src/config.yaml)\";\n case \"global\":\n return \"global config (~/.claude-collective/config.yaml)\";\n case \"default\":\n return \"default\";\n }\n}\n\n/**\n * Resolve all configured sources for skill search.\n * Returns primary source plus any extra sources from project/global config.\n */\nexport async function resolveAllSources(\n projectDir?: string,\n): Promise<{ primary: SourceEntry; extras: SourceEntry[] }> {\n const projectConfig = projectDir ? await loadProjectConfig(projectDir) : null;\n const globalConfig = await loadGlobalConfig();\n\n // Get primary source\n const resolvedConfig = await resolveSource(undefined, projectDir);\n const primary: SourceEntry = {\n name: \"marketplace\",\n url: resolvedConfig.source,\n description: \"Primary skills marketplace\",\n };\n\n // Merge extra sources: project takes precedence, then global\n const extras: SourceEntry[] = [];\n const seenNames = new Set<string>();\n\n // Add project sources first (higher priority)\n if (projectConfig?.sources) {\n for (const source of projectConfig.sources) {\n if (!seenNames.has(source.name)) {\n seenNames.add(source.name);\n extras.push(source);\n }\n }\n }\n\n // Add global sources (lower priority, skip duplicates)\n if (globalConfig?.sources) {\n for (const source of globalConfig.sources) {\n if (!seenNames.has(source.name)) {\n seenNames.add(source.name);\n extras.push(source);\n }\n }\n }\n\n return { primary, extras };\n}\n\nexport function isLocalSource(source: string): boolean {\n if (source.startsWith(\"/\") || source.startsWith(\".\")) {\n return true;\n }\n\n const remoteProtocols = [\n \"github:\",\n \"gh:\",\n \"gitlab:\",\n \"bitbucket:\",\n \"sourcehut:\",\n \"https://\",\n \"http://\",\n ];\n\n const hasRemoteProtocol = remoteProtocols.some((prefix) =>\n source.startsWith(prefix),\n );\n\n if (!hasRemoteProtocol) {\n if (source.includes(\"..\") || source.includes(\"~\")) {\n throw new Error(\n `Invalid source path: ${source}. Path traversal patterns are not allowed.`,\n );\n }\n }\n\n return !hasRemoteProtocol;\n}\n"],"mappings":"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","names":[]}
|