@claude-collective/cli 0.21.0 → 0.25.1
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 +174 -0
- package/README.md +41 -27
- package/config/skills-matrix.yaml +38 -37
- package/config/stacks.yaml +8 -14
- package/dist/{chunk-ZNIDWLL5.js → chunk-3X5D7RM5.js} +4 -3
- package/dist/chunk-3X5D7RM5.js.map +1 -0
- package/dist/chunk-4S4FCAA2.js +100 -0
- package/dist/chunk-4S4FCAA2.js.map +1 -0
- package/dist/chunk-4WGN6SUE.js +197 -0
- package/dist/chunk-4WGN6SUE.js.map +1 -0
- package/dist/{chunk-DHET7RCE.js → chunk-AWKZ5BDL.js} +9 -2
- package/dist/{chunk-DHET7RCE.js.map → chunk-AWKZ5BDL.js.map} +1 -1
- package/dist/{chunk-6Q3Y7KVB.js → chunk-DBRUQQUF.js} +8 -2
- package/dist/chunk-DBRUQQUF.js.map +1 -0
- package/dist/{chunk-OQYYMQJR.js → chunk-ETCVEV3S.js} +8 -11
- package/dist/chunk-ETCVEV3S.js.map +1 -0
- package/dist/{chunk-ZSVMS677.js → chunk-F4RD5FYM.js} +2 -2
- package/dist/chunk-F4RD5FYM.js.map +1 -0
- package/dist/{chunk-5KXUDHAB.js → chunk-GGFOD5PK.js} +6 -9
- package/dist/chunk-GGFOD5PK.js.map +1 -0
- package/dist/{chunk-UMORK7OK.js → chunk-H7SSBSPR.js} +2 -2
- package/dist/chunk-H7SSBSPR.js.map +1 -0
- package/dist/chunk-HWD32NP7.js +19 -0
- package/dist/chunk-HWD32NP7.js.map +1 -0
- package/dist/{chunk-HGCBZUH5.js → chunk-IAYAE6MG.js} +9 -10
- package/dist/chunk-IAYAE6MG.js.map +1 -0
- package/dist/{chunk-RTE64SJA.js → chunk-IXBCRT3F.js} +2 -2
- package/dist/chunk-IXBCRT3F.js.map +1 -0
- package/dist/{chunk-WFEFICFM.js → chunk-KWYO3M5Q.js} +5 -5
- package/dist/chunk-KWYO3M5Q.js.map +1 -0
- package/dist/{chunk-HEOHU5EZ.js → chunk-MCTSHLAF.js} +22 -11
- package/dist/chunk-MCTSHLAF.js.map +1 -0
- package/dist/chunk-MH66WDFV.js +251 -0
- package/dist/chunk-MH66WDFV.js.map +1 -0
- package/dist/{chunk-2LSGX6R4.js → chunk-MTPM7BX5.js} +83 -25
- package/dist/chunk-MTPM7BX5.js.map +1 -0
- package/dist/chunk-NQJ47R4N.js +1092 -0
- package/dist/chunk-NQJ47R4N.js.map +1 -0
- package/dist/chunk-NRC7XYCI.js +211 -0
- package/dist/chunk-NRC7XYCI.js.map +1 -0
- package/dist/{chunk-FJFEKPXF.js → chunk-O6ZTD7ZI.js} +14 -3
- package/dist/chunk-O6ZTD7ZI.js.map +1 -0
- package/dist/chunk-OBXAY23Y.js +56 -0
- package/dist/chunk-OBXAY23Y.js.map +1 -0
- package/dist/{chunk-XY3XDVMI.js → chunk-QR2EBWL2.js} +3 -3
- package/dist/{chunk-66UDJBF6.js → chunk-REJGRCVQ.js} +2 -2
- package/dist/{chunk-CBLPAMZO.js → chunk-TMED5DQ2.js} +68 -42
- package/dist/chunk-TMED5DQ2.js.map +1 -0
- package/dist/{chunk-Q3J43SF3.js → chunk-U7HFKR74.js} +2 -2
- package/dist/chunk-U7HFKR74.js.map +1 -0
- package/dist/{chunk-3EHUF54X.js → chunk-UEMRJI2K.js} +17 -4
- package/dist/chunk-UEMRJI2K.js.map +1 -0
- package/dist/{chunk-Z2CWURZ6.js → chunk-UNN7523L.js} +2 -2
- package/dist/chunk-V2ZIH7HV.js +29 -0
- package/dist/chunk-V2ZIH7HV.js.map +1 -0
- package/dist/{chunk-ZEI3ZUDU.js → chunk-VVYNZZUX.js} +7 -15
- package/dist/chunk-VVYNZZUX.js.map +1 -0
- package/dist/chunk-WXS4S3MA.js +220 -0
- package/dist/chunk-WXS4S3MA.js.map +1 -0
- package/dist/{chunk-A46TPNBJ.js → chunk-XENOESJZ.js} +7 -16
- package/dist/chunk-XENOESJZ.js.map +1 -0
- package/dist/chunk-YDBSSAJ6.js +4207 -0
- package/dist/chunk-YDBSSAJ6.js.map +1 -0
- package/dist/chunk-ZDREFYD2.js +696 -0
- package/dist/chunk-ZDREFYD2.js.map +1 -0
- package/dist/chunk-ZW2PELOH.js +197 -0
- package/dist/chunk-ZW2PELOH.js.map +1 -0
- package/dist/cli/defaults/agent-mappings.yaml +0 -1
- package/dist/commands/build/marketplace.js +15 -13
- package/dist/commands/build/marketplace.js.map +1 -1
- package/dist/commands/build/plugins.js +13 -229
- package/dist/commands/build/plugins.js.map +1 -1
- package/dist/commands/build/stack.js +11 -18
- package/dist/commands/build/stack.js.map +1 -1
- package/dist/commands/compile.js +36 -58
- package/dist/commands/compile.js.map +1 -1
- package/dist/commands/config/get.js +8 -8
- package/dist/commands/config/get.js.map +1 -1
- package/dist/commands/config/index.js +7 -7
- package/dist/commands/config/index.js.map +1 -1
- package/dist/commands/config/path.js +6 -6
- package/dist/commands/config/path.js.map +1 -1
- package/dist/commands/config/set-project.js +8 -8
- package/dist/commands/config/set-project.js.map +1 -1
- package/dist/commands/config/show.js +7 -7
- package/dist/commands/config/unset-project.js +8 -8
- package/dist/commands/config/unset-project.js.map +1 -1
- package/dist/commands/diff.js +10 -16
- package/dist/commands/diff.js.map +1 -1
- package/dist/commands/doctor.js +18 -51
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/edit.js +87 -57
- package/dist/commands/edit.js.map +1 -1
- package/dist/commands/eject.js +17 -49
- package/dist/commands/eject.js.map +1 -1
- package/dist/commands/import/skill.js +26 -26
- package/dist/commands/import/skill.js.map +1 -1
- package/dist/commands/info.js +15 -17
- package/dist/commands/info.js.map +1 -1
- package/dist/commands/init.js +45 -722
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/list.js +8 -87
- package/dist/commands/list.js.map +1 -1
- package/dist/commands/new/agent.js +8 -12
- package/dist/commands/new/agent.js.map +1 -1
- package/dist/commands/new/skill.js +6 -6
- package/dist/commands/new/skill.js.map +1 -1
- package/dist/commands/outdated.js +15 -19
- package/dist/commands/outdated.js.map +1 -1
- package/dist/commands/search.js +21 -34
- package/dist/commands/search.js.map +1 -1
- package/dist/commands/uninstall.js +15 -14
- package/dist/commands/uninstall.js.map +1 -1
- package/dist/commands/update.js +13 -24
- package/dist/commands/update.js.map +1 -1
- package/dist/commands/validate.js +44 -487
- package/dist/commands/validate.js.map +1 -1
- package/dist/commands/version/bump.js +11 -11
- package/dist/commands/version/bump.js.map +1 -1
- package/dist/commands/version/index.js +9 -10
- package/dist/commands/version/index.js.map +1 -1
- package/dist/commands/version/set.js +10 -8
- package/dist/commands/version/set.js.map +1 -1
- package/dist/commands/version/show.js +9 -10
- package/dist/commands/version/show.js.map +1 -1
- package/dist/components/common/confirm.js +2 -2
- package/dist/components/common/confirm.test.js +203 -0
- package/dist/components/common/confirm.test.js.map +1 -0
- package/dist/components/common/message.js +1 -1
- package/dist/components/common/spinner.js +1 -1
- package/dist/components/common/spinner.js.map +1 -1
- package/dist/components/skill-search/skill-search.js +3 -3
- package/dist/components/wizard/category-grid.js +2 -2
- package/dist/components/wizard/category-grid.test.js +132 -78
- package/dist/components/wizard/category-grid.test.js.map +1 -1
- package/dist/components/wizard/menu-item.js +2 -2
- package/dist/components/wizard/search-modal.js +9 -0
- package/dist/components/wizard/search-modal.js.map +1 -0
- package/dist/components/wizard/search-modal.test.js +216 -0
- package/dist/components/wizard/search-modal.test.js.map +1 -0
- package/dist/components/wizard/section-progress.js +2 -2
- package/dist/components/wizard/section-progress.test.js +4 -4
- package/dist/components/wizard/section-progress.test.js.map +1 -1
- package/dist/components/wizard/source-grid.js +10 -0
- package/dist/components/wizard/source-grid.js.map +1 -0
- package/dist/components/wizard/source-grid.test.js +500 -0
- package/dist/components/wizard/source-grid.test.js.map +1 -0
- package/dist/components/wizard/step-approach.js +7 -6
- package/dist/components/wizard/step-approach.test.js +115 -0
- package/dist/components/wizard/step-approach.test.js.map +1 -0
- package/dist/components/wizard/step-build.js +9 -4
- package/dist/components/wizard/step-build.test.js +103 -122
- package/dist/components/wizard/step-build.test.js.map +1 -1
- package/dist/components/wizard/step-confirm.js +3 -2
- package/dist/components/wizard/step-confirm.test.js +364 -0
- package/dist/components/wizard/step-confirm.test.js.map +1 -0
- package/dist/components/wizard/step-refine.js +2 -2
- package/dist/components/wizard/step-refine.test.js +19 -13
- package/dist/components/wizard/step-refine.test.js.map +1 -1
- package/dist/components/wizard/step-settings.js +14 -0
- package/dist/components/wizard/step-settings.js.map +1 -0
- package/dist/components/wizard/step-settings.test.js +240 -0
- package/dist/components/wizard/step-settings.test.js.map +1 -0
- package/dist/components/wizard/step-sources.js +17 -0
- package/dist/components/wizard/step-sources.js.map +1 -0
- package/dist/components/wizard/step-sources.test.js +290 -0
- package/dist/components/wizard/step-sources.test.js.map +1 -0
- package/dist/components/wizard/step-stack.js +7 -6
- package/dist/components/wizard/step-stack.test.js +344 -0
- package/dist/components/wizard/step-stack.test.js.map +1 -0
- package/dist/components/wizard/view-title.js +2 -2
- package/dist/components/wizard/wizard-layout.js +6 -5
- package/dist/components/wizard/wizard-tabs.js +2 -2
- package/dist/components/wizard/wizard-tabs.test.js +292 -0
- package/dist/components/wizard/wizard-tabs.test.js.map +1 -0
- package/dist/components/wizard/wizard.js +22 -14
- package/dist/config/skills-matrix.yaml +38 -37
- package/dist/config/stacks.yaml +8 -14
- package/dist/hooks/init.js +5 -5
- package/dist/hooks/init.js.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/{magic-string.es-RGXYGAW3.js → magic-string.es-PAH2SOTR.js} +2 -2
- package/dist/source-manager-DSYZEVGZ.js +16 -0
- package/dist/source-manager-DSYZEVGZ.js.map +1 -0
- package/dist/src/agents/developer/api-developer/agent.yaml +1 -1
- package/dist/src/agents/developer/cli-developer/agent.yaml +1 -1
- package/dist/src/agents/developer/web-architecture/agent.yaml +1 -1
- package/dist/src/agents/developer/web-developer/agent.yaml +1 -1
- package/dist/src/agents/meta/agent-summoner/agent.yaml +1 -1
- package/dist/src/agents/meta/documentor/agent.yaml +1 -1
- package/dist/src/agents/meta/skill-summoner/agent.yaml +1 -1
- package/dist/src/agents/migration/cli-migrator/agent.yaml +1 -1
- package/dist/src/agents/pattern/pattern-scout/agent.yaml +1 -1
- package/dist/src/agents/pattern/web-pattern-critique/agent.yaml +1 -1
- package/dist/src/agents/planning/web-pm/agent.yaml +1 -1
- package/dist/src/agents/researcher/api-researcher/agent.yaml +1 -1
- package/dist/src/agents/researcher/web-researcher/agent.yaml +1 -1
- package/dist/src/agents/reviewer/api-reviewer/agent.yaml +1 -1
- package/dist/src/agents/reviewer/cli-reviewer/agent.yaml +1 -1
- package/dist/src/agents/reviewer/web-reviewer/agent.yaml +1 -1
- package/dist/src/agents/tester/cli-tester/agent.yaml +1 -1
- package/dist/src/agents/tester/web-tester/agent.yaml +1 -1
- package/dist/stores/wizard-store.js +4 -3
- package/dist/stores/wizard-store.test.js +51 -82
- package/dist/stores/wizard-store.test.js.map +1 -1
- package/package.json +5 -3
- package/src/agents/developer/api-developer/agent.yaml +1 -1
- package/src/agents/developer/cli-developer/agent.yaml +1 -1
- package/src/agents/developer/web-architecture/agent.yaml +1 -1
- package/src/agents/developer/web-developer/agent.yaml +1 -1
- package/src/agents/meta/agent-summoner/agent.yaml +1 -1
- package/src/agents/meta/documentor/agent.yaml +1 -1
- package/src/agents/meta/skill-summoner/agent.yaml +1 -1
- package/src/agents/migration/cli-migrator/agent.yaml +1 -1
- package/src/agents/pattern/pattern-scout/agent.yaml +1 -1
- package/src/agents/pattern/web-pattern-critique/agent.yaml +1 -1
- package/src/agents/planning/web-pm/agent.yaml +1 -1
- package/src/agents/researcher/api-researcher/agent.yaml +1 -1
- package/src/agents/researcher/web-researcher/agent.yaml +1 -1
- package/src/agents/reviewer/api-reviewer/agent.yaml +1 -1
- package/src/agents/reviewer/cli-reviewer/agent.yaml +1 -1
- package/src/agents/reviewer/web-reviewer/agent.yaml +1 -1
- package/src/agents/tester/cli-tester/agent.yaml +1 -1
- package/src/agents/tester/web-tester/agent.yaml +1 -1
- package/dist/chunk-2LSGX6R4.js.map +0 -1
- package/dist/chunk-2OKUEELH.js +0 -32
- package/dist/chunk-2OKUEELH.js.map +0 -1
- package/dist/chunk-374JNMR6.js +0 -212
- package/dist/chunk-374JNMR6.js.map +0 -1
- package/dist/chunk-3EHUF54X.js.map +0 -1
- package/dist/chunk-3XR4PALU.js +0 -529
- package/dist/chunk-3XR4PALU.js.map +0 -1
- package/dist/chunk-5K2ZLUO5.js +0 -57
- package/dist/chunk-5K2ZLUO5.js.map +0 -1
- package/dist/chunk-5KXUDHAB.js.map +0 -1
- package/dist/chunk-6Q3Y7KVB.js.map +0 -1
- package/dist/chunk-7SLV7CMF.js +0 -615
- package/dist/chunk-7SLV7CMF.js.map +0 -1
- package/dist/chunk-A46TPNBJ.js.map +0 -1
- package/dist/chunk-AL74GBW4.js +0 -69
- package/dist/chunk-AL74GBW4.js.map +0 -1
- package/dist/chunk-BQX23RBV.js +0 -191
- package/dist/chunk-BQX23RBV.js.map +0 -1
- package/dist/chunk-CA4LH4LI.js +0 -132
- package/dist/chunk-CA4LH4LI.js.map +0 -1
- package/dist/chunk-CBLPAMZO.js.map +0 -1
- package/dist/chunk-CKPQHGXR.js +0 -417
- package/dist/chunk-CKPQHGXR.js.map +0 -1
- package/dist/chunk-CXOFOJCN.js +0 -80
- package/dist/chunk-CXOFOJCN.js.map +0 -1
- package/dist/chunk-EHGD7HIE.js +0 -104
- package/dist/chunk-EHGD7HIE.js.map +0 -1
- package/dist/chunk-EHS3TWWP.js +0 -95
- package/dist/chunk-EHS3TWWP.js.map +0 -1
- package/dist/chunk-FJFEKPXF.js.map +0 -1
- package/dist/chunk-HEOHU5EZ.js.map +0 -1
- package/dist/chunk-HGCBZUH5.js.map +0 -1
- package/dist/chunk-HPGFY5ZN.js +0 -114
- package/dist/chunk-HPGFY5ZN.js.map +0 -1
- package/dist/chunk-INJ2EFRW.js +0 -127
- package/dist/chunk-INJ2EFRW.js.map +0 -1
- package/dist/chunk-IOBFMF6X.js +0 -61
- package/dist/chunk-IOBFMF6X.js.map +0 -1
- package/dist/chunk-KH3HA7J7.js +0 -116
- package/dist/chunk-KH3HA7J7.js.map +0 -1
- package/dist/chunk-N6JNE326.js +0 -261
- package/dist/chunk-N6JNE326.js.map +0 -1
- package/dist/chunk-NAGU7TVZ.js +0 -36
- package/dist/chunk-NAGU7TVZ.js.map +0 -1
- package/dist/chunk-OQYYMQJR.js.map +0 -1
- package/dist/chunk-PLZOUVDD.js +0 -419
- package/dist/chunk-PLZOUVDD.js.map +0 -1
- package/dist/chunk-Q3J43SF3.js.map +0 -1
- package/dist/chunk-RTE64SJA.js.map +0 -1
- package/dist/chunk-T25OEQFI.js +0 -26
- package/dist/chunk-T25OEQFI.js.map +0 -1
- package/dist/chunk-UMORK7OK.js.map +0 -1
- package/dist/chunk-VFHWU7JU.js +0 -287
- package/dist/chunk-VFHWU7JU.js.map +0 -1
- package/dist/chunk-VS4GVTZE.js +0 -91
- package/dist/chunk-VS4GVTZE.js.map +0 -1
- package/dist/chunk-WFEFICFM.js.map +0 -1
- package/dist/chunk-WG6KIAPK.js +0 -54
- package/dist/chunk-WG6KIAPK.js.map +0 -1
- package/dist/chunk-ZEI3ZUDU.js.map +0 -1
- package/dist/chunk-ZNIDWLL5.js.map +0 -1
- package/dist/chunk-ZSVMS677.js.map +0 -1
- /package/dist/{chunk-XY3XDVMI.js.map → chunk-QR2EBWL2.js.map} +0 -0
- /package/dist/{chunk-66UDJBF6.js.map → chunk-REJGRCVQ.js.map} +0 -0
- /package/dist/{chunk-Z2CWURZ6.js.map → chunk-UNN7523L.js.map} +0 -0
- /package/dist/{magic-string.es-RGXYGAW3.js.map → magic-string.es-PAH2SOTR.js.map} +0 -0
|
@@ -2,146 +2,95 @@
|
|
|
2
2
|
import {
|
|
3
3
|
BaseCommand,
|
|
4
4
|
EXIT_CODES
|
|
5
|
-
} from "../chunk-
|
|
5
|
+
} from "../chunk-OBXAY23Y.js";
|
|
6
6
|
import {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
} from "../chunk-
|
|
7
|
+
extractFrontmatter,
|
|
8
|
+
printPluginValidationResult,
|
|
9
|
+
validateAllPlugins,
|
|
10
|
+
validatePlugin
|
|
11
|
+
} from "../chunk-YDBSSAJ6.js";
|
|
12
12
|
import {
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
agentYamlGenerationSchema,
|
|
14
|
+
fileExists,
|
|
15
|
+
metadataValidationSchema,
|
|
16
|
+
readFile,
|
|
17
|
+
skillFrontmatterValidationSchema,
|
|
18
|
+
skillsMatrixConfigSchema,
|
|
19
|
+
stackConfigValidationSchema
|
|
20
|
+
} from "../chunk-ZDREFYD2.js";
|
|
21
|
+
import "../chunk-HWD32NP7.js";
|
|
22
|
+
import "../chunk-O6ZTD7ZI.js";
|
|
15
23
|
import {
|
|
16
24
|
init_esm_shims
|
|
17
|
-
} from "../chunk-
|
|
25
|
+
} from "../chunk-AWKZ5BDL.js";
|
|
18
26
|
|
|
19
27
|
// src/cli/commands/validate.ts
|
|
20
28
|
init_esm_shims();
|
|
21
29
|
import { Args, Flags } from "@oclif/core";
|
|
22
|
-
import
|
|
30
|
+
import path2 from "path";
|
|
23
31
|
|
|
24
32
|
// src/cli/lib/schema-validator.ts
|
|
25
33
|
init_esm_shims();
|
|
26
|
-
import
|
|
27
|
-
import addFormats from "ajv-formats";
|
|
34
|
+
import { sumBy } from "remeda";
|
|
28
35
|
import path from "path";
|
|
29
|
-
import { parse as parseYaml2 } from "yaml";
|
|
30
|
-
import fg from "fast-glob";
|
|
31
|
-
|
|
32
|
-
// src/cli/utils/frontmatter.ts
|
|
33
|
-
init_esm_shims();
|
|
34
36
|
import { parse as parseYaml } from "yaml";
|
|
35
|
-
|
|
36
|
-
const frontmatterRegex = /^---\r?\n([\s\S]*?)\r?\n---/;
|
|
37
|
-
const match = content.match(frontmatterRegex);
|
|
38
|
-
if (!match || !match[1]) {
|
|
39
|
-
return null;
|
|
40
|
-
}
|
|
41
|
-
try {
|
|
42
|
-
return parseYaml(match[1]);
|
|
43
|
-
} catch {
|
|
44
|
-
return null;
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
// src/cli/lib/schema-validator.ts
|
|
37
|
+
import fg from "fast-glob";
|
|
49
38
|
var VALIDATION_TARGETS = [
|
|
50
39
|
{
|
|
51
40
|
name: "Skills Matrix",
|
|
52
|
-
schema:
|
|
41
|
+
schema: skillsMatrixConfigSchema,
|
|
53
42
|
pattern: "skills-matrix.yaml",
|
|
54
43
|
baseDir: "src/config"
|
|
55
44
|
},
|
|
56
45
|
{
|
|
57
46
|
name: "Skill Metadata",
|
|
58
|
-
schema:
|
|
47
|
+
schema: metadataValidationSchema,
|
|
59
48
|
pattern: "**/metadata.yaml",
|
|
60
49
|
baseDir: "src/skills"
|
|
61
50
|
},
|
|
62
51
|
{
|
|
63
52
|
name: "Stack Skill Metadata",
|
|
64
|
-
schema:
|
|
53
|
+
schema: metadataValidationSchema,
|
|
65
54
|
pattern: "**/skills/**/metadata.yaml",
|
|
66
55
|
baseDir: "src/stacks"
|
|
67
56
|
},
|
|
68
57
|
{
|
|
69
58
|
name: "Stack Config",
|
|
70
|
-
schema:
|
|
59
|
+
schema: stackConfigValidationSchema,
|
|
71
60
|
pattern: "*/config.yaml",
|
|
72
61
|
baseDir: "src/stacks"
|
|
73
62
|
},
|
|
74
63
|
{
|
|
75
64
|
name: "Agent Definition",
|
|
76
|
-
schema:
|
|
65
|
+
schema: agentYamlGenerationSchema,
|
|
77
66
|
pattern: "**/agent.yaml",
|
|
78
67
|
baseDir: "src/agents"
|
|
79
68
|
},
|
|
80
69
|
{
|
|
81
70
|
name: "Skill Frontmatter",
|
|
82
|
-
schema:
|
|
71
|
+
schema: skillFrontmatterValidationSchema,
|
|
83
72
|
pattern: "**/SKILL.md",
|
|
84
73
|
baseDir: "src/skills",
|
|
85
74
|
extractor: extractFrontmatter
|
|
86
75
|
},
|
|
87
76
|
{
|
|
88
77
|
name: "Stack Skill Frontmatter",
|
|
89
|
-
schema:
|
|
78
|
+
schema: skillFrontmatterValidationSchema,
|
|
90
79
|
pattern: "**/skills/**/SKILL.md",
|
|
91
80
|
baseDir: "src/stacks",
|
|
92
81
|
extractor: extractFrontmatter
|
|
93
82
|
}
|
|
94
83
|
];
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
return schemaCache.get(cacheKey);
|
|
101
|
-
}
|
|
102
|
-
const locations = [
|
|
103
|
-
path.join(PROJECT_ROOT, "src", "schemas", schemaName),
|
|
104
|
-
path.join(rootDir, "src", "schemas", schemaName)
|
|
105
|
-
];
|
|
106
|
-
for (const schemaPath of locations) {
|
|
107
|
-
if (await fileExists(schemaPath)) {
|
|
108
|
-
const content = await readFile(schemaPath);
|
|
109
|
-
const schema = JSON.parse(content);
|
|
110
|
-
schemaCache.set(cacheKey, schema);
|
|
111
|
-
return schema;
|
|
84
|
+
function formatZodErrors(error) {
|
|
85
|
+
return error.issues.map((issue) => {
|
|
86
|
+
const path3 = issue.path.join(".");
|
|
87
|
+
if (issue.code === "unrecognized_keys") {
|
|
88
|
+
return `Unrecognized key: "${issue.keys.join('", "')}"`;
|
|
112
89
|
}
|
|
113
|
-
|
|
114
|
-
throw new Error(`Schema not found: ${schemaName}. Searched: ${locations.join(", ")}`);
|
|
115
|
-
}
|
|
116
|
-
async function getValidator(schemaName, rootDir = process.cwd()) {
|
|
117
|
-
const cacheKey = `${rootDir}:${schemaName}`;
|
|
118
|
-
if (validatorCache.has(cacheKey)) {
|
|
119
|
-
return validatorCache.get(cacheKey);
|
|
120
|
-
}
|
|
121
|
-
const ajv = new Ajv({ allErrors: true, strict: false });
|
|
122
|
-
addFormats(ajv);
|
|
123
|
-
const schema = await loadSchema(schemaName, rootDir);
|
|
124
|
-
const validate = ajv.compile(schema);
|
|
125
|
-
validatorCache.set(cacheKey, validate);
|
|
126
|
-
return validate;
|
|
127
|
-
}
|
|
128
|
-
function formatAjvErrors(errors) {
|
|
129
|
-
if (!errors) return [];
|
|
130
|
-
return errors.map((err) => {
|
|
131
|
-
const errorPath = err.instancePath ? err.instancePath.replace(/^\//, "").replace(/\//g, ".") : "";
|
|
132
|
-
const message = err.message || "Unknown error";
|
|
133
|
-
if (err.keyword === "additionalProperties") {
|
|
134
|
-
const prop = err.params.additionalProperty;
|
|
135
|
-
return `Unrecognized key: "${prop}"`;
|
|
136
|
-
}
|
|
137
|
-
if (err.keyword === "enum") {
|
|
138
|
-
const allowed = err.params.allowedValues;
|
|
139
|
-
return errorPath ? `${errorPath}: ${message}. Allowed: ${allowed?.join(", ")}` : `${message}. Allowed: ${allowed?.join(", ")}`;
|
|
140
|
-
}
|
|
141
|
-
return errorPath ? `${errorPath}: ${message}` : message;
|
|
90
|
+
return path3 ? `${path3}: ${issue.message}` : issue.message;
|
|
142
91
|
});
|
|
143
92
|
}
|
|
144
|
-
async function validateFile(filePath,
|
|
93
|
+
async function validateFile(filePath, schema, extractor) {
|
|
145
94
|
try {
|
|
146
95
|
if (!await fileExists(filePath)) {
|
|
147
96
|
return { valid: false, errors: [`File not found: ${filePath}`] };
|
|
@@ -157,13 +106,13 @@ async function validateFile(filePath, validate, extractor) {
|
|
|
157
106
|
};
|
|
158
107
|
}
|
|
159
108
|
} else {
|
|
160
|
-
parsed =
|
|
109
|
+
parsed = parseYaml(content);
|
|
161
110
|
}
|
|
162
|
-
const
|
|
163
|
-
if (
|
|
111
|
+
const result = schema.safeParse(parsed);
|
|
112
|
+
if (result.success) {
|
|
164
113
|
return { valid: true, errors: [] };
|
|
165
114
|
}
|
|
166
|
-
return { valid: false, errors:
|
|
115
|
+
return { valid: false, errors: formatZodErrors(result.error) };
|
|
167
116
|
} catch (error) {
|
|
168
117
|
const message = error instanceof Error ? error.message : String(error);
|
|
169
118
|
return { valid: false, errors: [`Failed to parse content: ${message}`] };
|
|
@@ -183,9 +132,8 @@ async function validateTarget(target, rootDir = process.cwd()) {
|
|
|
183
132
|
if (files.length === 0) {
|
|
184
133
|
return result;
|
|
185
134
|
}
|
|
186
|
-
const validate = await getValidator(target.schema, rootDir);
|
|
187
135
|
for (const file of files) {
|
|
188
|
-
const validation = await validateFile(file,
|
|
136
|
+
const validation = await validateFile(file, target.schema, target.extractor);
|
|
189
137
|
const relativePath = path.relative(rootDir, file);
|
|
190
138
|
if (validation.valid) {
|
|
191
139
|
result.validFiles++;
|
|
@@ -207,9 +155,9 @@ async function validateAllSchemas(rootDir = process.cwd()) {
|
|
|
207
155
|
}
|
|
208
156
|
const summary = {
|
|
209
157
|
totalSchemas: results.length,
|
|
210
|
-
totalFiles: results
|
|
211
|
-
validFiles: results
|
|
212
|
-
invalidFiles: results
|
|
158
|
+
totalFiles: sumBy(results, (r) => r.totalFiles),
|
|
159
|
+
validFiles: sumBy(results, (r) => r.validFiles),
|
|
160
|
+
invalidFiles: sumBy(results, (r) => r.invalidFiles.length)
|
|
213
161
|
};
|
|
214
162
|
return {
|
|
215
163
|
valid: results.every((r) => r.valid),
|
|
@@ -251,397 +199,6 @@ function printValidationResults(result) {
|
|
|
251
199
|
}
|
|
252
200
|
}
|
|
253
201
|
|
|
254
|
-
// src/cli/lib/plugin-validator.ts
|
|
255
|
-
init_esm_shims();
|
|
256
|
-
import Ajv2 from "ajv";
|
|
257
|
-
import addFormats2 from "ajv-formats";
|
|
258
|
-
import path2 from "path";
|
|
259
|
-
import fg2 from "fast-glob";
|
|
260
|
-
var PLUGIN_DIR = ".claude-plugin";
|
|
261
|
-
var PLUGIN_MANIFEST = "plugin.json";
|
|
262
|
-
var KEBAB_CASE_REGEX = /^[a-z][a-z0-9]*(-[a-z0-9]+)*$/;
|
|
263
|
-
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-]+)*))?$/;
|
|
264
|
-
var schemaCache2 = /* @__PURE__ */ new Map();
|
|
265
|
-
var validatorCache2 = /* @__PURE__ */ new Map();
|
|
266
|
-
var REMOTE_SCHEMAS = {
|
|
267
|
-
"skill-frontmatter.schema.json": "https://raw.githubusercontent.com/claude-collective/skills/main/src/schemas/skill-frontmatter.schema.json"
|
|
268
|
-
};
|
|
269
|
-
async function loadSchema2(schemaName) {
|
|
270
|
-
if (schemaCache2.has(schemaName)) {
|
|
271
|
-
return schemaCache2.get(schemaName);
|
|
272
|
-
}
|
|
273
|
-
const locations = [
|
|
274
|
-
path2.join(PROJECT_ROOT, "src", "schemas", schemaName),
|
|
275
|
-
path2.join(process.cwd(), "src", "schemas", schemaName)
|
|
276
|
-
];
|
|
277
|
-
for (const schemaPath of locations) {
|
|
278
|
-
if (await fileExists(schemaPath)) {
|
|
279
|
-
const content = await readFile(schemaPath);
|
|
280
|
-
const schema = JSON.parse(content);
|
|
281
|
-
schemaCache2.set(schemaName, schema);
|
|
282
|
-
return schema;
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
const remoteUrl = REMOTE_SCHEMAS[schemaName];
|
|
286
|
-
if (remoteUrl) {
|
|
287
|
-
try {
|
|
288
|
-
const response = await fetch(remoteUrl);
|
|
289
|
-
if (response.ok) {
|
|
290
|
-
const schema = await response.json();
|
|
291
|
-
schemaCache2.set(schemaName, schema);
|
|
292
|
-
return schema;
|
|
293
|
-
}
|
|
294
|
-
} catch {
|
|
295
|
-
}
|
|
296
|
-
}
|
|
297
|
-
throw new Error(
|
|
298
|
-
`Schema not found: ${schemaName}. Searched: ${locations.join(", ")}${remoteUrl ? ` and ${remoteUrl}` : ""}`
|
|
299
|
-
);
|
|
300
|
-
}
|
|
301
|
-
async function getValidator2(schemaName) {
|
|
302
|
-
if (validatorCache2.has(schemaName)) {
|
|
303
|
-
return validatorCache2.get(schemaName);
|
|
304
|
-
}
|
|
305
|
-
const ajv = new Ajv2({ allErrors: true, strict: false });
|
|
306
|
-
addFormats2(ajv);
|
|
307
|
-
const schema = await loadSchema2(schemaName);
|
|
308
|
-
const validate = ajv.compile(schema);
|
|
309
|
-
validatorCache2.set(schemaName, validate);
|
|
310
|
-
return validate;
|
|
311
|
-
}
|
|
312
|
-
function formatAjvErrors2(errors) {
|
|
313
|
-
if (!errors) return [];
|
|
314
|
-
return errors.map((err) => {
|
|
315
|
-
const errorPath = err.instancePath ? err.instancePath.replace(/^\//, "").replace(/\//g, ".") : "";
|
|
316
|
-
const message = err.message || "Unknown error";
|
|
317
|
-
if (err.keyword === "additionalProperties") {
|
|
318
|
-
const prop = err.params.additionalProperty;
|
|
319
|
-
return `Unrecognized key: "${prop}"`;
|
|
320
|
-
}
|
|
321
|
-
if (err.keyword === "enum") {
|
|
322
|
-
const allowed = err.params.allowedValues;
|
|
323
|
-
return errorPath ? `${errorPath}: ${message}. Allowed: ${allowed?.join(", ")}` : `${message}. Allowed: ${allowed?.join(", ")}`;
|
|
324
|
-
}
|
|
325
|
-
if (err.keyword === "pattern") {
|
|
326
|
-
let hint = "";
|
|
327
|
-
if (errorPath === "name") {
|
|
328
|
-
hint = " (must be kebab-case)";
|
|
329
|
-
} else if (errorPath === "version") {
|
|
330
|
-
hint = " (must be semver: x.y.z)";
|
|
331
|
-
}
|
|
332
|
-
return errorPath ? `${errorPath}: ${message}${hint}` : `${message}${hint}`;
|
|
333
|
-
}
|
|
334
|
-
return errorPath ? `${errorPath}: ${message}` : message;
|
|
335
|
-
});
|
|
336
|
-
}
|
|
337
|
-
function isKebabCase(str) {
|
|
338
|
-
return KEBAB_CASE_REGEX.test(str);
|
|
339
|
-
}
|
|
340
|
-
function isValidSemver(str) {
|
|
341
|
-
return SEMVER_REGEX.test(str);
|
|
342
|
-
}
|
|
343
|
-
async function validatePluginStructure(pluginPath) {
|
|
344
|
-
const errors = [];
|
|
345
|
-
const warnings = [];
|
|
346
|
-
if (!await directoryExists(pluginPath)) {
|
|
347
|
-
return {
|
|
348
|
-
valid: false,
|
|
349
|
-
errors: [`Plugin directory does not exist: ${pluginPath}`],
|
|
350
|
-
warnings: []
|
|
351
|
-
};
|
|
352
|
-
}
|
|
353
|
-
const pluginDir = path2.join(pluginPath, PLUGIN_DIR);
|
|
354
|
-
if (!await directoryExists(pluginDir)) {
|
|
355
|
-
errors.push(`Missing ${PLUGIN_DIR}/ directory`);
|
|
356
|
-
}
|
|
357
|
-
const manifestPath = path2.join(pluginDir, PLUGIN_MANIFEST);
|
|
358
|
-
if (!await fileExists(manifestPath)) {
|
|
359
|
-
errors.push(`Missing ${PLUGIN_DIR}/${PLUGIN_MANIFEST}`);
|
|
360
|
-
}
|
|
361
|
-
const readmePath = path2.join(pluginPath, "README.md");
|
|
362
|
-
if (!await fileExists(readmePath)) {
|
|
363
|
-
warnings.push("Missing README.md (recommended for documentation)");
|
|
364
|
-
}
|
|
365
|
-
return {
|
|
366
|
-
valid: errors.length === 0,
|
|
367
|
-
errors,
|
|
368
|
-
warnings
|
|
369
|
-
};
|
|
370
|
-
}
|
|
371
|
-
async function validatePluginManifest(manifestPath) {
|
|
372
|
-
const errors = [];
|
|
373
|
-
const warnings = [];
|
|
374
|
-
if (!await fileExists(manifestPath)) {
|
|
375
|
-
return {
|
|
376
|
-
valid: false,
|
|
377
|
-
errors: [`Manifest file not found: ${manifestPath}`],
|
|
378
|
-
warnings: []
|
|
379
|
-
};
|
|
380
|
-
}
|
|
381
|
-
let manifest;
|
|
382
|
-
try {
|
|
383
|
-
const content = await readFile(manifestPath);
|
|
384
|
-
manifest = JSON.parse(content);
|
|
385
|
-
} catch (err) {
|
|
386
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
387
|
-
return {
|
|
388
|
-
valid: false,
|
|
389
|
-
errors: [`Invalid JSON in ${PLUGIN_MANIFEST}: ${message}`],
|
|
390
|
-
warnings: []
|
|
391
|
-
};
|
|
392
|
-
}
|
|
393
|
-
const validate = await getValidator2("plugin.schema.json");
|
|
394
|
-
const isValid = validate(manifest);
|
|
395
|
-
if (!isValid) {
|
|
396
|
-
errors.push(...formatAjvErrors2(validate.errors));
|
|
397
|
-
}
|
|
398
|
-
if (manifest.name && typeof manifest.name === "string") {
|
|
399
|
-
if (!isKebabCase(manifest.name)) {
|
|
400
|
-
errors.push(`name must be kebab-case: "${manifest.name}"`);
|
|
401
|
-
}
|
|
402
|
-
}
|
|
403
|
-
if (manifest.version && typeof manifest.version === "string") {
|
|
404
|
-
if (!isValidSemver(manifest.version)) {
|
|
405
|
-
warnings.push(
|
|
406
|
-
`version "${manifest.version}" is not valid semver (expected: major.minor.patch)`
|
|
407
|
-
);
|
|
408
|
-
}
|
|
409
|
-
}
|
|
410
|
-
if (!manifest.description) {
|
|
411
|
-
warnings.push("Missing description field (recommended for discoverability)");
|
|
412
|
-
}
|
|
413
|
-
const pluginDir = path2.dirname(path2.dirname(manifestPath));
|
|
414
|
-
if (manifest.skills && typeof manifest.skills === "string") {
|
|
415
|
-
const skillsPath = path2.join(pluginDir, manifest.skills);
|
|
416
|
-
if (!await directoryExists(skillsPath)) {
|
|
417
|
-
errors.push(`Skills path does not exist: ${manifest.skills}`);
|
|
418
|
-
}
|
|
419
|
-
}
|
|
420
|
-
if (manifest.agents && typeof manifest.agents === "string") {
|
|
421
|
-
const agentsPath = path2.join(pluginDir, manifest.agents);
|
|
422
|
-
if (!await directoryExists(agentsPath)) {
|
|
423
|
-
errors.push(`Agents path does not exist: ${manifest.agents}`);
|
|
424
|
-
}
|
|
425
|
-
}
|
|
426
|
-
return {
|
|
427
|
-
valid: errors.length === 0,
|
|
428
|
-
errors,
|
|
429
|
-
warnings
|
|
430
|
-
};
|
|
431
|
-
}
|
|
432
|
-
async function validateSkillFrontmatter(skillPath) {
|
|
433
|
-
const errors = [];
|
|
434
|
-
const warnings = [];
|
|
435
|
-
if (!await fileExists(skillPath)) {
|
|
436
|
-
return {
|
|
437
|
-
valid: false,
|
|
438
|
-
errors: [`Skill file not found: ${skillPath}`],
|
|
439
|
-
warnings: []
|
|
440
|
-
};
|
|
441
|
-
}
|
|
442
|
-
const content = await readFile(skillPath);
|
|
443
|
-
const frontmatter = extractFrontmatter(content);
|
|
444
|
-
if (frontmatter === null) {
|
|
445
|
-
return {
|
|
446
|
-
valid: false,
|
|
447
|
-
errors: ["Missing or invalid YAML frontmatter"],
|
|
448
|
-
warnings: []
|
|
449
|
-
};
|
|
450
|
-
}
|
|
451
|
-
const validate = await getValidator2("skill-frontmatter.schema.json");
|
|
452
|
-
const isValid = validate(frontmatter);
|
|
453
|
-
if (!isValid) {
|
|
454
|
-
errors.push(...formatAjvErrors2(validate.errors));
|
|
455
|
-
}
|
|
456
|
-
return {
|
|
457
|
-
valid: errors.length === 0,
|
|
458
|
-
errors,
|
|
459
|
-
warnings
|
|
460
|
-
};
|
|
461
|
-
}
|
|
462
|
-
async function validateAgentFrontmatter(agentPath) {
|
|
463
|
-
const errors = [];
|
|
464
|
-
const warnings = [];
|
|
465
|
-
if (!await fileExists(agentPath)) {
|
|
466
|
-
return {
|
|
467
|
-
valid: false,
|
|
468
|
-
errors: [`Agent file not found: ${agentPath}`],
|
|
469
|
-
warnings: []
|
|
470
|
-
};
|
|
471
|
-
}
|
|
472
|
-
const content = await readFile(agentPath);
|
|
473
|
-
const frontmatter = extractFrontmatter(content);
|
|
474
|
-
if (frontmatter === null) {
|
|
475
|
-
return {
|
|
476
|
-
valid: false,
|
|
477
|
-
errors: ["Missing or invalid YAML frontmatter"],
|
|
478
|
-
warnings: []
|
|
479
|
-
};
|
|
480
|
-
}
|
|
481
|
-
const validate = await getValidator2("agent-frontmatter.schema.json");
|
|
482
|
-
const isValid = validate(frontmatter);
|
|
483
|
-
if (!isValid) {
|
|
484
|
-
errors.push(...formatAjvErrors2(validate.errors));
|
|
485
|
-
}
|
|
486
|
-
const fm = frontmatter;
|
|
487
|
-
if (fm.name && typeof fm.name === "string") {
|
|
488
|
-
if (!isKebabCase(fm.name)) {
|
|
489
|
-
errors.push(`name must be kebab-case: "${fm.name}"`);
|
|
490
|
-
}
|
|
491
|
-
}
|
|
492
|
-
return {
|
|
493
|
-
valid: errors.length === 0,
|
|
494
|
-
errors,
|
|
495
|
-
warnings
|
|
496
|
-
};
|
|
497
|
-
}
|
|
498
|
-
async function validatePlugin(pluginPath) {
|
|
499
|
-
const errors = [];
|
|
500
|
-
const warnings = [];
|
|
501
|
-
const structureResult = await validatePluginStructure(pluginPath);
|
|
502
|
-
errors.push(...structureResult.errors);
|
|
503
|
-
warnings.push(...structureResult.warnings);
|
|
504
|
-
if (!structureResult.valid) {
|
|
505
|
-
return { valid: false, errors, warnings };
|
|
506
|
-
}
|
|
507
|
-
const manifestPath = path2.join(pluginPath, PLUGIN_DIR, PLUGIN_MANIFEST);
|
|
508
|
-
const manifestResult = await validatePluginManifest(manifestPath);
|
|
509
|
-
errors.push(...manifestResult.errors);
|
|
510
|
-
warnings.push(...manifestResult.warnings);
|
|
511
|
-
let manifest = null;
|
|
512
|
-
try {
|
|
513
|
-
const content = await readFile(manifestPath);
|
|
514
|
-
manifest = JSON.parse(content);
|
|
515
|
-
} catch {
|
|
516
|
-
}
|
|
517
|
-
if (manifest) {
|
|
518
|
-
if (manifest.skills && typeof manifest.skills === "string") {
|
|
519
|
-
const skillsDir = path2.join(pluginPath, manifest.skills);
|
|
520
|
-
if (await directoryExists(skillsDir)) {
|
|
521
|
-
const skillFiles = await fg2("**/SKILL.md", {
|
|
522
|
-
cwd: skillsDir,
|
|
523
|
-
absolute: true
|
|
524
|
-
});
|
|
525
|
-
if (skillFiles.length === 0) {
|
|
526
|
-
warnings.push(
|
|
527
|
-
`Skills directory exists but contains no SKILL.md files: ${manifest.skills}`
|
|
528
|
-
);
|
|
529
|
-
}
|
|
530
|
-
for (const skillFile of skillFiles) {
|
|
531
|
-
const relativePath = path2.relative(pluginPath, skillFile);
|
|
532
|
-
const skillResult = await validateSkillFrontmatter(skillFile);
|
|
533
|
-
if (!skillResult.valid) {
|
|
534
|
-
errors.push(...skillResult.errors.map((e) => `${relativePath}: ${e}`));
|
|
535
|
-
}
|
|
536
|
-
warnings.push(...skillResult.warnings.map((w) => `${relativePath}: ${w}`));
|
|
537
|
-
}
|
|
538
|
-
}
|
|
539
|
-
}
|
|
540
|
-
if (manifest.agents && typeof manifest.agents === "string") {
|
|
541
|
-
const agentsDir = path2.join(pluginPath, manifest.agents);
|
|
542
|
-
if (await directoryExists(agentsDir)) {
|
|
543
|
-
const agentFiles = await fg2("*.md", {
|
|
544
|
-
cwd: agentsDir,
|
|
545
|
-
absolute: true
|
|
546
|
-
});
|
|
547
|
-
if (agentFiles.length === 0) {
|
|
548
|
-
warnings.push(`Agents directory exists but contains no .md files: ${manifest.agents}`);
|
|
549
|
-
}
|
|
550
|
-
for (const agentFile of agentFiles) {
|
|
551
|
-
const relativePath = path2.relative(pluginPath, agentFile);
|
|
552
|
-
const agentResult = await validateAgentFrontmatter(agentFile);
|
|
553
|
-
if (!agentResult.valid) {
|
|
554
|
-
errors.push(...agentResult.errors.map((e) => `${relativePath}: ${e}`));
|
|
555
|
-
}
|
|
556
|
-
warnings.push(...agentResult.warnings.map((w) => `${relativePath}: ${w}`));
|
|
557
|
-
}
|
|
558
|
-
}
|
|
559
|
-
}
|
|
560
|
-
}
|
|
561
|
-
return {
|
|
562
|
-
valid: errors.length === 0,
|
|
563
|
-
errors,
|
|
564
|
-
warnings
|
|
565
|
-
};
|
|
566
|
-
}
|
|
567
|
-
async function validateAllPlugins(pluginsDir) {
|
|
568
|
-
const results = [];
|
|
569
|
-
if (!await directoryExists(pluginsDir)) {
|
|
570
|
-
return {
|
|
571
|
-
valid: false,
|
|
572
|
-
results: [
|
|
573
|
-
{
|
|
574
|
-
name: pluginsDir,
|
|
575
|
-
result: {
|
|
576
|
-
valid: false,
|
|
577
|
-
errors: [`Directory does not exist: ${pluginsDir}`],
|
|
578
|
-
warnings: []
|
|
579
|
-
}
|
|
580
|
-
}
|
|
581
|
-
],
|
|
582
|
-
summary: { total: 0, valid: 0, invalid: 1, withWarnings: 0 }
|
|
583
|
-
};
|
|
584
|
-
}
|
|
585
|
-
const allDirs = await listDirectories(pluginsDir);
|
|
586
|
-
const pluginDirs = [];
|
|
587
|
-
for (const dirName of allDirs) {
|
|
588
|
-
const potentialPluginDir = path2.join(pluginsDir, dirName, PLUGIN_DIR);
|
|
589
|
-
if (await directoryExists(potentialPluginDir)) {
|
|
590
|
-
pluginDirs.push(dirName);
|
|
591
|
-
}
|
|
592
|
-
}
|
|
593
|
-
if (pluginDirs.length === 0) {
|
|
594
|
-
return {
|
|
595
|
-
valid: false,
|
|
596
|
-
results: [
|
|
597
|
-
{
|
|
598
|
-
name: pluginsDir,
|
|
599
|
-
result: {
|
|
600
|
-
valid: false,
|
|
601
|
-
errors: [
|
|
602
|
-
`No plugins found in directory: ${pluginsDir}. Plugins must contain a ${PLUGIN_DIR}/ directory.`
|
|
603
|
-
],
|
|
604
|
-
warnings: []
|
|
605
|
-
}
|
|
606
|
-
}
|
|
607
|
-
],
|
|
608
|
-
summary: { total: 0, valid: 0, invalid: 1, withWarnings: 0 }
|
|
609
|
-
};
|
|
610
|
-
}
|
|
611
|
-
for (const pluginName of pluginDirs) {
|
|
612
|
-
const pluginPath = path2.join(pluginsDir, pluginName);
|
|
613
|
-
const result = await validatePlugin(pluginPath);
|
|
614
|
-
results.push({ name: pluginName, result });
|
|
615
|
-
}
|
|
616
|
-
const summary = {
|
|
617
|
-
total: results.length,
|
|
618
|
-
valid: results.filter((r) => r.result.valid).length,
|
|
619
|
-
invalid: results.filter((r) => !r.result.valid).length,
|
|
620
|
-
withWarnings: results.filter((r) => r.result.warnings.length > 0).length
|
|
621
|
-
};
|
|
622
|
-
return {
|
|
623
|
-
valid: summary.invalid === 0,
|
|
624
|
-
results,
|
|
625
|
-
summary
|
|
626
|
-
};
|
|
627
|
-
}
|
|
628
|
-
function printPluginValidationResult(name, result, verbose = false) {
|
|
629
|
-
const status = result.valid ? "\u2713" : "\u2717";
|
|
630
|
-
if (result.valid && result.warnings.length === 0 && !verbose) {
|
|
631
|
-
return;
|
|
632
|
-
}
|
|
633
|
-
console.log(`
|
|
634
|
-
${status} ${name}`);
|
|
635
|
-
if (result.errors.length > 0) {
|
|
636
|
-
console.log(" Errors:");
|
|
637
|
-
result.errors.forEach((e) => console.log(` - ${e}`));
|
|
638
|
-
}
|
|
639
|
-
if (result.warnings.length > 0) {
|
|
640
|
-
console.log(" Warnings:");
|
|
641
|
-
result.warnings.forEach((w) => console.log(` - ${w}`));
|
|
642
|
-
}
|
|
643
|
-
}
|
|
644
|
-
|
|
645
202
|
// src/cli/commands/validate.ts
|
|
646
203
|
var Validate = class _Validate extends BaseCommand {
|
|
647
204
|
static summary = "Validate YAML files against schemas or validate compiled plugins";
|
|
@@ -696,7 +253,7 @@ var Validate = class _Validate extends BaseCommand {
|
|
|
696
253
|
}
|
|
697
254
|
}
|
|
698
255
|
async validatePlugins(pluginPath, verbose, all) {
|
|
699
|
-
const targetPath = pluginPath ?
|
|
256
|
+
const targetPath = pluginPath ? path2.resolve(pluginPath) : process.cwd();
|
|
700
257
|
if (all) {
|
|
701
258
|
await this.validateAllPluginsInDirectory(targetPath, verbose);
|
|
702
259
|
} else {
|
|
@@ -742,7 +299,7 @@ var Validate = class _Validate extends BaseCommand {
|
|
|
742
299
|
const result = await validatePlugin(targetPath);
|
|
743
300
|
const summary = result.valid ? "Done: Plugin is valid" : "Done: Plugin has errors";
|
|
744
301
|
this.log(summary);
|
|
745
|
-
printPluginValidationResult(
|
|
302
|
+
printPluginValidationResult(path2.basename(targetPath), result, true);
|
|
746
303
|
if (result.valid && result.warnings.length === 0) {
|
|
747
304
|
this.log("");
|
|
748
305
|
this.logSuccess("Plugin validated successfully");
|