@agents-inc/cli 0.46.0 → 0.48.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 +26 -0
- package/README.md +114 -118
- package/config/skill-categories.yaml +344 -0
- package/config/skill-rules.yaml +740 -0
- package/dist/{chunk-LFZXMQOH.js → chunk-2BVZOYJP.js} +2 -2
- package/dist/{chunk-4C7PDDLY.js → chunk-2DNDAXF6.js} +5 -5
- package/dist/{chunk-C7BO2ASM.js → chunk-34BP5BC4.js} +2 -2
- package/dist/{chunk-TOWP4T5L.js → chunk-37QYD33C.js} +2 -2
- package/dist/{chunk-YT7UHV67.js → chunk-5MN5S3DV.js} +11 -9
- package/dist/chunk-5MN5S3DV.js.map +1 -0
- package/dist/{chunk-72GS6PIH.js → chunk-5O6GKXAN.js} +7 -7
- package/dist/{chunk-KWQ2BQXF.js → chunk-7IAKVZL5.js} +3 -3
- package/dist/{chunk-CTQHZELA.js → chunk-AMNCCZSG.js} +14 -14
- package/dist/{chunk-PZLUO4OY.js → chunk-AXV7NFFJ.js} +4 -4
- package/dist/{chunk-ODQ2BKWU.js → chunk-AXZNJ5PN.js} +3 -3
- package/dist/{chunk-J64CA4V6.js → chunk-C7DLY64D.js} +2 -2
- package/dist/{chunk-G2WNOT3R.js → chunk-DG2U2WY3.js} +2 -2
- package/dist/{chunk-3WKFSTG6.js → chunk-F7KTUFGU.js} +2 -2
- package/dist/{chunk-5M6JI76P.js → chunk-FHKNG3UA.js} +2 -2
- package/dist/{chunk-I26YP2Q3.js → chunk-FPTUCWBY.js} +5 -5
- package/dist/{chunk-VH3PI43B.js → chunk-G5OZQ376.js} +4 -4
- package/dist/{chunk-RWR56UVK.js → chunk-GSPPOXMG.js} +11 -2
- package/dist/chunk-GSPPOXMG.js.map +1 -0
- package/dist/{chunk-YVMYQSED.js → chunk-I52THVF6.js} +2 -2
- package/dist/{chunk-FKBCYT7B.js → chunk-IS7GP6XC.js} +5 -5
- package/dist/{chunk-UK3AMBR7.js → chunk-KPJJOLAQ.js} +13 -6
- package/dist/{chunk-UK3AMBR7.js.map → chunk-KPJJOLAQ.js.map} +1 -1
- package/dist/{chunk-74HSA7C4.js → chunk-LESHL6SM.js} +9 -5
- package/dist/chunk-LESHL6SM.js.map +1 -0
- package/dist/{chunk-NMXNHRAK.js → chunk-NJVJ7VO5.js} +3 -3
- package/dist/{chunk-GVLYNP2I.js → chunk-OHDEJEYB.js} +4 -4
- package/dist/{chunk-CD64ZNYI.js → chunk-OTTITQ7C.js} +11 -3
- package/dist/chunk-OTTITQ7C.js.map +1 -0
- package/dist/{chunk-RT6IBH37.js → chunk-P2SFRDWI.js} +191 -109
- package/dist/chunk-P2SFRDWI.js.map +1 -0
- package/dist/{chunk-FUEZQ2H6.js → chunk-PY2XZUBF.js} +4 -4
- package/dist/{chunk-CDGHSTB6.js → chunk-SPVSWDFM.js} +7 -5
- package/dist/chunk-SPVSWDFM.js.map +1 -0
- package/dist/{chunk-DO5OZHSS.js → chunk-U2AEK4ZL.js} +2 -2
- package/dist/{chunk-HM3DHMW7.js → chunk-VBAAATPU.js} +8 -8
- package/dist/chunk-VBAAATPU.js.map +1 -0
- package/dist/{chunk-7LDSHHKN.js → chunk-W62XVWXB.js} +3 -3
- package/dist/{chunk-D7JTL3DJ.js → chunk-WSGKCBY5.js} +2 -2
- package/dist/{chunk-XE6RTHUD.js → chunk-X3SZIBVW.js} +34 -4
- package/dist/chunk-X3SZIBVW.js.map +1 -0
- package/dist/{chunk-QBUOZVNZ.js → chunk-YDASDMTH.js} +2 -2
- package/dist/{chunk-5QRJUBK7.js → chunk-YMUWTPOM.js} +41 -29
- package/dist/chunk-YMUWTPOM.js.map +1 -0
- package/dist/{chunk-SGXUMZWL.js → chunk-ZML3OCYA.js} +2 -2
- package/dist/commands/build/marketplace.js +4 -4
- package/dist/commands/build/plugins.js +5 -5
- package/dist/commands/build/stack.js +5 -5
- package/dist/commands/compile.js +6 -6
- package/dist/commands/config/get.js +4 -4
- package/dist/commands/config/index.js +5 -5
- package/dist/commands/config/path.js +4 -4
- package/dist/commands/config/set-project.js +4 -4
- package/dist/commands/config/show.js +5 -5
- package/dist/commands/config/unset-project.js +4 -4
- package/dist/commands/diff.js +4 -4
- package/dist/commands/doctor.js +4 -4
- package/dist/commands/edit.js +29 -29
- package/dist/commands/eject.js +4 -4
- package/dist/commands/import/skill.js +7 -8
- package/dist/commands/import/skill.js.map +1 -1
- package/dist/commands/info.js +5 -5
- package/dist/commands/init.js +28 -28
- package/dist/commands/list.js +4 -4
- package/dist/commands/new/agent.js +6 -6
- package/dist/commands/new/marketplace.js +5 -5
- package/dist/commands/new/skill.js +10 -8
- package/dist/commands/new/skill.js.map +1 -1
- package/dist/commands/outdated.js +4 -4
- package/dist/commands/search.js +7 -8
- package/dist/commands/search.js.map +1 -1
- package/dist/commands/uninstall.js +6 -6
- package/dist/commands/update.js +6 -6
- package/dist/commands/validate.js +267 -24
- package/dist/commands/validate.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 +122 -2
- package/dist/components/wizard/category-grid.test.js.map +1 -1
- package/dist/components/wizard/checkbox-grid.js +3 -3
- package/dist/components/wizard/checkbox-grid.test.js +3 -3
- package/dist/components/wizard/domain-selection.js +9 -9
- package/dist/components/wizard/help-modal.js +2 -2
- package/dist/components/wizard/menu-item.js +1 -1
- package/dist/components/wizard/search-modal.js +2 -2
- package/dist/components/wizard/search-modal.test.js +2 -2
- package/dist/components/wizard/section-progress.js +2 -2
- package/dist/components/wizard/section-progress.test.js +2 -2
- package/dist/components/wizard/selection-card.js +2 -2
- package/dist/components/wizard/source-grid.js +3 -3
- package/dist/components/wizard/source-grid.test.js +3 -3
- package/dist/components/wizard/stack-selection.js +8 -8
- package/dist/components/wizard/step-agents.js +8 -8
- package/dist/components/wizard/step-agents.test.js +9 -9
- package/dist/components/wizard/step-build.js +8 -8
- package/dist/components/wizard/step-build.test.js +74 -46
- package/dist/components/wizard/step-build.test.js.map +1 -1
- package/dist/components/wizard/step-confirm.js +4 -4
- package/dist/components/wizard/step-confirm.test.js +8 -8
- package/dist/components/wizard/step-refine.js +2 -2
- package/dist/components/wizard/step-refine.test.js +2 -2
- package/dist/components/wizard/step-settings.js +5 -5
- package/dist/components/wizard/step-settings.test.js +8 -8
- package/dist/components/wizard/step-sources.js +10 -10
- package/dist/components/wizard/step-sources.test.js +11 -11
- package/dist/components/wizard/step-stack.js +12 -12
- package/dist/components/wizard/step-stack.test.js +13 -13
- package/dist/components/wizard/view-title.js +2 -2
- package/dist/components/wizard/wizard-layout.js +8 -8
- package/dist/components/wizard/wizard-tabs.js +2 -2
- package/dist/components/wizard/wizard-tabs.test.js +2 -2
- package/dist/components/wizard/wizard.js +25 -25
- package/dist/config/skill-categories.yaml +344 -0
- package/dist/config/skill-rules.yaml +740 -0
- package/dist/hooks/init.js +3 -3
- package/dist/{source-manager-6QZ2GDUA.js → source-manager-Y7R6WPOW.js} +4 -4
- package/dist/src/agents/meta/documentor/examples.md +35 -36
- package/dist/src/agents/meta/documentor/workflow.md +91 -105
- package/dist/stores/wizard-store.js +5 -5
- package/dist/stores/wizard-store.test.js +48 -6
- package/dist/stores/wizard-store.test.js.map +1 -1
- package/package.json +5 -1
- package/src/agents/meta/documentor/examples.md +35 -36
- package/src/agents/meta/documentor/workflow.md +91 -105
- package/src/schemas/agent.schema.json +3 -0
- package/src/schemas/metadata.schema.json +5 -5
- package/src/schemas/project-source-config.schema.json +4 -1
- package/config/skills-matrix.yaml +0 -918
- package/dist/chunk-5QRJUBK7.js.map +0 -1
- package/dist/chunk-74HSA7C4.js.map +0 -1
- package/dist/chunk-CD64ZNYI.js.map +0 -1
- package/dist/chunk-CDGHSTB6.js.map +0 -1
- package/dist/chunk-HM3DHMW7.js.map +0 -1
- package/dist/chunk-RT6IBH37.js.map +0 -1
- package/dist/chunk-RWR56UVK.js.map +0 -1
- package/dist/chunk-XE6RTHUD.js.map +0 -1
- package/dist/chunk-YT7UHV67.js.map +0 -1
- package/dist/config/skills-matrix.yaml +0 -918
- package/src/schemas/skills-matrix.schema.json +0 -179
- /package/dist/{chunk-LFZXMQOH.js.map → chunk-2BVZOYJP.js.map} +0 -0
- /package/dist/{chunk-4C7PDDLY.js.map → chunk-2DNDAXF6.js.map} +0 -0
- /package/dist/{chunk-C7BO2ASM.js.map → chunk-34BP5BC4.js.map} +0 -0
- /package/dist/{chunk-TOWP4T5L.js.map → chunk-37QYD33C.js.map} +0 -0
- /package/dist/{chunk-72GS6PIH.js.map → chunk-5O6GKXAN.js.map} +0 -0
- /package/dist/{chunk-KWQ2BQXF.js.map → chunk-7IAKVZL5.js.map} +0 -0
- /package/dist/{chunk-CTQHZELA.js.map → chunk-AMNCCZSG.js.map} +0 -0
- /package/dist/{chunk-PZLUO4OY.js.map → chunk-AXV7NFFJ.js.map} +0 -0
- /package/dist/{chunk-ODQ2BKWU.js.map → chunk-AXZNJ5PN.js.map} +0 -0
- /package/dist/{chunk-J64CA4V6.js.map → chunk-C7DLY64D.js.map} +0 -0
- /package/dist/{chunk-G2WNOT3R.js.map → chunk-DG2U2WY3.js.map} +0 -0
- /package/dist/{chunk-3WKFSTG6.js.map → chunk-F7KTUFGU.js.map} +0 -0
- /package/dist/{chunk-5M6JI76P.js.map → chunk-FHKNG3UA.js.map} +0 -0
- /package/dist/{chunk-I26YP2Q3.js.map → chunk-FPTUCWBY.js.map} +0 -0
- /package/dist/{chunk-VH3PI43B.js.map → chunk-G5OZQ376.js.map} +0 -0
- /package/dist/{chunk-YVMYQSED.js.map → chunk-I52THVF6.js.map} +0 -0
- /package/dist/{chunk-FKBCYT7B.js.map → chunk-IS7GP6XC.js.map} +0 -0
- /package/dist/{chunk-NMXNHRAK.js.map → chunk-NJVJ7VO5.js.map} +0 -0
- /package/dist/{chunk-GVLYNP2I.js.map → chunk-OHDEJEYB.js.map} +0 -0
- /package/dist/{chunk-FUEZQ2H6.js.map → chunk-PY2XZUBF.js.map} +0 -0
- /package/dist/{chunk-DO5OZHSS.js.map → chunk-U2AEK4ZL.js.map} +0 -0
- /package/dist/{chunk-7LDSHHKN.js.map → chunk-W62XVWXB.js.map} +0 -0
- /package/dist/{chunk-D7JTL3DJ.js.map → chunk-WSGKCBY5.js.map} +0 -0
- /package/dist/{chunk-QBUOZVNZ.js.map → chunk-YDASDMTH.js.map} +0 -0
- /package/dist/{chunk-SGXUMZWL.js.map → chunk-ZML3OCYA.js.map} +0 -0
- /package/dist/{source-manager-6QZ2GDUA.js.map → source-manager-Y7R6WPOW.js.map} +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/cli/commands/search.tsx","../../src/cli/components/skill-search/index.ts"],"sourcesContent":["import { Args, Flags } from \"@oclif/core\";\nimport { printTable } from \"@oclif/table\";\nimport { render } from \"ink\";\nimport path from \"path\";\nimport { sortBy } from \"remeda\";\n\nimport { BaseCommand } from \"../base-command.js\";\nimport { SkillSearch, type SkillSearchResult } from \"../components/skill-search/index.js\";\nimport type { SourcedSkill } from \"../components/skill-search/skill-search.js\";\nimport { DEFAULT_SKILLS_SUBDIR, LOCAL_SKILLS_PATH, STANDARD_FILES } from \"../consts.js\";\nimport { EXIT_CODES } from \"../lib/exit-codes.js\";\nimport { resolveAllSources, type SourceEntry } from \"../lib/configuration/index.js\";\nimport { loadSkillsMatrixFromSource, fetchFromSource } from \"../lib/loading/index.js\";\nimport type { CategoryPath, ResolvedSkill, SkillId } from \"../types/index.js\";\nimport { listDirectories, fileExists, copy, ensureDir } from \"../utils/fs.js\";\nimport { SUCCESS_MESSAGES, STATUS_MESSAGES, INFO_MESSAGES } from \"../utils/messages.js\";\n\nconst MAX_DESCRIPTION_WIDTH = 50;\n\nfunction truncate(str: string, maxLength: number): string {\n if (str.length <= maxLength) return str;\n return `${str.slice(0, maxLength - 3)}...`;\n}\n\nfunction matchesQuery(skill: ResolvedSkill, query: string): boolean {\n const lowerQuery = query.toLowerCase();\n\n if (skill.id.toLowerCase().includes(lowerQuery)) return true;\n if (skill.displayName?.toLowerCase().includes(lowerQuery)) return true;\n if (skill.description.toLowerCase().includes(lowerQuery)) return true;\n if (skill.category.toLowerCase().includes(lowerQuery)) return true;\n\n return skill.tags.some((tag) => tag.toLowerCase().includes(lowerQuery));\n}\n\nfunction matchesCategory(skill: ResolvedSkill, category: CategoryPath): boolean {\n const lowerCategory = category.toLowerCase();\n return skill.category.toLowerCase().includes(lowerCategory);\n}\n\nfunction toSourcedSkill(\n skill: ResolvedSkill,\n sourceName: string,\n sourceUrl?: string,\n): SourcedSkill {\n return {\n ...skill,\n sourceName,\n sourceUrl,\n };\n}\n\nasync function fetchSkillsFromSource(\n source: SourceEntry,\n forceRefresh: boolean,\n): Promise<SourcedSkill[]> {\n try {\n const result = await fetchFromSource(source.url, { forceRefresh });\n const skillsDir = path.join(result.path, DEFAULT_SKILLS_SUBDIR);\n\n if (!(await fileExists(skillsDir))) {\n return [];\n }\n\n const skillDirs = await listDirectories(skillsDir);\n const skills: SourcedSkill[] = [];\n\n for (const skillDir of skillDirs) {\n const skillMdPath = path.join(skillsDir, skillDir, STANDARD_FILES.SKILL_MD);\n if (await fileExists(skillMdPath)) {\n skills.push({\n // Directory name is an untyped string — cast at data boundary\n id: skillDir as SkillId,\n description: `Skill from ${source.name}`,\n // Synthetic category for third-party sources — not in CategoryPath union\n category: \"imported\" as CategoryPath,\n categoryExclusive: false,\n tags: [],\n author: `@${source.name}`,\n conflictsWith: [],\n recommends: [],\n requires: [],\n alternatives: [],\n discourages: [],\n compatibleWith: [],\n requiresSetup: [],\n providesSetupFor: [],\n sourceName: source.name,\n sourceUrl: source.url,\n path: path.join(skillsDir, skillDir),\n });\n }\n }\n\n return skills;\n } catch {\n // Source unavailable, return empty\n return [];\n }\n}\n\nexport default class Search extends BaseCommand {\n static summary = \"Search available skills\";\n static description =\n \"Search skills by ID, alias, description, category, or tags. \" +\n \"Run without arguments or with -i for interactive mode with multi-select.\";\n\n static examples = [\n {\n description: \"Search for React skills\",\n command: \"<%= config.bin %> search react\",\n },\n {\n description: \"Interactive search mode\",\n command: \"<%= config.bin %> search\",\n },\n {\n description: \"Interactive with pre-filled query\",\n command: \"<%= config.bin %> search -i react\",\n },\n {\n description: \"Search with category filter\",\n command: \"<%= config.bin %> search state -c frontend\",\n },\n ];\n\n static args = {\n query: Args.string({\n description: \"Search query (matches name, description, category, tags)\",\n required: false,\n }),\n };\n\n static flags = {\n ...BaseCommand.baseFlags,\n interactive: Flags.boolean({\n char: \"i\",\n description: \"Launch interactive search with multi-select\",\n default: false,\n }),\n category: Flags.string({\n char: \"c\",\n description: \"Filter by category\",\n required: false,\n }),\n refresh: Flags.boolean({\n description: \"Force refresh from remote sources\",\n default: false,\n }),\n };\n\n async run(): Promise<void> {\n const { args, flags } = await this.parse(Search);\n const projectDir = process.cwd();\n\n const isInteractive = flags.interactive || !args.query;\n\n if (isInteractive) {\n await this.runInteractive(args.query, flags.refresh, projectDir);\n } else {\n await this.runStatic(args.query!, flags);\n }\n }\n\n private async runInteractive(\n initialQuery: string | undefined,\n forceRefresh: boolean,\n projectDir: string,\n ): Promise<void> {\n this.log(\"Loading skills from all sources...\");\n\n try {\n const { matrix, sourcePath } = await loadSkillsMatrixFromSource({\n sourceFlag: undefined,\n projectDir,\n forceRefresh,\n });\n\n const primarySkills = Object.values(matrix.skills)\n .filter((skill): skill is ResolvedSkill => skill !== undefined)\n .map((skill) => toSourcedSkill(skill, \"marketplace\", sourcePath));\n\n const { extras } = await resolveAllSources(projectDir);\n\n const extraSkillArrays = await Promise.all(\n extras.map((source) => fetchSkillsFromSource(source, forceRefresh)),\n );\n\n const allSkills: SourcedSkill[] = [...primarySkills, ...extraSkillArrays.flat()];\n const sourceCount = 1 + extras.length;\n\n this.log(`Loaded ${allSkills.length} skills from ${sourceCount} source(s)`);\n this.log(\"\");\n\n const searchResultPromise = new Promise<SkillSearchResult>((resolve) => {\n const { waitUntilExit } = render(\n <SkillSearch\n skills={allSkills}\n sourceCount={sourceCount}\n initialQuery={initialQuery}\n onComplete={(result) => {\n resolve(result);\n }}\n onCancel={() => {\n resolve({ selectedSkills: [], cancelled: true });\n }}\n />,\n );\n\n waitUntilExit().then(() => {\n resolve({ selectedSkills: [], cancelled: true });\n });\n });\n\n const searchResult = await searchResultPromise;\n\n if (searchResult.cancelled) {\n this.log(\"Search cancelled\");\n this.exit(EXIT_CODES.CANCELLED);\n }\n\n if (searchResult.selectedSkills.length === 0) {\n this.log(\"No skills selected\");\n return;\n }\n\n this.log(\"\");\n this.log(`Importing ${searchResult.selectedSkills.length} skill(s)...`);\n\n const destDir = path.join(projectDir, LOCAL_SKILLS_PATH);\n\n for (const skill of searchResult.selectedSkills) {\n if (skill.path) {\n const destPath = path.join(destDir, skill.id);\n await ensureDir(path.dirname(destPath));\n await copy(skill.path, destPath);\n this.logSuccess(`Imported: ${skill.id}`);\n } else {\n this.warn(`Skipping ${skill.id}: No source path available`);\n }\n }\n\n this.log(\"\");\n this.logSuccess(SUCCESS_MESSAGES.IMPORT_COMPLETE);\n this.log(`Skills location: ${destDir}`);\n this.log(INFO_MESSAGES.RUN_COMPILE);\n } catch (error) {\n this.handleError(error);\n }\n }\n\n private async runStatic(\n query: string,\n flags: { source?: string; category?: string },\n ): Promise<void> {\n try {\n this.log(STATUS_MESSAGES.LOADING_SKILLS);\n\n const { matrix, sourcePath, isLocal } = await loadSkillsMatrixFromSource({\n sourceFlag: flags.source,\n });\n\n this.log(`Loaded from ${isLocal ? \"local\" : \"remote\"}: ${sourcePath}`);\n\n const allSkills = Object.values(matrix.skills).filter(\n (skill): skill is ResolvedSkill => skill !== undefined,\n );\n\n let results = allSkills.filter((skill) => matchesQuery(skill, query));\n\n if (flags.category) {\n // CLI flag is an untyped string — cast at data boundary\n results = results.filter((skill) => matchesCategory(skill, flags.category as CategoryPath));\n }\n\n results = sortBy(results, (r) => r.displayName || r.id);\n\n this.log(\"\");\n if (results.length === 0) {\n this.warn(`No skills found matching \"${query}\"`);\n if (flags.category) {\n this.logInfo(`Category filter: ${flags.category}`);\n }\n } else {\n this.logInfo(\n `Found ${results.length} skill${results.length === 1 ? \"\" : \"s\"} matching \"${query}\"`,\n );\n if (flags.category) {\n this.logInfo(`Category filter: ${flags.category}`);\n }\n this.log(\"\");\n\n printTable({\n data: results.map((skill) => ({\n id: skill.displayName || skill.id,\n category: skill.category,\n description: truncate(skill.description, MAX_DESCRIPTION_WIDTH),\n })),\n columns: [\n { key: \"id\", name: \"ID\" },\n { key: \"category\", name: \"Category\" },\n { key: \"description\", name: \"Description\" },\n ],\n headerOptions: { bold: true },\n });\n }\n this.log(\"\");\n } catch (error) {\n this.handleError(error);\n }\n }\n}\n","export { SkillSearch, type SkillSearchResult } from \"./skill-search.js\";\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/cli/commands/search.tsx","../../src/cli/components/skill-search/index.ts"],"sourcesContent":["import { Args, Flags } from \"@oclif/core\";\nimport { printTable } from \"@oclif/table\";\nimport { render } from \"ink\";\nimport path from \"path\";\nimport { sortBy } from \"remeda\";\n\nimport { BaseCommand } from \"../base-command.js\";\nimport { SkillSearch, type SkillSearchResult } from \"../components/skill-search/index.js\";\nimport type { SourcedSkill } from \"../components/skill-search/skill-search.js\";\nimport { DEFAULT_SKILLS_SUBDIR, LOCAL_SKILLS_PATH, STANDARD_FILES } from \"../consts.js\";\nimport { EXIT_CODES } from \"../lib/exit-codes.js\";\nimport { resolveAllSources, type SourceEntry } from \"../lib/configuration/index.js\";\nimport { loadSkillsMatrixFromSource, fetchFromSource } from \"../lib/loading/index.js\";\nimport type { CategoryPath, ResolvedSkill, SkillId } from \"../types/index.js\";\nimport { listDirectories, fileExists, copy, ensureDir } from \"../utils/fs.js\";\nimport { SUCCESS_MESSAGES, STATUS_MESSAGES, INFO_MESSAGES } from \"../utils/messages.js\";\n\nconst MAX_DESCRIPTION_WIDTH = 50;\n\nfunction truncate(str: string, maxLength: number): string {\n if (str.length <= maxLength) return str;\n return `${str.slice(0, maxLength - 3)}...`;\n}\n\nfunction matchesQuery(skill: ResolvedSkill, query: string): boolean {\n const lowerQuery = query.toLowerCase();\n\n if (skill.id.toLowerCase().includes(lowerQuery)) return true;\n if (skill.displayName?.toLowerCase().includes(lowerQuery)) return true;\n if (skill.description.toLowerCase().includes(lowerQuery)) return true;\n if (skill.category.toLowerCase().includes(lowerQuery)) return true;\n\n return skill.tags.some((tag) => tag.toLowerCase().includes(lowerQuery));\n}\n\nfunction matchesCategory(skill: ResolvedSkill, category: CategoryPath): boolean {\n const lowerCategory = category.toLowerCase();\n return skill.category.toLowerCase().includes(lowerCategory);\n}\n\nfunction toSourcedSkill(\n skill: ResolvedSkill,\n sourceName: string,\n sourceUrl?: string,\n): SourcedSkill {\n return {\n ...skill,\n sourceName,\n sourceUrl,\n };\n}\n\nasync function fetchSkillsFromSource(\n source: SourceEntry,\n forceRefresh: boolean,\n): Promise<SourcedSkill[]> {\n try {\n const result = await fetchFromSource(source.url, { forceRefresh });\n const skillsDir = path.join(result.path, DEFAULT_SKILLS_SUBDIR);\n\n if (!(await fileExists(skillsDir))) {\n return [];\n }\n\n const skillDirs = await listDirectories(skillsDir);\n const skills: SourcedSkill[] = [];\n\n for (const skillDir of skillDirs) {\n const skillMdPath = path.join(skillsDir, skillDir, STANDARD_FILES.SKILL_MD);\n if (await fileExists(skillMdPath)) {\n skills.push({\n // Directory name is an untyped string — cast at data boundary\n id: skillDir as SkillId,\n description: `Skill from ${source.name}`,\n // Synthetic category for third-party sources — not in CategoryPath union\n category: \"imported\" as CategoryPath,\n tags: [],\n author: `@${source.name}`,\n conflictsWith: [],\n recommends: [],\n requires: [],\n alternatives: [],\n discourages: [],\n compatibleWith: [],\n requiresSetup: [],\n providesSetupFor: [],\n sourceName: source.name,\n sourceUrl: source.url,\n path: path.join(skillsDir, skillDir),\n });\n }\n }\n\n return skills;\n } catch {\n // Source unavailable, return empty\n return [];\n }\n}\n\nexport default class Search extends BaseCommand {\n static summary = \"Search available skills\";\n static description =\n \"Search skills by ID, alias, description, category, or tags. \" +\n \"Run without arguments or with -i for interactive mode with multi-select.\";\n\n static examples = [\n {\n description: \"Search for React skills\",\n command: \"<%= config.bin %> search react\",\n },\n {\n description: \"Interactive search mode\",\n command: \"<%= config.bin %> search\",\n },\n {\n description: \"Interactive with pre-filled query\",\n command: \"<%= config.bin %> search -i react\",\n },\n {\n description: \"Search with category filter\",\n command: \"<%= config.bin %> search state -c frontend\",\n },\n ];\n\n static args = {\n query: Args.string({\n description: \"Search query (matches name, description, category, tags)\",\n required: false,\n }),\n };\n\n static flags = {\n ...BaseCommand.baseFlags,\n interactive: Flags.boolean({\n char: \"i\",\n description: \"Launch interactive search with multi-select\",\n default: false,\n }),\n category: Flags.string({\n char: \"c\",\n description: \"Filter by category\",\n required: false,\n }),\n refresh: Flags.boolean({\n description: \"Force refresh from remote sources\",\n default: false,\n }),\n };\n\n async run(): Promise<void> {\n const { args, flags } = await this.parse(Search);\n const projectDir = process.cwd();\n\n const isInteractive = flags.interactive || !args.query;\n\n if (isInteractive) {\n await this.runInteractive(args.query, flags.refresh, projectDir);\n } else {\n await this.runStatic(args.query!, flags);\n }\n }\n\n private async runInteractive(\n initialQuery: string | undefined,\n forceRefresh: boolean,\n projectDir: string,\n ): Promise<void> {\n this.log(\"Loading skills from all sources...\");\n\n try {\n const { matrix, sourcePath } = await loadSkillsMatrixFromSource({\n sourceFlag: undefined,\n projectDir,\n forceRefresh,\n });\n\n const primarySkills = Object.values(matrix.skills)\n .filter((skill): skill is ResolvedSkill => skill !== undefined)\n .map((skill) => toSourcedSkill(skill, \"marketplace\", sourcePath));\n\n const { extras } = await resolveAllSources(projectDir);\n\n const extraSkillArrays = await Promise.all(\n extras.map((source) => fetchSkillsFromSource(source, forceRefresh)),\n );\n\n const allSkills: SourcedSkill[] = [...primarySkills, ...extraSkillArrays.flat()];\n const sourceCount = 1 + extras.length;\n\n this.log(`Loaded ${allSkills.length} skills from ${sourceCount} source(s)`);\n this.log(\"\");\n\n const searchResultPromise = new Promise<SkillSearchResult>((resolve) => {\n const { waitUntilExit } = render(\n <SkillSearch\n skills={allSkills}\n sourceCount={sourceCount}\n initialQuery={initialQuery}\n onComplete={(result) => {\n resolve(result);\n }}\n onCancel={() => {\n resolve({ selectedSkills: [], cancelled: true });\n }}\n />,\n );\n\n waitUntilExit().then(() => {\n resolve({ selectedSkills: [], cancelled: true });\n });\n });\n\n const searchResult = await searchResultPromise;\n\n if (searchResult.cancelled) {\n this.log(\"Search cancelled\");\n this.exit(EXIT_CODES.CANCELLED);\n }\n\n if (searchResult.selectedSkills.length === 0) {\n this.log(\"No skills selected\");\n return;\n }\n\n this.log(\"\");\n this.log(`Importing ${searchResult.selectedSkills.length} skill(s)...`);\n\n const destDir = path.join(projectDir, LOCAL_SKILLS_PATH);\n\n for (const skill of searchResult.selectedSkills) {\n if (skill.path) {\n const destPath = path.join(destDir, skill.id);\n await ensureDir(path.dirname(destPath));\n await copy(skill.path, destPath);\n this.logSuccess(`Imported: ${skill.id}`);\n } else {\n this.warn(`Skipping ${skill.id}: No source path available`);\n }\n }\n\n this.log(\"\");\n this.logSuccess(SUCCESS_MESSAGES.IMPORT_COMPLETE);\n this.log(`Skills location: ${destDir}`);\n this.log(INFO_MESSAGES.RUN_COMPILE);\n } catch (error) {\n this.handleError(error);\n }\n }\n\n private async runStatic(\n query: string,\n flags: { source?: string; category?: string },\n ): Promise<void> {\n try {\n this.log(STATUS_MESSAGES.LOADING_SKILLS);\n\n const { matrix, sourcePath, isLocal } = await loadSkillsMatrixFromSource({\n sourceFlag: flags.source,\n });\n\n this.log(`Loaded from ${isLocal ? \"local\" : \"remote\"}: ${sourcePath}`);\n\n const allSkills = Object.values(matrix.skills).filter(\n (skill): skill is ResolvedSkill => skill !== undefined,\n );\n\n let results = allSkills.filter((skill) => matchesQuery(skill, query));\n\n if (flags.category) {\n // CLI flag is an untyped string — cast at data boundary\n results = results.filter((skill) => matchesCategory(skill, flags.category as CategoryPath));\n }\n\n results = sortBy(results, (r) => r.displayName || r.id);\n\n this.log(\"\");\n if (results.length === 0) {\n this.warn(`No skills found matching \"${query}\"`);\n if (flags.category) {\n this.logInfo(`Category filter: ${flags.category}`);\n }\n } else {\n this.logInfo(\n `Found ${results.length} skill${results.length === 1 ? \"\" : \"s\"} matching \"${query}\"`,\n );\n if (flags.category) {\n this.logInfo(`Category filter: ${flags.category}`);\n }\n this.log(\"\");\n\n printTable({\n data: results.map((skill) => ({\n id: skill.displayName || skill.id,\n category: skill.category,\n description: truncate(skill.description, MAX_DESCRIPTION_WIDTH),\n })),\n columns: [\n { key: \"id\", name: \"ID\" },\n { key: \"category\", name: \"Category\" },\n { key: \"description\", name: \"Description\" },\n ],\n headerOptions: { bold: true },\n });\n }\n this.log(\"\");\n } catch (error) {\n this.handleError(error);\n }\n }\n}\n","export { SkillSearch, type SkillSearchResult } from \"./skill-search.js\";\n"],"mappings":"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","names":[]}
|
|
@@ -5,35 +5,35 @@ import {
|
|
|
5
5
|
import {
|
|
6
6
|
claudePluginUninstall,
|
|
7
7
|
isClaudeCLIAvailable
|
|
8
|
-
} from "../chunk-
|
|
8
|
+
} from "../chunk-YDASDMTH.js";
|
|
9
9
|
import {
|
|
10
10
|
DRY_RUN_MESSAGES,
|
|
11
11
|
INFO_MESSAGES,
|
|
12
12
|
SUCCESS_MESSAGES
|
|
13
|
-
} from "../chunk-
|
|
13
|
+
} from "../chunk-DG2U2WY3.js";
|
|
14
14
|
import {
|
|
15
15
|
BaseCommand,
|
|
16
16
|
EXIT_CODES
|
|
17
|
-
} from "../chunk-
|
|
17
|
+
} from "../chunk-2BVZOYJP.js";
|
|
18
18
|
import {
|
|
19
19
|
getProjectPluginsDir,
|
|
20
20
|
listPluginNames,
|
|
21
21
|
loadProjectSourceConfig,
|
|
22
22
|
readForkedFromMetadata
|
|
23
|
-
} from "../chunk-
|
|
23
|
+
} from "../chunk-P2SFRDWI.js";
|
|
24
24
|
import "../chunk-T4EXUIBY.js";
|
|
25
25
|
import {
|
|
26
26
|
directoryExists,
|
|
27
27
|
getErrorMessage,
|
|
28
28
|
listDirectories,
|
|
29
29
|
remove
|
|
30
|
-
} from "../chunk-
|
|
30
|
+
} from "../chunk-YMUWTPOM.js";
|
|
31
31
|
import {
|
|
32
32
|
CLAUDE_DIR,
|
|
33
33
|
CLAUDE_SRC_DIR,
|
|
34
34
|
CLI_COLORS,
|
|
35
35
|
DEFAULT_BRANDING
|
|
36
|
-
} from "../chunk-
|
|
36
|
+
} from "../chunk-LESHL6SM.js";
|
|
37
37
|
import {
|
|
38
38
|
init_esm_shims
|
|
39
39
|
} from "../chunk-DHET7RCE.js";
|
package/dist/commands/update.js
CHANGED
|
@@ -4,32 +4,32 @@ import {
|
|
|
4
4
|
} from "../chunk-N6S7ZRIL.js";
|
|
5
5
|
import {
|
|
6
6
|
recompileAgents
|
|
7
|
-
} from "../chunk-
|
|
7
|
+
} from "../chunk-AXV7NFFJ.js";
|
|
8
8
|
import {
|
|
9
9
|
ERROR_MESSAGES,
|
|
10
10
|
INFO_MESSAGES,
|
|
11
11
|
STATUS_MESSAGES,
|
|
12
12
|
SUCCESS_MESSAGES
|
|
13
|
-
} from "../chunk-
|
|
13
|
+
} from "../chunk-DG2U2WY3.js";
|
|
14
14
|
import {
|
|
15
15
|
BaseCommand,
|
|
16
16
|
EXIT_CODES
|
|
17
|
-
} from "../chunk-
|
|
17
|
+
} from "../chunk-2BVZOYJP.js";
|
|
18
18
|
import {
|
|
19
19
|
compareLocalSkillsWithSource,
|
|
20
20
|
injectForkedFromMetadata,
|
|
21
21
|
loadSkillsMatrixFromSource
|
|
22
|
-
} from "../chunk-
|
|
22
|
+
} from "../chunk-P2SFRDWI.js";
|
|
23
23
|
import "../chunk-T4EXUIBY.js";
|
|
24
24
|
import {
|
|
25
25
|
copy,
|
|
26
26
|
fileExists,
|
|
27
27
|
getErrorMessage
|
|
28
|
-
} from "../chunk-
|
|
28
|
+
} from "../chunk-YMUWTPOM.js";
|
|
29
29
|
import {
|
|
30
30
|
CLI_BIN_NAME,
|
|
31
31
|
LOCAL_SKILLS_PATH
|
|
32
|
-
} from "../chunk-
|
|
32
|
+
} from "../chunk-LESHL6SM.js";
|
|
33
33
|
import {
|
|
34
34
|
init_esm_shims
|
|
35
35
|
} from "../chunk-DHET7RCE.js";
|
|
@@ -1,38 +1,52 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
ERROR_MESSAGES
|
|
4
|
-
} from "../chunk-
|
|
4
|
+
} from "../chunk-DG2U2WY3.js";
|
|
5
5
|
import {
|
|
6
6
|
BaseCommand,
|
|
7
7
|
EXIT_CODES
|
|
8
|
-
} from "../chunk-
|
|
8
|
+
} from "../chunk-2BVZOYJP.js";
|
|
9
9
|
import {
|
|
10
|
+
checkMatrixHealth,
|
|
11
|
+
extractAllSkills,
|
|
10
12
|
extractFrontmatter,
|
|
13
|
+
loadProjectSourceConfig,
|
|
14
|
+
loadSkillCategories,
|
|
15
|
+
loadSkillRules,
|
|
16
|
+
mergeMatrixWithSkills,
|
|
17
|
+
parseFrontmatter,
|
|
11
18
|
printPluginValidationResult,
|
|
12
19
|
validateAllPlugins,
|
|
13
20
|
validatePlugin
|
|
14
|
-
} from "../chunk-
|
|
21
|
+
} from "../chunk-P2SFRDWI.js";
|
|
15
22
|
import "../chunk-T4EXUIBY.js";
|
|
16
23
|
import {
|
|
24
|
+
SKILL_ID_PATTERN,
|
|
17
25
|
agentFrontmatterValidationSchema,
|
|
18
26
|
agentYamlGenerationSchema,
|
|
27
|
+
directoryExists,
|
|
19
28
|
fileExists,
|
|
20
29
|
getErrorMessage,
|
|
30
|
+
glob,
|
|
21
31
|
log,
|
|
22
32
|
metadataValidationSchema,
|
|
23
33
|
pluginManifestSchema,
|
|
24
34
|
projectSourceConfigSchema,
|
|
25
35
|
readFile,
|
|
36
|
+
skillCategoriesFileSchema,
|
|
26
37
|
skillFrontmatterValidationSchema,
|
|
27
|
-
|
|
38
|
+
skillRulesFileSchema,
|
|
28
39
|
stackConfigValidationSchema,
|
|
29
|
-
stacksConfigSchema
|
|
30
|
-
|
|
40
|
+
stacksConfigSchema,
|
|
41
|
+
verbose
|
|
42
|
+
} from "../chunk-YMUWTPOM.js";
|
|
31
43
|
import {
|
|
32
44
|
CLAUDE_DIR,
|
|
33
45
|
CLAUDE_SRC_DIR,
|
|
46
|
+
SKILL_CATEGORIES_YAML_PATH,
|
|
47
|
+
SKILL_RULES_YAML_PATH,
|
|
34
48
|
STANDARD_FILES
|
|
35
|
-
} from "../chunk-
|
|
49
|
+
} from "../chunk-LESHL6SM.js";
|
|
36
50
|
import {
|
|
37
51
|
init_esm_shims
|
|
38
52
|
} from "../chunk-DHET7RCE.js";
|
|
@@ -40,7 +54,7 @@ import {
|
|
|
40
54
|
// src/cli/commands/validate.ts
|
|
41
55
|
init_esm_shims();
|
|
42
56
|
import { Args, Flags } from "@oclif/core";
|
|
43
|
-
import
|
|
57
|
+
import path3 from "path";
|
|
44
58
|
|
|
45
59
|
// src/cli/lib/schema-validator.ts
|
|
46
60
|
init_esm_shims();
|
|
@@ -50,10 +64,16 @@ import { parse as parseYaml } from "yaml";
|
|
|
50
64
|
import fg from "fast-glob";
|
|
51
65
|
var VALIDATION_TARGETS = [
|
|
52
66
|
{
|
|
53
|
-
name: "
|
|
54
|
-
schema:
|
|
55
|
-
pattern: STANDARD_FILES.
|
|
56
|
-
baseDir: "
|
|
67
|
+
name: "Skill Categories",
|
|
68
|
+
schema: skillCategoriesFileSchema,
|
|
69
|
+
pattern: STANDARD_FILES.SKILL_CATEGORIES_YAML,
|
|
70
|
+
baseDir: "config"
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
name: "Skill Rules",
|
|
74
|
+
schema: skillRulesFileSchema,
|
|
75
|
+
pattern: STANDARD_FILES.SKILL_RULES_YAML,
|
|
76
|
+
baseDir: "config"
|
|
57
77
|
},
|
|
58
78
|
{
|
|
59
79
|
name: "Skill Metadata",
|
|
@@ -135,11 +155,11 @@ var VALIDATION_TARGETS = [
|
|
|
135
155
|
];
|
|
136
156
|
function formatZodErrors(error) {
|
|
137
157
|
return error.issues.map((issue) => {
|
|
138
|
-
const
|
|
158
|
+
const path4 = issue.path.join(".");
|
|
139
159
|
if (issue.code === "unrecognized_keys") {
|
|
140
160
|
return `Unrecognized key: "${issue.keys.join('", "')}"`;
|
|
141
161
|
}
|
|
142
|
-
return
|
|
162
|
+
return path4 ? `${path4}: ${issue.message}` : issue.message;
|
|
143
163
|
});
|
|
144
164
|
}
|
|
145
165
|
async function validateFile(filePath, schema, extractor) {
|
|
@@ -246,15 +266,203 @@ function printValidationResults(result) {
|
|
|
246
266
|
}
|
|
247
267
|
}
|
|
248
268
|
|
|
269
|
+
// src/cli/lib/source-validator.ts
|
|
270
|
+
init_esm_shims();
|
|
271
|
+
import path2 from "path";
|
|
272
|
+
import { parse as parseYaml2 } from "yaml";
|
|
273
|
+
function isSnakeCase(key) {
|
|
274
|
+
return /[a-z]_[a-z]/.test(key);
|
|
275
|
+
}
|
|
276
|
+
async function validateSource(sourcePath) {
|
|
277
|
+
const issues = [];
|
|
278
|
+
const resolvedPath = path2.isAbsolute(sourcePath) ? sourcePath : path2.resolve(sourcePath);
|
|
279
|
+
if (!await directoryExists(resolvedPath)) {
|
|
280
|
+
issues.push({
|
|
281
|
+
severity: "error",
|
|
282
|
+
file: resolvedPath,
|
|
283
|
+
message: "Source directory does not exist"
|
|
284
|
+
});
|
|
285
|
+
return buildResult(issues, 0);
|
|
286
|
+
}
|
|
287
|
+
const sourceProjectConfig = await loadProjectSourceConfig(resolvedPath);
|
|
288
|
+
const skillsDirRelPath = sourceProjectConfig?.skillsDir ?? "src/skills";
|
|
289
|
+
const skillsDir = path2.join(resolvedPath, skillsDirRelPath);
|
|
290
|
+
if (!await directoryExists(skillsDir)) {
|
|
291
|
+
issues.push({
|
|
292
|
+
severity: "error",
|
|
293
|
+
file: skillsDir,
|
|
294
|
+
message: "Skills directory does not exist"
|
|
295
|
+
});
|
|
296
|
+
return buildResult(issues, 0);
|
|
297
|
+
}
|
|
298
|
+
const skillMdFiles = await glob(`**/${STANDARD_FILES.SKILL_MD}`, skillsDir);
|
|
299
|
+
const metadataFiles = await glob(`**/${STANDARD_FILES.METADATA_YAML}`, skillsDir);
|
|
300
|
+
const skillMdDirs = new Set(skillMdFiles.map((f) => path2.dirname(f)));
|
|
301
|
+
const metadataDirs = new Set(metadataFiles.map((f) => path2.dirname(f)));
|
|
302
|
+
for (const dir of skillMdDirs) {
|
|
303
|
+
if (!metadataDirs.has(dir)) {
|
|
304
|
+
issues.push({
|
|
305
|
+
severity: "error",
|
|
306
|
+
file: path2.join(skillsDir, dir),
|
|
307
|
+
message: `Missing ${STANDARD_FILES.METADATA_YAML} \u2014 skill directory has ${STANDARD_FILES.SKILL_MD} but no metadata`
|
|
308
|
+
});
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
for (const dir of metadataDirs) {
|
|
312
|
+
if (!skillMdDirs.has(dir)) {
|
|
313
|
+
issues.push({
|
|
314
|
+
severity: "error",
|
|
315
|
+
file: path2.join(skillsDir, dir),
|
|
316
|
+
message: `Missing ${STANDARD_FILES.SKILL_MD} \u2014 skill directory has ${STANDARD_FILES.METADATA_YAML} but no SKILL.md`
|
|
317
|
+
});
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
let skillCount = 0;
|
|
321
|
+
for (const metadataFile of metadataFiles) {
|
|
322
|
+
const metadataPath = path2.join(skillsDir, metadataFile);
|
|
323
|
+
const skillDir = path2.dirname(metadataFile);
|
|
324
|
+
const skillMdPath = path2.join(skillsDir, skillDir, STANDARD_FILES.SKILL_MD);
|
|
325
|
+
if (!await fileExists(skillMdPath)) {
|
|
326
|
+
continue;
|
|
327
|
+
}
|
|
328
|
+
skillCount++;
|
|
329
|
+
const relPath = path2.join(skillsDirRelPath, metadataFile);
|
|
330
|
+
let rawMetadata;
|
|
331
|
+
try {
|
|
332
|
+
const metadataContent = await readFile(metadataPath);
|
|
333
|
+
rawMetadata = parseYaml2(metadataContent);
|
|
334
|
+
} catch (error) {
|
|
335
|
+
issues.push({
|
|
336
|
+
severity: "error",
|
|
337
|
+
file: relPath,
|
|
338
|
+
message: "Failed to parse YAML"
|
|
339
|
+
});
|
|
340
|
+
continue;
|
|
341
|
+
}
|
|
342
|
+
if (rawMetadata && typeof rawMetadata === "object" && !Array.isArray(rawMetadata)) {
|
|
343
|
+
for (const key of Object.keys(rawMetadata)) {
|
|
344
|
+
if (isSnakeCase(key)) {
|
|
345
|
+
issues.push({
|
|
346
|
+
severity: "error",
|
|
347
|
+
file: relPath,
|
|
348
|
+
message: `Key '${key}' uses snake_case \u2014 use camelCase instead`
|
|
349
|
+
});
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
const result = metadataValidationSchema.safeParse(rawMetadata);
|
|
354
|
+
if (!result.success) {
|
|
355
|
+
for (const issue of result.error.issues) {
|
|
356
|
+
const fieldPath = issue.path.join(".");
|
|
357
|
+
issues.push({
|
|
358
|
+
severity: "error",
|
|
359
|
+
file: relPath,
|
|
360
|
+
message: `${fieldPath}: ${issue.message}`
|
|
361
|
+
});
|
|
362
|
+
}
|
|
363
|
+
continue;
|
|
364
|
+
}
|
|
365
|
+
const metadata = result.data;
|
|
366
|
+
const dirName = path2.basename(skillDir);
|
|
367
|
+
if (metadata.displayName !== dirName) {
|
|
368
|
+
issues.push({
|
|
369
|
+
severity: "warning",
|
|
370
|
+
file: relPath,
|
|
371
|
+
message: `displayName '${metadata.displayName}' does not match directory name '${dirName}'`
|
|
372
|
+
});
|
|
373
|
+
}
|
|
374
|
+
const skillMdContent = await readFile(skillMdPath);
|
|
375
|
+
const frontmatter = parseFrontmatter(skillMdContent, skillMdPath);
|
|
376
|
+
if (frontmatter) {
|
|
377
|
+
if (!SKILL_ID_PATTERN.test(frontmatter.name)) {
|
|
378
|
+
issues.push({
|
|
379
|
+
severity: "warning",
|
|
380
|
+
file: path2.join(skillsDirRelPath, skillDir, STANDARD_FILES.SKILL_MD),
|
|
381
|
+
message: `SKILL.md name '${frontmatter.name}' does not match expected skill ID pattern (domain-subcategory-name)`
|
|
382
|
+
});
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
if (metadata.category && !/^(web|api|cli|mobile|infra|meta|security|shared)-.+$/.test(metadata.category)) {
|
|
386
|
+
issues.push({
|
|
387
|
+
severity: "warning",
|
|
388
|
+
file: relPath,
|
|
389
|
+
message: `Category '${metadata.category}' does not follow domain-prefixed pattern (e.g., 'web-framework', 'api-database')`
|
|
390
|
+
});
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
try {
|
|
394
|
+
const categoriesPath = path2.join(resolvedPath, SKILL_CATEGORIES_YAML_PATH);
|
|
395
|
+
const rulesPath = path2.join(resolvedPath, SKILL_RULES_YAML_PATH);
|
|
396
|
+
const hasCats = await fileExists(categoriesPath);
|
|
397
|
+
const hasRules = await fileExists(rulesPath);
|
|
398
|
+
if (hasCats || hasRules) {
|
|
399
|
+
const cats = hasCats ? await loadSkillCategories(categoriesPath) : {};
|
|
400
|
+
const defaultRelationships = {
|
|
401
|
+
conflicts: [],
|
|
402
|
+
discourages: [],
|
|
403
|
+
recommends: [],
|
|
404
|
+
requires: [],
|
|
405
|
+
alternatives: []
|
|
406
|
+
};
|
|
407
|
+
const rules = hasRules ? await loadSkillRules(rulesPath) : {
|
|
408
|
+
version: "1.0.0",
|
|
409
|
+
aliases: {},
|
|
410
|
+
relationships: defaultRelationships,
|
|
411
|
+
perSkill: {}
|
|
412
|
+
};
|
|
413
|
+
const skills = await extractAllSkills(skillsDir);
|
|
414
|
+
const mergedMatrix = await mergeMatrixWithSkills(
|
|
415
|
+
cats,
|
|
416
|
+
rules.relationships,
|
|
417
|
+
rules.aliases,
|
|
418
|
+
skills,
|
|
419
|
+
rules.perSkill
|
|
420
|
+
);
|
|
421
|
+
const healthIssues = checkMatrixHealth(mergedMatrix);
|
|
422
|
+
for (const healthIssue of healthIssues) {
|
|
423
|
+
issues.push({
|
|
424
|
+
severity: healthIssue.severity,
|
|
425
|
+
file: SKILL_CATEGORIES_YAML_PATH,
|
|
426
|
+
message: healthIssue.details
|
|
427
|
+
});
|
|
428
|
+
}
|
|
429
|
+
} else {
|
|
430
|
+
verbose(
|
|
431
|
+
`No categories/rules files at '${resolvedPath}' \u2014 skipping cross-reference validation`
|
|
432
|
+
);
|
|
433
|
+
}
|
|
434
|
+
} catch (error) {
|
|
435
|
+
issues.push({
|
|
436
|
+
severity: "warning",
|
|
437
|
+
file: SKILL_CATEGORIES_YAML_PATH,
|
|
438
|
+
message: `Cross-reference validation skipped: failed to load categories/rules`
|
|
439
|
+
});
|
|
440
|
+
}
|
|
441
|
+
return buildResult(issues, skillCount);
|
|
442
|
+
}
|
|
443
|
+
function buildResult(issues, skillCount) {
|
|
444
|
+
const errorCount = issues.filter((i) => i.severity === "error").length;
|
|
445
|
+
const warningCount = issues.filter((i) => i.severity === "warning").length;
|
|
446
|
+
return { issues, skillCount, errorCount, warningCount };
|
|
447
|
+
}
|
|
448
|
+
|
|
249
449
|
// src/cli/commands/validate.ts
|
|
250
450
|
var Validate = class _Validate extends BaseCommand {
|
|
251
|
-
static summary = "Validate YAML files against schemas or validate
|
|
252
|
-
static description = "Validates skill/agent YAML files against JSON schemas,
|
|
451
|
+
static summary = "Validate YAML files against schemas, validate compiled plugins, or validate a skills source";
|
|
452
|
+
static description = "Validates skill/agent YAML files against JSON schemas, validates compiled plugin structure and content, or validates a skills source repository for metadata correctness. Without arguments, validates all YAML files in the current directory against their schemas. With --source, validates all skills in the source for schema compliance, cross-references, and conventions. With a path argument or --plugins flag, validates plugin(s) instead.";
|
|
253
453
|
static examples = [
|
|
254
454
|
{
|
|
255
455
|
description: "Validate all YAML schemas",
|
|
256
456
|
command: "<%= config.bin %> <%= command.id %>"
|
|
257
457
|
},
|
|
458
|
+
{
|
|
459
|
+
description: "Validate a skills source repository",
|
|
460
|
+
command: "<%= config.bin %> <%= command.id %> --source ."
|
|
461
|
+
},
|
|
462
|
+
{
|
|
463
|
+
description: "Validate a remote skills source",
|
|
464
|
+
command: "<%= config.bin %> <%= command.id %> --source github:acme-corp/skills"
|
|
465
|
+
},
|
|
258
466
|
{
|
|
259
467
|
description: "Validate a specific plugin",
|
|
260
468
|
command: "<%= config.bin %> <%= command.id %> ./path/to/plugin"
|
|
@@ -294,7 +502,9 @@ var Validate = class _Validate extends BaseCommand {
|
|
|
294
502
|
};
|
|
295
503
|
async run() {
|
|
296
504
|
const { args, flags } = await this.parse(_Validate);
|
|
297
|
-
if (
|
|
505
|
+
if (flags.source) {
|
|
506
|
+
await this.validateSkillsSource(flags.source);
|
|
507
|
+
} else if (args.path || flags.plugins) {
|
|
298
508
|
await this.validatePlugins(args.path, flags.verbose, flags.all);
|
|
299
509
|
} else {
|
|
300
510
|
await this.validateSchemas();
|
|
@@ -317,15 +527,15 @@ var Validate = class _Validate extends BaseCommand {
|
|
|
317
527
|
this.error(`${ERROR_MESSAGES.VALIDATION_FAILED}: ${message}`, { exit: EXIT_CODES.ERROR });
|
|
318
528
|
}
|
|
319
529
|
}
|
|
320
|
-
async validatePlugins(pluginPath,
|
|
321
|
-
const targetPath = pluginPath ?
|
|
530
|
+
async validatePlugins(pluginPath, verbose2, all) {
|
|
531
|
+
const targetPath = pluginPath ? path3.resolve(pluginPath) : process.cwd();
|
|
322
532
|
if (all) {
|
|
323
|
-
await this.validateAllPluginsInDirectory(targetPath,
|
|
533
|
+
await this.validateAllPluginsInDirectory(targetPath, verbose2);
|
|
324
534
|
} else {
|
|
325
|
-
await this.validateSinglePlugin(targetPath,
|
|
535
|
+
await this.validateSinglePlugin(targetPath, verbose2);
|
|
326
536
|
}
|
|
327
537
|
}
|
|
328
|
-
async validateAllPluginsInDirectory(targetPath,
|
|
538
|
+
async validateAllPluginsInDirectory(targetPath, verbose2) {
|
|
329
539
|
this.log("");
|
|
330
540
|
this.log(`Validating all plugins in: ${targetPath}`);
|
|
331
541
|
this.log("");
|
|
@@ -341,7 +551,7 @@ var Validate = class _Validate extends BaseCommand {
|
|
|
341
551
|
this.log(` Invalid: ${result.summary.invalid}`);
|
|
342
552
|
this.log(` With warnings: ${result.summary.withWarnings}`);
|
|
343
553
|
for (const { name, result: pluginResult } of result.results) {
|
|
344
|
-
printPluginValidationResult(name, pluginResult,
|
|
554
|
+
printPluginValidationResult(name, pluginResult, verbose2);
|
|
345
555
|
}
|
|
346
556
|
if (result.valid) {
|
|
347
557
|
this.log("");
|
|
@@ -364,7 +574,7 @@ var Validate = class _Validate extends BaseCommand {
|
|
|
364
574
|
const result = await validatePlugin(targetPath);
|
|
365
575
|
const summary = result.valid ? "Done: Plugin is valid" : "Done: Plugin has errors";
|
|
366
576
|
this.log(summary);
|
|
367
|
-
printPluginValidationResult(
|
|
577
|
+
printPluginValidationResult(path3.basename(targetPath), result, true);
|
|
368
578
|
if (result.valid && result.warnings.length === 0) {
|
|
369
579
|
this.log("");
|
|
370
580
|
this.logSuccess("Plugin validated successfully");
|
|
@@ -382,6 +592,39 @@ var Validate = class _Validate extends BaseCommand {
|
|
|
382
592
|
this.error(`${ERROR_MESSAGES.VALIDATION_FAILED}: ${message}`, { exit: EXIT_CODES.ERROR });
|
|
383
593
|
}
|
|
384
594
|
}
|
|
595
|
+
async validateSkillsSource(source) {
|
|
596
|
+
this.log("");
|
|
597
|
+
this.log(`Validating source: ${source}`);
|
|
598
|
+
this.log("");
|
|
599
|
+
try {
|
|
600
|
+
const result = await validateSource(source);
|
|
601
|
+
this.log(`Checked ${result.skillCount} skill(s)`);
|
|
602
|
+
this.log("");
|
|
603
|
+
for (const issue of result.issues) {
|
|
604
|
+
const prefix = issue.severity === "error" ? "ERROR" : "WARN";
|
|
605
|
+
this.log(` [${prefix}] ${issue.file}: ${issue.message}`);
|
|
606
|
+
}
|
|
607
|
+
if (result.issues.length > 0) {
|
|
608
|
+
this.log("");
|
|
609
|
+
}
|
|
610
|
+
this.log(`Result: ${result.errorCount} error(s), ${result.warningCount} warning(s)`);
|
|
611
|
+
if (result.errorCount > 0) {
|
|
612
|
+
this.log("");
|
|
613
|
+
this.error(ERROR_MESSAGES.VALIDATION_FAILED, { exit: EXIT_CODES.ERROR });
|
|
614
|
+
} else if (result.warningCount > 0) {
|
|
615
|
+
this.log("");
|
|
616
|
+
this.logWarning("Source valid with warnings");
|
|
617
|
+
this.log("");
|
|
618
|
+
} else {
|
|
619
|
+
this.log("");
|
|
620
|
+
this.logSuccess("Source validated successfully");
|
|
621
|
+
this.log("");
|
|
622
|
+
}
|
|
623
|
+
} catch (error) {
|
|
624
|
+
const message = getErrorMessage(error);
|
|
625
|
+
this.error(`${ERROR_MESSAGES.VALIDATION_FAILED}: ${message}`, { exit: EXIT_CODES.ERROR });
|
|
626
|
+
}
|
|
627
|
+
}
|
|
385
628
|
};
|
|
386
629
|
export {
|
|
387
630
|
Validate as default
|