@agents-inc/cli 0.85.0 → 0.87.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 +20 -0
- package/dist/{chunk-6VGBO6SZ.js → chunk-5M6Q5UQO.js} +2 -2
- package/dist/chunk-5UJJQFET.js +564 -0
- package/dist/chunk-5UJJQFET.js.map +1 -0
- package/dist/{chunk-TXW257CU.js → chunk-7FFNNDJQ.js} +181 -202
- package/dist/chunk-7FFNNDJQ.js.map +1 -0
- package/dist/{chunk-YJ2URWF7.js → chunk-B6MYECV6.js} +2 -2
- package/dist/{chunk-G2MINRWX.js → chunk-C5IYJ42F.js} +2 -2
- package/dist/{chunk-7UZUDHP7.js → chunk-CXWBVBDM.js} +2 -2
- package/dist/{chunk-CYPCJ536.js → chunk-FBZR46GC.js} +92 -92
- package/dist/chunk-FBZR46GC.js.map +1 -0
- package/dist/{chunk-LTFGEVTM.js → chunk-HH3AWXF4.js} +3 -3
- package/dist/{chunk-2XVLQDNI.js → chunk-HSLVCKVQ.js} +3 -3
- package/dist/{chunk-TAQGYJIS.js → chunk-HZ2IBXVQ.js} +3 -3
- package/dist/{chunk-LN76TJJP.js → chunk-HZQOFFKA.js} +10 -10
- package/dist/{chunk-W7LHI54P.js → chunk-I44YG6VI.js} +2 -2
- package/dist/{chunk-FT46LN7K.js → chunk-I5AZKNNL.js} +7 -8
- package/dist/chunk-I5AZKNNL.js.map +1 -0
- package/dist/chunk-J6PI73YV.js +68 -0
- package/dist/chunk-J6PI73YV.js.map +1 -0
- package/dist/{chunk-L7COG2EX.js → chunk-LZ7XQ3IU.js} +2 -2
- package/dist/{chunk-LMR7VAP3.js → chunk-MMTMXLI4.js} +2 -2
- package/dist/chunk-N6A7A4RA.js +16 -0
- package/dist/chunk-N6A7A4RA.js.map +1 -0
- package/dist/{chunk-WJKD6EGK.js → chunk-NUU3U43A.js} +5 -6
- package/dist/chunk-NUU3U43A.js.map +1 -0
- package/dist/{chunk-YYIWB42G.js → chunk-Q4DMIPZB.js} +2 -2
- package/dist/{chunk-YSLDMYWP.js → chunk-SGZOFIFF.js} +2 -2
- package/dist/{chunk-FKXD3EXJ.js → chunk-TMTUTUEV.js} +42 -228
- package/dist/chunk-TMTUTUEV.js.map +1 -0
- package/dist/{chunk-WCCWQ56J.js → chunk-UNEJKTLP.js} +3 -3
- package/dist/{chunk-ZGD7PLLC.js → chunk-ZOWRO7UQ.js} +3 -3
- package/dist/commands/build/marketplace.js +3 -3
- package/dist/commands/build/plugins.js +5 -5
- package/dist/commands/build/stack.js +5 -5
- package/dist/commands/compile.js +77 -171
- package/dist/commands/compile.js.map +1 -1
- package/dist/commands/config/index.js +5 -5
- package/dist/commands/config/path.js +4 -4
- package/dist/commands/config/show.js +5 -5
- package/dist/commands/diff.js +161 -167
- package/dist/commands/diff.js.map +1 -1
- package/dist/commands/doctor.js +68 -83
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/edit.js +275 -209
- package/dist/commands/edit.js.map +1 -1
- package/dist/commands/eject.js +206 -124
- package/dist/commands/eject.js.map +1 -1
- package/dist/commands/import/skill.js +175 -144
- package/dist/commands/import/skill.js.map +1 -1
- package/dist/commands/info.js +58 -102
- package/dist/commands/info.js.map +1 -1
- package/dist/commands/init.js +19 -16
- package/dist/commands/list.js +4 -4
- package/dist/commands/new/agent.js +124 -102
- package/dist/commands/new/agent.js.map +1 -1
- package/dist/commands/new/marketplace.js +6 -6
- package/dist/commands/new/marketplace.js.map +1 -1
- package/dist/commands/new/skill.js +328 -15
- package/dist/commands/new/skill.js.map +1 -1
- package/dist/commands/outdated.js +16 -24
- package/dist/commands/outdated.js.map +1 -1
- package/dist/commands/search.js +166 -132
- package/dist/commands/search.js.map +1 -1
- package/dist/commands/uninstall.js +269 -189
- package/dist/commands/uninstall.js.map +1 -1
- package/dist/commands/update.js +238 -219
- package/dist/commands/update.js.map +1 -1
- package/dist/commands/validate.js +4 -4
- package/dist/components/skill-search/skill-search.js +2 -1
- package/dist/components/wizard/category-grid.test.js +4 -4
- package/dist/components/wizard/domain-selection.js +5 -5
- package/dist/components/wizard/help-modal.js +5 -5
- package/dist/components/wizard/source-grid.test.js +4 -4
- package/dist/components/wizard/stack-selection.js +5 -5
- package/dist/components/wizard/step-agents.js +5 -5
- package/dist/components/wizard/step-agents.test.js +5 -5
- package/dist/components/wizard/step-build.js +5 -5
- package/dist/components/wizard/step-build.test.js +5 -5
- package/dist/components/wizard/step-confirm.test.js +4 -4
- package/dist/components/wizard/step-settings.js +4 -4
- package/dist/components/wizard/step-settings.test.js +7 -7
- package/dist/components/wizard/step-sources.js +5 -5
- package/dist/components/wizard/step-sources.test.js +5 -5
- package/dist/components/wizard/step-stack.js +6 -6
- package/dist/components/wizard/step-stack.test.js +6 -6
- package/dist/components/wizard/wizard-layout.js +6 -6
- package/dist/components/wizard/wizard.js +14 -14
- package/dist/hooks/init.js +19 -16
- package/dist/hooks/init.js.map +1 -1
- package/dist/{loader-GT2A7R7U.js → loader-GSEGPK64.js} +3 -3
- package/dist/{source-loader-TNQW4P47.js → source-loader-OGFTIRIX.js} +4 -4
- package/dist/{source-manager-INRXRFJE.js → source-manager-FMMDDVZA.js} +4 -4
- package/dist/stores/wizard-store.js +4 -4
- package/dist/stores/wizard-store.test.js +4 -4
- package/package.json +1 -1
- package/dist/chunk-AABH2HSE.js +0 -340
- package/dist/chunk-AABH2HSE.js.map +0 -1
- package/dist/chunk-CYPCJ536.js.map +0 -1
- package/dist/chunk-FKXD3EXJ.js.map +0 -1
- package/dist/chunk-FT46LN7K.js.map +0 -1
- package/dist/chunk-TXW257CU.js.map +0 -1
- package/dist/chunk-WJKD6EGK.js.map +0 -1
- /package/dist/{chunk-6VGBO6SZ.js.map → chunk-5M6Q5UQO.js.map} +0 -0
- /package/dist/{chunk-YJ2URWF7.js.map → chunk-B6MYECV6.js.map} +0 -0
- /package/dist/{chunk-G2MINRWX.js.map → chunk-C5IYJ42F.js.map} +0 -0
- /package/dist/{chunk-7UZUDHP7.js.map → chunk-CXWBVBDM.js.map} +0 -0
- /package/dist/{chunk-LTFGEVTM.js.map → chunk-HH3AWXF4.js.map} +0 -0
- /package/dist/{chunk-2XVLQDNI.js.map → chunk-HSLVCKVQ.js.map} +0 -0
- /package/dist/{chunk-TAQGYJIS.js.map → chunk-HZ2IBXVQ.js.map} +0 -0
- /package/dist/{chunk-LN76TJJP.js.map → chunk-HZQOFFKA.js.map} +0 -0
- /package/dist/{chunk-W7LHI54P.js.map → chunk-I44YG6VI.js.map} +0 -0
- /package/dist/{chunk-L7COG2EX.js.map → chunk-LZ7XQ3IU.js.map} +0 -0
- /package/dist/{chunk-LMR7VAP3.js.map → chunk-MMTMXLI4.js.map} +0 -0
- /package/dist/{chunk-YYIWB42G.js.map → chunk-Q4DMIPZB.js.map} +0 -0
- /package/dist/{chunk-YSLDMYWP.js.map → chunk-SGZOFIFF.js.map} +0 -0
- /package/dist/{chunk-WCCWQ56J.js.map → chunk-UNEJKTLP.js.map} +0 -0
- /package/dist/{chunk-ZGD7PLLC.js.map → chunk-ZOWRO7UQ.js.map} +0 -0
- /package/dist/{loader-GT2A7R7U.js.map → loader-GSEGPK64.js.map} +0 -0
- /package/dist/{source-loader-TNQW4P47.js.map → source-loader-OGFTIRIX.js.map} +0 -0
- /package/dist/{source-manager-INRXRFJE.js.map → source-manager-FMMDDVZA.js.map} +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/cli/commands/eject.ts"],"sourcesContent":["import { Args, Flags } from \"@oclif/core\";\nimport path from \"path\";\nimport os from \"os\";\nimport { BaseCommand } from \"../base-command.js\";\nimport {\n copy,\n ensureDir,\n directoryExists,\n fileExists,\n listDirectories,\n writeFile,\n} from \"../utils/fs.js\";\nimport {\n CLAUDE_SRC_DIR,\n DEFAULT_BRANDING,\n DIRS,\n LOCAL_SKILLS_PATH,\n PROJECT_ROOT,\n STANDARD_FILES,\n} from \"../consts.js\";\nimport { EXIT_CODES } from \"../lib/exit-codes.js\";\nimport { loadSkillsMatrixFromSource, type SourceLoadResult } from \"../lib/loading/index.js\";\nimport { matrix } from \"../lib/matrix/matrix-provider\";\nimport { copySkillsToLocalFlattened } from \"../lib/skills/index.js\";\nimport type { SkillId } from \"../types/index.js\";\nimport { typedKeys } from \"../utils/typed-object.js\";\nimport {\n loadProjectSourceConfig,\n resolveSource,\n saveSourceToProjectConfig,\n} from \"../lib/configuration/index.js\";\n\nconst EJECT_TYPES = [\"agent-partials\", \"templates\", \"skills\", \"all\"] as const;\ntype EjectType = (typeof EJECT_TYPES)[number];\n\nfunction isEjectType(value: string): value is EjectType {\n return (EJECT_TYPES as readonly string[]).includes(value);\n}\n\nexport default class Eject extends BaseCommand {\n static summary = \"Eject skills, agent partials, or templates for local customization\";\n static description =\n \"Copy agent partials, templates, or skills to your project for customization. \" +\n \"Agent partials and templates are always copied from the CLI. \" +\n \"Skills are copied from the configured source (public marketplace by default).\";\n\n static examples = [\n {\n description: \"Eject agent partials for customization\",\n command: \"<%= config.bin %> <%= command.id %> agent-partials\",\n },\n {\n description: \"Eject only agent templates\",\n command: \"<%= config.bin %> <%= command.id %> templates\",\n },\n {\n description: \"Eject skills to local directory\",\n command: \"<%= config.bin %> <%= command.id %> skills\",\n },\n {\n description: \"Eject everything with force overwrite\",\n command: \"<%= config.bin %> <%= command.id %> all --force\",\n },\n {\n description: \"Eject to a custom output directory\",\n command: \"<%= config.bin %> <%= command.id %> skills -o ./custom-dir\",\n },\n ];\n\n static args = {\n type: Args.string({\n description: \"What to eject: agent-partials, templates, skills, all\",\n required: false,\n options: [...EJECT_TYPES],\n }),\n };\n\n static flags = {\n ...BaseCommand.baseFlags,\n force: Flags.boolean({\n char: \"f\",\n description: \"Overwrite existing files\",\n default: false,\n }),\n output: Flags.string({\n char: \"o\",\n description: \"Output directory (default: .claude/ in current directory)\",\n }),\n refresh: Flags.boolean({\n description: \"Force refresh from remote source\",\n default: false,\n }),\n };\n\n async run(): Promise<void> {\n const { args, flags } = await this.parse(Eject);\n const projectDir = process.cwd();\n\n if (!args.type) {\n this.error(\"Please specify what to eject: agent-partials, templates, skills, or all\", {\n exit: EXIT_CODES.INVALID_ARGS,\n });\n }\n\n if (!isEjectType(args.type)) {\n this.error(`Unknown eject type: ${args.type}`, {\n exit: EXIT_CODES.INVALID_ARGS,\n });\n }\n\n let outputBase: string;\n if (flags.output) {\n const expandedPath = flags.output.startsWith(\"~\")\n ? path.join(os.homedir(), flags.output.slice(1))\n : flags.output;\n outputBase = path.resolve(projectDir, expandedPath);\n\n if (await fileExists(outputBase)) {\n this.error(`Output path exists as a file: ${outputBase}`, {\n exit: EXIT_CODES.INVALID_ARGS,\n });\n }\n } else {\n outputBase = path.join(projectDir, CLAUDE_SRC_DIR);\n }\n\n this.log(\"\");\n this.log(`${DEFAULT_BRANDING.NAME} Eject`);\n this.log(\"\");\n\n if (flags.output) {\n this.log(`Output directory: ${outputBase}`);\n }\n\n const ejectType = args.type;\n const directOutput = !!flags.output;\n\n let sourceResult: SourceLoadResult | undefined;\n if (ejectType === \"skills\" || ejectType === \"all\") {\n sourceResult = await loadSkillsMatrixFromSource({\n sourceFlag: flags.source,\n projectDir,\n forceRefresh: flags.refresh,\n });\n }\n\n switch (ejectType) {\n case \"agent-partials\":\n await this.ejectAgentPartials(outputBase, flags.force, directOutput, false);\n break;\n case \"templates\":\n await this.ejectAgentPartials(outputBase, flags.force, directOutput, true);\n break;\n case \"skills\":\n await this.ejectSkills(\n projectDir,\n flags.force,\n sourceResult!,\n directOutput,\n directOutput ? outputBase : undefined,\n );\n break;\n case \"all\":\n await this.ejectAgentPartials(outputBase, flags.force, directOutput, false);\n await this.ejectAgentPartials(outputBase, true, directOutput, true);\n await this.ejectSkills(\n projectDir,\n flags.force,\n sourceResult!,\n directOutput,\n directOutput ? outputBase : undefined,\n );\n break;\n default:\n break;\n }\n\n if (flags.source) {\n await saveSourceToProjectConfig(projectDir, flags.source, path.basename(projectDir));\n this.log(`Source saved to .claude-src/config.ts`);\n }\n\n await this.ensureMinimalConfig(projectDir, flags.source, sourceResult);\n\n this.log(\"\");\n this.logSuccess(\"Eject complete!\");\n this.log(\"\");\n }\n\n // Ensures a minimal config exists so `agentsinc compile` works after eject\n private async ensureMinimalConfig(\n projectDir: string,\n sourceFlag?: string,\n sourceResult?: SourceLoadResult,\n ): Promise<void> {\n const tsConfigPath = path.join(projectDir, CLAUDE_SRC_DIR, STANDARD_FILES.CONFIG_TS);\n\n if (await fileExists(tsConfigPath)) {\n return;\n }\n\n const projectName = path.basename(projectDir);\n\n const config: Record<string, unknown> = {\n name: projectName,\n };\n\n const resolvedConfig =\n sourceResult?.sourceConfig ?? (await resolveSource(sourceFlag, projectDir));\n\n if (sourceFlag) {\n config.source = sourceFlag;\n } else if (resolvedConfig.source) {\n config.source = resolvedConfig.source;\n }\n\n if (resolvedConfig.marketplace) {\n config.marketplace = resolvedConfig.marketplace;\n }\n\n const existingProjectConfig = await loadProjectSourceConfig(projectDir);\n if (existingProjectConfig?.author) {\n config.author = existingProjectConfig.author;\n }\n if (existingProjectConfig?.agentsSource) {\n config.agentsSource = existingProjectConfig.agentsSource;\n }\n\n await ensureDir(path.join(projectDir, CLAUDE_SRC_DIR));\n\n // JSON.parse(JSON.stringify(x)) removes undefined values\n const cleaned = JSON.parse(JSON.stringify(config));\n const body = JSON.stringify(cleaned, null, 2);\n const content = `export default ${body};\\n`;\n\n await writeFile(tsConfigPath, content);\n\n this.logSuccess(`Created ${CLAUDE_SRC_DIR}/config.ts`);\n }\n\n private async ejectAgentPartials(\n outputBase: string,\n force: boolean,\n directOutput = false,\n templatesFlag = false,\n ): Promise<void> {\n const sourceDir = templatesFlag\n ? path.join(PROJECT_ROOT, DIRS.templates)\n : path.join(PROJECT_ROOT, DIRS.agents);\n\n if (!(await directoryExists(sourceDir))) {\n this.warn(\n templatesFlag ? \"No agent templates found in CLI.\" : \"No agent partials found in CLI.\",\n );\n return;\n }\n\n const destDir = directOutput\n ? outputBase\n : templatesFlag\n ? path.join(outputBase, path.basename(DIRS.agents), path.basename(DIRS.templates))\n : path.join(outputBase, path.basename(DIRS.agents));\n\n const templatesBasename = path.basename(DIRS.templates);\n\n if ((await directoryExists(destDir)) && !force) {\n if (templatesFlag) {\n this.warn(`Agent templates already exist at ${destDir}. Use --force to overwrite.`);\n return;\n }\n\n const hasTemplates = await directoryExists(path.join(destDir, templatesBasename));\n if ((await this.hasAgentPartialDirs(destDir)) && !hasTemplates) {\n this.warn(`Agent partials already exist at ${destDir}. Use --force to overwrite.`);\n return;\n }\n }\n\n await ensureDir(destDir);\n\n const skipTemplates =\n !templatesFlag && !force && (await directoryExists(path.join(destDir, templatesBasename)));\n\n if (skipTemplates) {\n const sourceEntries = await listDirectories(sourceDir);\n const nonTemplateEntries = sourceEntries.filter((entry) => entry !== templatesBasename);\n for (const entry of nonTemplateEntries) {\n await copy(path.join(sourceDir, entry), path.join(destDir, entry));\n }\n this.warn(\n \"Agent templates already exist — skipping templates, only ejecting agent partials.\",\n );\n } else {\n await copy(sourceDir, destDir);\n }\n\n this.logSuccess(\n `${templatesFlag ? \"Agent templates\" : \"Agent partials\"} ejected to ${destDir}`,\n );\n this.log(\n templatesFlag\n ? \"You can now customize agent templates locally.\"\n : \"You can now customize templates, agent intro, workflow, and examples locally.\",\n );\n }\n\n /** Checks whether the agents directory contains any agent subdirectories (not just _templates). */\n private async hasAgentPartialDirs(agentsDir: string): Promise<boolean> {\n const subdirs = await listDirectories(agentsDir);\n const templatesBasename = path.basename(DIRS.templates);\n return subdirs.some((dir) => dir !== templatesBasename);\n }\n\n private async ejectSkills(\n projectDir: string,\n force: boolean,\n sourceResult: SourceLoadResult,\n directOutput = false,\n customOutputBase?: string,\n ): Promise<void> {\n const destDir =\n directOutput && customOutputBase\n ? customOutputBase\n : path.join(projectDir, LOCAL_SKILLS_PATH);\n\n if ((await directoryExists(destDir)) && !force) {\n this.warn(`Skills already exist at ${destDir}. Use --force to overwrite.`);\n return;\n }\n\n const skillIds = typedKeys<SkillId>(matrix.skills).filter(\n (skillId) => !matrix.skills[skillId]?.local,\n );\n\n if (skillIds.length === 0) {\n this.warn(\"No skills found in source to eject.\");\n return;\n }\n\n await ensureDir(destDir);\n\n const copiedSkills = await copySkillsToLocalFlattened(skillIds, destDir, matrix, sourceResult);\n\n const sourceLabel = sourceResult.isLocal\n ? sourceResult.sourcePath\n : sourceResult.marketplace || sourceResult.sourceConfig.source;\n\n this.logSuccess(`${copiedSkills.length} skills ejected to ${destDir} from ${sourceLabel}`);\n this.log(\"You can now customize skill content locally.\");\n }\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/cli/commands/eject.ts"],"sourcesContent":["import { Args, Flags } from \"@oclif/core\";\nimport path from \"path\";\nimport os from \"os\";\nimport { BaseCommand } from \"../base-command.js\";\nimport {\n copy,\n ensureDir,\n directoryExists,\n fileExists,\n listDirectories,\n writeFile,\n} from \"../utils/fs.js\";\nimport {\n CLAUDE_SRC_DIR,\n DEFAULT_BRANDING,\n DIRS,\n LOCAL_SKILLS_PATH,\n PROJECT_ROOT,\n STANDARD_FILES,\n} from \"../consts.js\";\nimport { EXIT_CODES } from \"../lib/exit-codes.js\";\nimport { type SourceLoadResult } from \"../lib/loading/index.js\";\nimport { loadSource } from \"../lib/operations/index.js\";\nimport { matrix } from \"../lib/matrix/matrix-provider\";\nimport {\n saveSourceToProjectConfig,\n resolveSource,\n loadProjectSourceConfig,\n} from \"../lib/configuration/index.js\";\nimport { copySkillsToLocalFlattened, type CopiedSkill } from \"../lib/skills/index.js\";\nimport type { MergedSkillsMatrix, SkillId } from \"../types/index.js\";\nimport { typedKeys } from \"../utils/typed-object.js\";\n\nconst EJECT_TYPES = [\"agent-partials\", \"templates\", \"skills\", \"all\"] as const;\ntype EjectType = (typeof EJECT_TYPES)[number];\n\nfunction isEjectType(value: string): value is EjectType {\n return (EJECT_TYPES as readonly string[]).includes(value);\n}\n\nexport default class Eject extends BaseCommand {\n static summary = \"Eject skills, agent partials, or templates for local customization\";\n static description =\n \"Copy agent partials, templates, or skills to your project for customization. \" +\n \"Agent partials and templates are always copied from the CLI. \" +\n \"Skills are copied from the configured source (public marketplace by default).\";\n\n static examples = [\n {\n description: \"Eject agent partials for customization\",\n command: \"<%= config.bin %> <%= command.id %> agent-partials\",\n },\n {\n description: \"Eject only agent templates\",\n command: \"<%= config.bin %> <%= command.id %> templates\",\n },\n {\n description: \"Eject skills to local directory\",\n command: \"<%= config.bin %> <%= command.id %> skills\",\n },\n {\n description: \"Eject everything with force overwrite\",\n command: \"<%= config.bin %> <%= command.id %> all --force\",\n },\n {\n description: \"Eject to a custom output directory\",\n command: \"<%= config.bin %> <%= command.id %> skills -o ./custom-dir\",\n },\n ];\n\n static args = {\n type: Args.string({\n description: \"What to eject: agent-partials, templates, skills, all\",\n required: false,\n options: [...EJECT_TYPES],\n }),\n };\n\n static flags = {\n ...BaseCommand.baseFlags,\n force: Flags.boolean({\n char: \"f\",\n description: \"Overwrite existing files\",\n default: false,\n }),\n output: Flags.string({\n char: \"o\",\n description: \"Output directory (default: .claude/ in current directory)\",\n }),\n refresh: Flags.boolean({\n description: \"Force refresh from remote source\",\n default: false,\n }),\n };\n\n async run(): Promise<void> {\n const { args, flags } = await this.parse(Eject);\n const projectDir = process.cwd();\n\n const ejectType = this.validateEjectType(args.type);\n const outputBase = await this.resolveOutputBase(flags, projectDir);\n\n this.printHeader(flags.output ? outputBase : undefined);\n\n const sourceResult = await this.loadSourceIfNeeded(ejectType, flags, projectDir);\n await this.executeEject(ejectType, outputBase, flags, projectDir, sourceResult);\n await this.saveSourceIfFlagged(flags.source, projectDir);\n await this.ensureConfig(projectDir, flags.source, sourceResult);\n\n this.log(\"\");\n this.logSuccess(\"Eject complete!\");\n this.log(\"\");\n }\n\n private validateEjectType(typeArg: string | undefined): EjectType {\n if (!typeArg) {\n this.error(\"Please specify what to eject: agent-partials, templates, skills, or all\", {\n exit: EXIT_CODES.INVALID_ARGS,\n });\n }\n\n if (!isEjectType(typeArg)) {\n this.error(`Unknown eject type: ${typeArg}`, {\n exit: EXIT_CODES.INVALID_ARGS,\n });\n }\n\n return typeArg;\n }\n\n private async resolveOutputBase(flags: { output?: string }, projectDir: string): Promise<string> {\n if (flags.output) {\n const expandedPath = flags.output.startsWith(\"~\")\n ? path.join(os.homedir(), flags.output.slice(1))\n : flags.output;\n const outputBase = path.resolve(projectDir, expandedPath);\n\n if (await fileExists(outputBase)) {\n this.error(`Output path exists as a file: ${outputBase}`, {\n exit: EXIT_CODES.INVALID_ARGS,\n });\n }\n\n return outputBase;\n }\n\n return path.join(projectDir, CLAUDE_SRC_DIR);\n }\n\n private printHeader(outputBase?: string): void {\n this.log(\"\");\n this.log(`${DEFAULT_BRANDING.NAME} Eject`);\n this.log(\"\");\n\n if (outputBase) {\n this.log(`Output directory: ${outputBase}`);\n }\n }\n\n private async loadSourceIfNeeded(\n ejectType: EjectType,\n flags: { source?: string; refresh: boolean },\n projectDir: string,\n ): Promise<SourceLoadResult | undefined> {\n if (ejectType === \"skills\" || ejectType === \"all\") {\n const loaded = await loadSource({\n sourceFlag: flags.source,\n projectDir,\n forceRefresh: flags.refresh,\n });\n return loaded.sourceResult;\n }\n return undefined;\n }\n\n private async executeEject(\n ejectType: EjectType,\n outputBase: string,\n flags: { force: boolean; output?: string },\n projectDir: string,\n sourceResult: SourceLoadResult | undefined,\n ): Promise<void> {\n const directOutput = !!flags.output;\n\n switch (ejectType) {\n case \"agent-partials\":\n await this.handleAgentPartials(outputBase, flags.force, directOutput, false);\n break;\n case \"templates\":\n await this.handleAgentPartials(outputBase, flags.force, directOutput, true);\n break;\n case \"skills\":\n await this.handleSkills(projectDir, flags.force, sourceResult!, directOutput, outputBase);\n break;\n case \"all\":\n await this.handleAgentPartials(outputBase, flags.force, directOutput, false);\n await this.handleAgentPartials(outputBase, true, directOutput, true);\n await this.handleSkills(projectDir, flags.force, sourceResult!, directOutput, outputBase);\n break;\n default:\n break;\n }\n }\n\n private async saveSourceIfFlagged(\n sourceFlag: string | undefined,\n projectDir: string,\n ): Promise<void> {\n if (sourceFlag) {\n await saveSourceToProjectConfig(projectDir, sourceFlag, path.basename(projectDir));\n this.log(`Source saved to .claude-src/config.ts`);\n }\n }\n\n private async ensureConfig(\n projectDir: string,\n sourceFlag: string | undefined,\n sourceResult: SourceLoadResult | undefined,\n ): Promise<void> {\n const configResult = await ensureMinimalConfig({\n projectDir,\n sourceFlag,\n sourceResult,\n });\n if (configResult.created) {\n this.logSuccess(`Created ${CLAUDE_SRC_DIR}/config.ts`);\n }\n }\n\n private async handleAgentPartials(\n outputBase: string,\n force: boolean,\n directOutput: boolean,\n templatesOnly: boolean,\n ): Promise<void> {\n const result = await ejectAgentPartials({\n outputBase,\n force,\n directOutput,\n templatesOnly,\n });\n\n if (result.skipped) {\n this.warn(result.skipReason!);\n return;\n }\n\n if (result.templatesSkipped) {\n this.warn(\n \"Agent templates already exist — skipping templates, only ejecting agent partials.\",\n );\n }\n\n this.logSuccess(\n `${templatesOnly ? \"Agent templates\" : \"Agent partials\"} ejected to ${result.destDir}`,\n );\n this.log(\n templatesOnly\n ? \"You can now customize agent templates locally.\"\n : \"You can now customize templates, agent intro, workflow, and examples locally.\",\n );\n }\n\n private async handleSkills(\n projectDir: string,\n force: boolean,\n sourceResult: SourceLoadResult,\n directOutput: boolean,\n outputBase: string,\n ): Promise<void> {\n const result = await ejectSkills({\n projectDir,\n force,\n sourceResult,\n matrix,\n directOutput,\n customOutputBase: directOutput ? outputBase : undefined,\n });\n\n if (result.skipped) {\n this.warn(result.skipReason!);\n return;\n }\n\n this.logSuccess(\n `${result.copiedSkills.length} skills ejected to ${result.destDir} from ${result.sourceLabel}`,\n );\n this.log(\"You can now customize skill content locally.\");\n }\n}\n\ntype EjectAgentPartialsOptions = {\n outputBase: string;\n force: boolean;\n /** When true, outputBase is used directly as the destination (no subdirectory nesting). */\n directOutput?: boolean;\n /** When true, ejects only the _templates directory instead of the full agents directory. */\n templatesOnly?: boolean;\n};\n\ntype EjectAgentPartialsResult = {\n /** Whether the operation was skipped (e.g. destination already exists without --force). */\n skipped: boolean;\n /** Human-readable reason when skipped. */\n skipReason?: string;\n /** Destination directory that was written to (undefined when skipped). */\n destDir?: string;\n /** Whether templates were skipped during a full agent-partials eject (existing templates preserved). */\n templatesSkipped: boolean;\n};\n\n/**\n * Copies agent partials or templates from the CLI source to a target directory.\n *\n * When `templatesOnly` is true, copies only the _templates subdirectory.\n * When false, copies the full agents directory (optionally skipping existing templates).\n *\n * Returns structured data — the command decides what to log.\n */\nasync function ejectAgentPartials(\n options: EjectAgentPartialsOptions,\n): Promise<EjectAgentPartialsResult> {\n const { outputBase, force, directOutput = false, templatesOnly = false } = options;\n\n const sourceDir = templatesOnly\n ? path.join(PROJECT_ROOT, DIRS.templates)\n : path.join(PROJECT_ROOT, DIRS.agents);\n\n if (!(await directoryExists(sourceDir))) {\n return {\n skipped: true,\n skipReason: templatesOnly\n ? \"No agent templates found in CLI.\"\n : \"No agent partials found in CLI.\",\n templatesSkipped: false,\n };\n }\n\n const destDir = directOutput\n ? outputBase\n : templatesOnly\n ? path.join(outputBase, path.basename(DIRS.agents), path.basename(DIRS.templates))\n : path.join(outputBase, path.basename(DIRS.agents));\n\n const templatesBasename = path.basename(DIRS.templates);\n\n if ((await directoryExists(destDir)) && !force) {\n if (templatesOnly) {\n return {\n skipped: true,\n skipReason: `Agent templates already exist at ${destDir}. Use --force to overwrite.`,\n templatesSkipped: false,\n };\n }\n\n const hasTemplates = await directoryExists(path.join(destDir, templatesBasename));\n if ((await hasAgentPartialDirs(destDir)) && !hasTemplates) {\n return {\n skipped: true,\n skipReason: `Agent partials already exist at ${destDir}. Use --force to overwrite.`,\n templatesSkipped: false,\n };\n }\n }\n\n await ensureDir(destDir);\n\n const skipTemplates =\n !templatesOnly && !force && (await directoryExists(path.join(destDir, templatesBasename)));\n\n if (skipTemplates) {\n const sourceEntries = await listDirectories(sourceDir);\n const nonTemplateEntries = sourceEntries.filter((entry) => entry !== templatesBasename);\n for (const entry of nonTemplateEntries) {\n await copy(path.join(sourceDir, entry), path.join(destDir, entry));\n }\n } else {\n await copy(sourceDir, destDir);\n }\n\n return {\n skipped: false,\n destDir,\n templatesSkipped: skipTemplates,\n };\n}\n\ntype EjectSkillsOptions = {\n projectDir: string;\n force: boolean;\n sourceResult: SourceLoadResult;\n matrix: MergedSkillsMatrix;\n /** When true, uses customOutputBase as destination instead of LOCAL_SKILLS_PATH. */\n directOutput?: boolean;\n customOutputBase?: string;\n};\n\ntype EjectSkillsResult = {\n /** Whether the operation was skipped. */\n skipped: boolean;\n /** Human-readable reason when skipped. */\n skipReason?: string;\n /** Array of skills that were copied. */\n copiedSkills: CopiedSkill[];\n /** Destination directory that was written to. */\n destDir?: string;\n /** Label describing the source that skills were copied from. */\n sourceLabel?: string;\n};\n\n/**\n * Copies non-local skills from source to a target directory.\n *\n * Filters out skills already marked as local, then copies the remaining skills\n * using copySkillsToLocalFlattened.\n *\n * Returns structured data — the command decides what to log.\n */\nasync function ejectSkills(options: EjectSkillsOptions): Promise<EjectSkillsResult> {\n const {\n projectDir,\n force,\n sourceResult,\n matrix,\n directOutput = false,\n customOutputBase,\n } = options;\n\n const destDir =\n directOutput && customOutputBase ? customOutputBase : path.join(projectDir, LOCAL_SKILLS_PATH);\n\n if ((await directoryExists(destDir)) && !force) {\n return {\n skipped: true,\n skipReason: `Skills already exist at ${destDir}. Use --force to overwrite.`,\n copiedSkills: [],\n };\n }\n\n const skillIds = typedKeys<SkillId>(matrix.skills).filter(\n (skillId) => !matrix.skills[skillId]?.local,\n );\n\n if (skillIds.length === 0) {\n return {\n skipped: true,\n skipReason: \"No skills found in source to eject.\",\n copiedSkills: [],\n };\n }\n\n await ensureDir(destDir);\n\n const copiedSkills = await copySkillsToLocalFlattened(skillIds, destDir, matrix, sourceResult);\n\n const sourceLabel = sourceResult.isLocal\n ? sourceResult.sourcePath\n : sourceResult.marketplace || sourceResult.sourceConfig.source;\n\n return {\n skipped: false,\n copiedSkills,\n destDir,\n sourceLabel,\n };\n}\n\ntype EnsureMinimalConfigOptions = {\n projectDir: string;\n sourceFlag?: string;\n sourceResult?: SourceLoadResult;\n};\n\ntype EnsureMinimalConfigResult = {\n /** Path to the config file. */\n configPath: string;\n /** Whether a new config was created. */\n created: boolean;\n};\n\n/**\n * Ensures a minimal config.ts exists so `agentsinc compile` works after eject.\n *\n * If the config already exists, returns immediately with `created: false`.\n * Otherwise generates a minimal config from the resolved source and project metadata.\n *\n * Returns structured data — the command decides what to log.\n */\nasync function ensureMinimalConfig(\n options: EnsureMinimalConfigOptions,\n): Promise<EnsureMinimalConfigResult> {\n const { projectDir, sourceFlag, sourceResult } = options;\n\n const tsConfigPath = path.join(projectDir, CLAUDE_SRC_DIR, STANDARD_FILES.CONFIG_TS);\n\n if (await fileExists(tsConfigPath)) {\n return { configPath: tsConfigPath, created: false };\n }\n\n const projectName = path.basename(projectDir);\n\n const config: Record<string, unknown> = {\n name: projectName,\n };\n\n const resolvedConfig =\n sourceResult?.sourceConfig ?? (await resolveSource(sourceFlag, projectDir));\n\n if (sourceFlag) {\n config.source = sourceFlag;\n } else if (resolvedConfig.source) {\n config.source = resolvedConfig.source;\n }\n\n if (resolvedConfig.marketplace) {\n config.marketplace = resolvedConfig.marketplace;\n }\n\n const existingProjectConfig = await loadProjectSourceConfig(projectDir);\n if (existingProjectConfig?.author) {\n config.author = existingProjectConfig.author;\n }\n if (existingProjectConfig?.agentsSource) {\n config.agentsSource = existingProjectConfig.agentsSource;\n }\n\n await ensureDir(path.join(projectDir, CLAUDE_SRC_DIR));\n\n // JSON.parse(JSON.stringify(x)) removes undefined values\n const cleaned = JSON.parse(JSON.stringify(config));\n const body = JSON.stringify(cleaned, null, 2);\n const content = `export default ${body};\\n`;\n\n await writeFile(tsConfigPath, content);\n\n return { configPath: tsConfigPath, created: true };\n}\n\n/** Checks whether the agents directory contains any agent subdirectories (not just _templates). */\nasync function hasAgentPartialDirs(agentsDir: string): Promise<boolean> {\n const subdirs = await listDirectories(agentsDir);\n const templatesBasename = path.basename(DIRS.templates);\n return subdirs.some((dir) => dir !== templatesBasename);\n}\n"],"mappings":"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","names":["matrix"]}
|
|
@@ -8,13 +8,13 @@ import {
|
|
|
8
8
|
computeFileHash,
|
|
9
9
|
fetchFromSource,
|
|
10
10
|
getCurrentDate
|
|
11
|
-
} from "../../chunk-
|
|
12
|
-
import "../../chunk-
|
|
11
|
+
} from "../../chunk-TMTUTUEV.js";
|
|
12
|
+
import "../../chunk-B6MYECV6.js";
|
|
13
13
|
import "../../chunk-ANXHMG32.js";
|
|
14
14
|
import {
|
|
15
15
|
BaseCommand,
|
|
16
16
|
EXIT_CODES
|
|
17
|
-
} from "../../chunk-
|
|
17
|
+
} from "../../chunk-MMTMXLI4.js";
|
|
18
18
|
import {
|
|
19
19
|
copy,
|
|
20
20
|
directoryExists,
|
|
@@ -24,8 +24,9 @@ import {
|
|
|
24
24
|
importedSkillMetadataSchema,
|
|
25
25
|
listDirectories,
|
|
26
26
|
readFile,
|
|
27
|
+
warn,
|
|
27
28
|
writeFile
|
|
28
|
-
} from "../../chunk-
|
|
29
|
+
} from "../../chunk-NUU3U43A.js";
|
|
29
30
|
import "../../chunk-6XWHJHNZ.js";
|
|
30
31
|
import {
|
|
31
32
|
DEFAULT_SKILLS_SUBDIR,
|
|
@@ -44,45 +45,6 @@ init_esm_shims();
|
|
|
44
45
|
import { Args, Flags } from "@oclif/core";
|
|
45
46
|
import path from "path";
|
|
46
47
|
import { parse as parseYaml, stringify as stringifyYaml } from "yaml";
|
|
47
|
-
var SKILL_MD_FILE = STANDARD_FILES.SKILL_MD;
|
|
48
|
-
var METADATA_YAML_FILE = STANDARD_FILES.METADATA_YAML;
|
|
49
|
-
var METADATA_JSON_FILE = STANDARD_FILES.METADATA_JSON;
|
|
50
|
-
function parseGitHubSource(source) {
|
|
51
|
-
if (source.startsWith(GITHUB_SOURCE.HTTPS_PREFIX)) {
|
|
52
|
-
const path2 = source.replace(GITHUB_SOURCE.HTTPS_PREFIX, "");
|
|
53
|
-
return {
|
|
54
|
-
gigetSource: `${GITHUB_SOURCE.GITHUB_PREFIX}${path2}`,
|
|
55
|
-
displaySource: source
|
|
56
|
-
};
|
|
57
|
-
}
|
|
58
|
-
if (source.startsWith(GITHUB_SOURCE.GITHUB_PREFIX) || source.startsWith(GITHUB_SOURCE.GH_PREFIX)) {
|
|
59
|
-
const normalized = source.startsWith(GITHUB_SOURCE.GH_PREFIX) ? GITHUB_SOURCE.GITHUB_PREFIX + source.slice(GITHUB_SOURCE.GH_PREFIX.length) : source;
|
|
60
|
-
return {
|
|
61
|
-
gigetSource: normalized,
|
|
62
|
-
displaySource: `${GITHUB_SOURCE.HTTPS_PREFIX}${normalized.replace(GITHUB_SOURCE.GITHUB_PREFIX, "")}`
|
|
63
|
-
};
|
|
64
|
-
}
|
|
65
|
-
if (source.includes("/") && !source.includes(":")) {
|
|
66
|
-
return {
|
|
67
|
-
gigetSource: `${GITHUB_SOURCE.GITHUB_PREFIX}${source}`,
|
|
68
|
-
displaySource: `${GITHUB_SOURCE.HTTPS_PREFIX}${source}`
|
|
69
|
-
};
|
|
70
|
-
}
|
|
71
|
-
return {
|
|
72
|
-
gigetSource: source,
|
|
73
|
-
displaySource: source
|
|
74
|
-
};
|
|
75
|
-
}
|
|
76
|
-
async function discoverValidSkills(skillsDir, skillDirs) {
|
|
77
|
-
const validSkills = [];
|
|
78
|
-
for (const skillDir of skillDirs) {
|
|
79
|
-
const skillMdPath = path.join(skillsDir, skillDir, SKILL_MD_FILE);
|
|
80
|
-
if (await fileExists(skillMdPath)) {
|
|
81
|
-
validSkills.push(skillDir);
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
return validSkills.sort();
|
|
85
|
-
}
|
|
86
48
|
var ImportSkill = class _ImportSkill extends BaseCommand {
|
|
87
49
|
static summary = "Import a skill from a third-party GitHub repository";
|
|
88
50
|
static description = "Download and import skills from external GitHub repositories into your local .claude/skills/ directory. Supports importing specific skills or listing available skills.";
|
|
@@ -144,9 +106,26 @@ var ImportSkill = class _ImportSkill extends BaseCommand {
|
|
|
144
106
|
async run() {
|
|
145
107
|
const { args, flags } = await this.parse(_ImportSkill);
|
|
146
108
|
const projectDir = process.cwd();
|
|
109
|
+
this.printHeader();
|
|
110
|
+
this.validateFlags(flags);
|
|
111
|
+
const { gigetSource, displaySource } = parseGitHubSource(args.source);
|
|
112
|
+
this.log(`Source: ${displaySource}`);
|
|
113
|
+
const repoPath = await this.fetchRepository(gigetSource, args.source, flags.refresh);
|
|
114
|
+
const skillsDir = this.resolveSkillsDir(repoPath, flags.subdir);
|
|
115
|
+
const availableSkills = await this.discoverAndValidate(skillsDir, flags.subdir);
|
|
116
|
+
if (flags.list) {
|
|
117
|
+
this.listAvailableSkills(availableSkills);
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
const skillsToImport = this.resolveSkillsToImport(flags, availableSkills);
|
|
121
|
+
await this.importSkills(skillsToImport, skillsDir, projectDir, displaySource, flags.force);
|
|
122
|
+
}
|
|
123
|
+
printHeader() {
|
|
147
124
|
this.log("");
|
|
148
125
|
this.log("Import Third-Party Skill");
|
|
149
126
|
this.log("");
|
|
127
|
+
}
|
|
128
|
+
validateFlags(flags) {
|
|
150
129
|
if (!flags.list && !flags.skill && !flags.all) {
|
|
151
130
|
this.error("Please specify --skill <name>, --all, or --list to list available skills", {
|
|
152
131
|
exit: EXIT_CODES.INVALID_ARGS
|
|
@@ -157,22 +136,23 @@ var ImportSkill = class _ImportSkill extends BaseCommand {
|
|
|
157
136
|
exit: EXIT_CODES.INVALID_ARGS
|
|
158
137
|
});
|
|
159
138
|
}
|
|
160
|
-
|
|
161
|
-
|
|
139
|
+
}
|
|
140
|
+
async fetchRepository(gigetSource, sourceArg, refresh) {
|
|
162
141
|
this.log(STATUS_MESSAGES.FETCHING_REPOSITORY);
|
|
163
|
-
let repoPath;
|
|
164
142
|
try {
|
|
165
|
-
const result = await
|
|
166
|
-
|
|
143
|
+
const result = await fetchSkillSource({
|
|
144
|
+
gigetSource,
|
|
145
|
+
forceRefresh: refresh
|
|
167
146
|
});
|
|
168
|
-
repoPath = result.path;
|
|
169
147
|
this.log(result.fromCache ? "Using cached source" : "Downloaded fresh copy");
|
|
148
|
+
return result.path;
|
|
170
149
|
} catch (error) {
|
|
171
|
-
this.error(error instanceof Error ? error.message : `Failed to fetch: ${
|
|
150
|
+
this.error(error instanceof Error ? error.message : `Failed to fetch: ${sourceArg}`, {
|
|
172
151
|
exit: EXIT_CODES.NETWORK_ERROR
|
|
173
152
|
});
|
|
174
153
|
}
|
|
175
|
-
|
|
154
|
+
}
|
|
155
|
+
resolveSkillsDir(repoPath, subdir) {
|
|
176
156
|
if (/\0/.test(subdir)) {
|
|
177
157
|
this.error("--subdir contains null bytes", {
|
|
178
158
|
exit: EXIT_CODES.INVALID_ARGS
|
|
@@ -190,37 +170,41 @@ var ImportSkill = class _ImportSkill extends BaseCommand {
|
|
|
190
170
|
exit: EXIT_CODES.INVALID_ARGS
|
|
191
171
|
});
|
|
192
172
|
}
|
|
173
|
+
return skillsDir;
|
|
174
|
+
}
|
|
175
|
+
async discoverAndValidate(skillsDir, subdir) {
|
|
193
176
|
if (!await directoryExists(skillsDir)) {
|
|
194
177
|
this.error(
|
|
195
|
-
`Skills directory not found: ${
|
|
196
|
-
The repository doesn't have a '${
|
|
178
|
+
`Skills directory not found: ${subdir}
|
|
179
|
+
The repository doesn't have a '${subdir}' directory.
|
|
197
180
|
Use --subdir to specify a different location.`,
|
|
198
181
|
{ exit: EXIT_CODES.INVALID_ARGS }
|
|
199
182
|
);
|
|
200
183
|
}
|
|
201
|
-
const
|
|
202
|
-
const availableSkills = await discoverValidSkills(skillsDir, skillDirs);
|
|
184
|
+
const availableSkills = await discoverValidSkills(skillsDir);
|
|
203
185
|
if (availableSkills.length === 0) {
|
|
204
|
-
this.error(`No valid skills found in ${
|
|
186
|
+
this.error(`No valid skills found in ${subdir}/
|
|
205
187
|
Skills must have a SKILL.md file.`, {
|
|
206
188
|
exit: EXIT_CODES.ERROR
|
|
207
189
|
});
|
|
208
190
|
}
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
this.log(
|
|
217
|
-
this.log("Use --skill <name> to import a specific skill, or --all to import all.");
|
|
218
|
-
return;
|
|
191
|
+
return availableSkills;
|
|
192
|
+
}
|
|
193
|
+
listAvailableSkills(skills) {
|
|
194
|
+
this.log("");
|
|
195
|
+
this.log(`Available skills (${skills.length}):`);
|
|
196
|
+
this.log("");
|
|
197
|
+
for (const skill of skills) {
|
|
198
|
+
this.log(` - ${skill}`);
|
|
219
199
|
}
|
|
220
|
-
|
|
200
|
+
this.log("");
|
|
201
|
+
this.log("Use --skill <name> to import a specific skill, or --all to import all.");
|
|
202
|
+
}
|
|
203
|
+
resolveSkillsToImport(flags, availableSkills) {
|
|
221
204
|
if (flags.all) {
|
|
222
|
-
|
|
223
|
-
}
|
|
205
|
+
return availableSkills;
|
|
206
|
+
}
|
|
207
|
+
if (flags.skill) {
|
|
224
208
|
if (!availableSkills.includes(flags.skill)) {
|
|
225
209
|
this.error(
|
|
226
210
|
`Skill '${flags.skill}' not found in repository.
|
|
@@ -229,8 +213,11 @@ Use --list to see all available skills.`,
|
|
|
229
213
|
{ exit: EXIT_CODES.INVALID_ARGS }
|
|
230
214
|
);
|
|
231
215
|
}
|
|
232
|
-
|
|
216
|
+
return [flags.skill];
|
|
233
217
|
}
|
|
218
|
+
return [];
|
|
219
|
+
}
|
|
220
|
+
async importSkills(skillsToImport, skillsDir, projectDir, displaySource, force) {
|
|
234
221
|
const destDir = path.join(projectDir, LOCAL_SKILLS_PATH);
|
|
235
222
|
this.log("");
|
|
236
223
|
this.log(`Importing ${skillsToImport.length} skill(s)...`);
|
|
@@ -240,14 +227,14 @@ Use --list to see all available skills.`,
|
|
|
240
227
|
const sourcePath = path.join(skillsDir, skillName);
|
|
241
228
|
const destPath = path.join(destDir, skillName);
|
|
242
229
|
if (await directoryExists(destPath)) {
|
|
243
|
-
if (!
|
|
230
|
+
if (!force) {
|
|
244
231
|
this.warn(`Skipping '${skillName}': already exists. Use --force to overwrite.`);
|
|
245
232
|
skipped++;
|
|
246
233
|
continue;
|
|
247
234
|
}
|
|
248
235
|
}
|
|
249
236
|
try {
|
|
250
|
-
await
|
|
237
|
+
await importSkillFromSource({ sourcePath, destPath, skillName, displaySource });
|
|
251
238
|
this.logSuccess(`Imported: ${skillName}`);
|
|
252
239
|
imported++;
|
|
253
240
|
} catch (error) {
|
|
@@ -262,91 +249,135 @@ Use --list to see all available skills.`,
|
|
|
262
249
|
this.log(INFO_MESSAGES.RUN_COMPILE);
|
|
263
250
|
this.log("");
|
|
264
251
|
}
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
252
|
+
};
|
|
253
|
+
function parseGitHubSource(source) {
|
|
254
|
+
if (source.startsWith(GITHUB_SOURCE.HTTPS_PREFIX)) {
|
|
255
|
+
const path2 = source.replace(GITHUB_SOURCE.HTTPS_PREFIX, "");
|
|
256
|
+
return {
|
|
257
|
+
gigetSource: `${GITHUB_SOURCE.GITHUB_PREFIX}${path2}`,
|
|
258
|
+
displaySource: source
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
if (source.startsWith(GITHUB_SOURCE.GITHUB_PREFIX) || source.startsWith(GITHUB_SOURCE.GH_PREFIX)) {
|
|
262
|
+
const normalized = source.startsWith(GITHUB_SOURCE.GH_PREFIX) ? GITHUB_SOURCE.GITHUB_PREFIX + source.slice(GITHUB_SOURCE.GH_PREFIX.length) : source;
|
|
263
|
+
return {
|
|
264
|
+
gigetSource: normalized,
|
|
265
|
+
displaySource: `${GITHUB_SOURCE.HTTPS_PREFIX}${normalized.replace(GITHUB_SOURCE.GITHUB_PREFIX, "")}`
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
if (source.includes("/") && !source.includes(":")) {
|
|
269
|
+
return {
|
|
270
|
+
gigetSource: `${GITHUB_SOURCE.GITHUB_PREFIX}${source}`,
|
|
271
|
+
displaySource: `${GITHUB_SOURCE.HTTPS_PREFIX}${source}`
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
return {
|
|
275
|
+
gigetSource: source,
|
|
276
|
+
displaySource: source
|
|
277
|
+
};
|
|
278
|
+
}
|
|
279
|
+
async function fetchSkillSource(options) {
|
|
280
|
+
const result = await fetchFromSource(options.gigetSource, {
|
|
281
|
+
forceRefresh: options.forceRefresh
|
|
282
|
+
});
|
|
283
|
+
return { path: result.path, fromCache: result.fromCache };
|
|
284
|
+
}
|
|
285
|
+
async function discoverValidSkills(skillsDir) {
|
|
286
|
+
const skillDirs = await listDirectories(skillsDir);
|
|
287
|
+
const validSkills = [];
|
|
288
|
+
for (const skillDir of skillDirs) {
|
|
289
|
+
const skillMdPath = path.join(skillsDir, skillDir, STANDARD_FILES.SKILL_MD);
|
|
290
|
+
if (await fileExists(skillMdPath)) {
|
|
291
|
+
validSkills.push(skillDir);
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
return validSkills.sort();
|
|
295
|
+
}
|
|
296
|
+
async function importSkillFromSource(options) {
|
|
297
|
+
const { sourcePath, destPath, skillName, displaySource } = options;
|
|
298
|
+
const skillMdPath = path.join(sourcePath, STANDARD_FILES.SKILL_MD);
|
|
299
|
+
if (!await fileExists(skillMdPath)) {
|
|
300
|
+
throw new Error(
|
|
301
|
+
`Missing required SKILL.md file at ${skillMdPath}
|
|
270
302
|
Every skill must have a SKILL.md file containing the skill's prompt content.
|
|
271
303
|
Create one with:
|
|
272
|
-
echo "# ${skillName}" > ${path.join(sourcePath,
|
|
273
|
-
|
|
274
|
-
}
|
|
275
|
-
const contentHash = await computeFileHash(skillMdPath);
|
|
276
|
-
await ensureDir(path.dirname(destPath));
|
|
277
|
-
await copy(sourcePath, destPath);
|
|
278
|
-
await this.injectForkedFromMetadata(destPath, skillName, source, contentHash);
|
|
304
|
+
echo "# ${skillName}" > ${path.join(sourcePath, STANDARD_FILES.SKILL_MD)}`
|
|
305
|
+
);
|
|
279
306
|
}
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
307
|
+
const contentHash = await computeFileHash(skillMdPath);
|
|
308
|
+
await ensureDir(path.dirname(destPath));
|
|
309
|
+
await copy(sourcePath, destPath);
|
|
310
|
+
await injectImportedForkedFromMetadata(destPath, skillName, displaySource, contentHash);
|
|
311
|
+
}
|
|
312
|
+
async function injectImportedForkedFromMetadata(destPath, skillName, source, contentHash) {
|
|
313
|
+
const metadataYamlPath = path.join(destPath, STANDARD_FILES.METADATA_YAML);
|
|
314
|
+
const metadataJsonPath = path.join(destPath, STANDARD_FILES.METADATA_JSON);
|
|
315
|
+
const forkedFrom = {
|
|
316
|
+
source,
|
|
317
|
+
skillName,
|
|
318
|
+
contentHash,
|
|
319
|
+
date: getCurrentDate()
|
|
320
|
+
};
|
|
321
|
+
if (await fileExists(metadataYamlPath)) {
|
|
322
|
+
const rawContent = await readFile(metadataYamlPath);
|
|
323
|
+
const lines = rawContent.split("\n");
|
|
324
|
+
let yamlContent2 = rawContent;
|
|
325
|
+
let schemaComment = "";
|
|
326
|
+
if (lines[0]?.startsWith("# yaml-language-server:")) {
|
|
327
|
+
schemaComment = `${lines[0]}
|
|
296
328
|
`;
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
329
|
+
yamlContent2 = lines.slice(1).join("\n");
|
|
330
|
+
}
|
|
331
|
+
const raw = parseYaml(yamlContent2);
|
|
332
|
+
const parseResult = importedSkillMetadataSchema.safeParse(raw);
|
|
333
|
+
if (!parseResult.success) {
|
|
334
|
+
warn(
|
|
335
|
+
`Malformed metadata.yaml at ${metadataYamlPath} \u2014 existing fields may be lost
|
|
304
336
|
Validation errors: ${parseResult.error.issues.map((i) => i.message).join(", ")}
|
|
305
337
|
Expected fields: displayName (string), cliDescription (string), category (string)
|
|
306
338
|
Validate your YAML syntax at https://yamllint.com`
|
|
307
|
-
|
|
308
|
-
}
|
|
309
|
-
const metadata = parseResult.success ? parseResult.data : { forkedFrom: void 0 };
|
|
310
|
-
metadata.forkedFrom = forkedFrom;
|
|
311
|
-
const newYamlContent = stringifyYaml(metadata, {
|
|
312
|
-
lineWidth: YAML_FORMATTING.LINE_WIDTH_NONE
|
|
313
|
-
});
|
|
314
|
-
await writeFile(metadataYamlPath, schemaComment + newYamlContent);
|
|
315
|
-
return;
|
|
339
|
+
);
|
|
316
340
|
}
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
341
|
+
const metadata = parseResult.success ? parseResult.data : { forkedFrom: void 0 };
|
|
342
|
+
metadata.forkedFrom = forkedFrom;
|
|
343
|
+
const newYamlContent = stringifyYaml(metadata, {
|
|
344
|
+
lineWidth: YAML_FORMATTING.LINE_WIDTH_NONE
|
|
345
|
+
});
|
|
346
|
+
await writeFile(metadataYamlPath, schemaComment + newYamlContent);
|
|
347
|
+
return;
|
|
348
|
+
}
|
|
349
|
+
if (await fileExists(metadataJsonPath)) {
|
|
350
|
+
const rawContent = await readFile(metadataJsonPath);
|
|
351
|
+
let jsonParsed;
|
|
352
|
+
try {
|
|
353
|
+
jsonParsed = JSON.parse(rawContent);
|
|
354
|
+
} catch {
|
|
355
|
+
warn(
|
|
356
|
+
`Malformed JSON in ${metadataJsonPath} \u2014 skipping metadata injection
|
|
325
357
|
Common issues: trailing commas, unquoted keys, single quotes instead of double quotes
|
|
326
358
|
Validate your JSON at https://jsonlint.com`
|
|
327
|
-
|
|
328
|
-
return;
|
|
329
|
-
}
|
|
330
|
-
const jsonResult = importedSkillMetadataSchema.safeParse(jsonParsed);
|
|
331
|
-
const metadata = jsonResult.success ? jsonResult.data : { forkedFrom: void 0 };
|
|
332
|
-
metadata.forkedFrom = forkedFrom;
|
|
333
|
-
const yamlContent2 = stringifyYaml(metadata, { lineWidth: YAML_FORMATTING.LINE_WIDTH_NONE });
|
|
334
|
-
await writeFile(metadataYamlPath, yamlContent2);
|
|
359
|
+
);
|
|
335
360
|
return;
|
|
336
361
|
}
|
|
337
|
-
const
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
};
|
|
344
|
-
const yamlContent = stringifyYaml(minimalMetadata, {
|
|
345
|
-
lineWidth: YAML_FORMATTING.LINE_WIDTH_NONE
|
|
346
|
-
});
|
|
347
|
-
await writeFile(metadataYamlPath, yamlContent);
|
|
362
|
+
const jsonResult = importedSkillMetadataSchema.safeParse(jsonParsed);
|
|
363
|
+
const metadata = jsonResult.success ? jsonResult.data : { forkedFrom: void 0 };
|
|
364
|
+
metadata.forkedFrom = forkedFrom;
|
|
365
|
+
const yamlContent2 = stringifyYaml(metadata, { lineWidth: YAML_FORMATTING.LINE_WIDTH_NONE });
|
|
366
|
+
await writeFile(metadataYamlPath, yamlContent2);
|
|
367
|
+
return;
|
|
348
368
|
}
|
|
349
|
-
|
|
369
|
+
const minimalMetadata = {
|
|
370
|
+
displayName: skillName.split("-").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" "),
|
|
371
|
+
cliDescription: "Imported from third-party repository",
|
|
372
|
+
category: IMPORT_DEFAULTS.CATEGORY,
|
|
373
|
+
author: IMPORT_DEFAULTS.AUTHOR,
|
|
374
|
+
forkedFrom
|
|
375
|
+
};
|
|
376
|
+
const yamlContent = stringifyYaml(minimalMetadata, {
|
|
377
|
+
lineWidth: YAML_FORMATTING.LINE_WIDTH_NONE
|
|
378
|
+
});
|
|
379
|
+
await writeFile(metadataYamlPath, yamlContent);
|
|
380
|
+
}
|
|
350
381
|
export {
|
|
351
382
|
ImportSkill as default
|
|
352
383
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/cli/commands/import/skill.ts"],"sourcesContent":["import { Args, Flags } from \"@oclif/core\";\nimport path from \"path\";\nimport { parse as parseYaml, stringify as stringifyYaml } from \"yaml\";\nimport { BaseCommand } from \"../../base-command.js\";\nimport { getErrorMessage } from \"../../utils/errors.js\";\nimport { EXIT_CODES } from \"../../lib/exit-codes.js\";\nimport { fetchFromSource } from \"../../lib/loading/index.js\";\nimport { importedSkillMetadataSchema } from \"../../lib/schemas.js\";\nimport { getCurrentDate, computeFileHash } from \"../../lib/versioning.js\";\nimport {\n copy,\n directoryExists,\n fileExists,\n listDirectories,\n readFile,\n writeFile,\n ensureDir,\n} from \"../../utils/fs.js\";\nimport {\n DEFAULT_SKILLS_SUBDIR,\n GITHUB_SOURCE,\n LOCAL_SKILLS_PATH,\n STANDARD_FILES,\n YAML_FORMATTING,\n} from \"../../consts.js\";\nimport { IMPORT_DEFAULTS } from \"../../lib/metadata-keys.js\";\nimport { STATUS_MESSAGES, INFO_MESSAGES } from \"../../utils/messages.js\";\n\n/**\n * Metadata for tracking third-party imports. Different from ForkedFromMetadata\n * in skill-metadata.ts which tracks internal fork lineage (uses skillId\n * instead of source/skillName).\n */\ntype ImportedForkedFromMetadata = {\n source: string;\n skillName: string;\n contentHash: string;\n date: string;\n};\n\ntype SkillMetadata = {\n forkedFrom?: ImportedForkedFromMetadata;\n [key: string]: unknown;\n};\n\nconst SKILL_MD_FILE = STANDARD_FILES.SKILL_MD;\nconst METADATA_YAML_FILE = STANDARD_FILES.METADATA_YAML;\nconst METADATA_JSON_FILE = STANDARD_FILES.METADATA_JSON;\n\nfunction parseGitHubSource(source: string): {\n gigetSource: string;\n displaySource: string;\n} {\n if (source.startsWith(GITHUB_SOURCE.HTTPS_PREFIX)) {\n const path = source.replace(GITHUB_SOURCE.HTTPS_PREFIX, \"\");\n return {\n gigetSource: `${GITHUB_SOURCE.GITHUB_PREFIX}${path}`,\n displaySource: source,\n };\n }\n\n if (\n source.startsWith(GITHUB_SOURCE.GITHUB_PREFIX) ||\n source.startsWith(GITHUB_SOURCE.GH_PREFIX)\n ) {\n const normalized = source.startsWith(GITHUB_SOURCE.GH_PREFIX)\n ? GITHUB_SOURCE.GITHUB_PREFIX + source.slice(GITHUB_SOURCE.GH_PREFIX.length)\n : source;\n return {\n gigetSource: normalized,\n displaySource: `${GITHUB_SOURCE.HTTPS_PREFIX}${normalized.replace(GITHUB_SOURCE.GITHUB_PREFIX, \"\")}`,\n };\n }\n\n if (source.includes(\"/\") && !source.includes(\":\")) {\n return {\n gigetSource: `${GITHUB_SOURCE.GITHUB_PREFIX}${source}`,\n displaySource: `${GITHUB_SOURCE.HTTPS_PREFIX}${source}`,\n };\n }\n\n return {\n gigetSource: source,\n displaySource: source,\n };\n}\n\nasync function discoverValidSkills(skillsDir: string, skillDirs: string[]): Promise<string[]> {\n const validSkills: string[] = [];\n\n for (const skillDir of skillDirs) {\n const skillMdPath = path.join(skillsDir, skillDir, SKILL_MD_FILE);\n if (await fileExists(skillMdPath)) {\n validSkills.push(skillDir);\n }\n }\n\n return validSkills.sort();\n}\n\nexport default class ImportSkill extends BaseCommand {\n static summary = \"Import a skill from a third-party GitHub repository\";\n static description =\n \"Download and import skills from external GitHub repositories into your local \" +\n \".claude/skills/ directory. Supports importing specific skills or listing available skills.\";\n\n static examples = [\n {\n description: \"List available skills from a repository\",\n command: \"<%= config.bin %> import skill github:vercel-labs/agent-skills --list\",\n },\n {\n description: \"Import a specific skill\",\n command:\n \"<%= config.bin %> import skill github:vercel-labs/agent-skills --skill react-best-practices\",\n },\n {\n description: \"Import all skills from a repository\",\n command: \"<%= config.bin %> import skill github:vercel-labs/agent-skills --all\",\n },\n {\n description: \"Import with custom skills directory\",\n command:\n \"<%= config.bin %> import skill github:owner/repo --skill my-skill --subdir custom-skills\",\n },\n ];\n\n static args = {\n source: Args.string({\n description:\n \"GitHub repository source (github:owner/repo, https://github.com/owner/repo, or owner/repo)\",\n required: true,\n }),\n };\n\n static flags = {\n ...BaseCommand.baseFlags,\n skill: Flags.string({\n char: \"n\",\n description: \"Name of the specific skill to import\",\n required: false,\n }),\n all: Flags.boolean({\n char: \"a\",\n description: \"Import all skills from the repository\",\n default: false,\n }),\n list: Flags.boolean({\n char: \"l\",\n description: \"List available skills without importing\",\n default: false,\n }),\n subdir: Flags.string({\n description: \"Subdirectory containing skills (default: skills)\",\n default: DEFAULT_SKILLS_SUBDIR,\n }),\n force: Flags.boolean({\n char: \"f\",\n description: \"Overwrite existing skills\",\n default: false,\n }),\n refresh: Flags.boolean({\n description: \"Force refresh from remote (ignore cache)\",\n default: false,\n }),\n };\n\n async run(): Promise<void> {\n const { args, flags } = await this.parse(ImportSkill);\n const projectDir = process.cwd();\n\n this.log(\"\");\n this.log(\"Import Third-Party Skill\");\n this.log(\"\");\n\n if (!flags.list && !flags.skill && !flags.all) {\n this.error(\"Please specify --skill <name>, --all, or --list to list available skills\", {\n exit: EXIT_CODES.INVALID_ARGS,\n });\n }\n\n if (flags.skill && flags.all) {\n this.error(\"Cannot use --skill and --all together\", {\n exit: EXIT_CODES.INVALID_ARGS,\n });\n }\n\n const { gigetSource, displaySource } = parseGitHubSource(args.source);\n this.log(`Source: ${displaySource}`);\n\n this.log(STATUS_MESSAGES.FETCHING_REPOSITORY);\n\n let repoPath: string;\n try {\n const result = await fetchFromSource(gigetSource, {\n forceRefresh: flags.refresh,\n });\n repoPath = result.path;\n this.log(result.fromCache ? \"Using cached source\" : \"Downloaded fresh copy\");\n } catch (error) {\n this.error(error instanceof Error ? error.message : `Failed to fetch: ${args.source}`, {\n exit: EXIT_CODES.NETWORK_ERROR,\n });\n }\n\n // Validate --subdir to prevent path traversal outside repository boundary\n const subdir = flags.subdir;\n if (/\\0/.test(subdir)) {\n this.error(\"--subdir contains null bytes\", {\n exit: EXIT_CODES.INVALID_ARGS,\n });\n }\n if (path.isAbsolute(subdir)) {\n this.error(`--subdir must be a relative path, got: ${subdir}`, {\n exit: EXIT_CODES.INVALID_ARGS,\n });\n }\n const skillsDir = path.resolve(path.join(repoPath, subdir));\n const resolvedRepoPath = path.resolve(repoPath);\n if (!skillsDir.startsWith(resolvedRepoPath + path.sep) && skillsDir !== resolvedRepoPath) {\n this.error(`--subdir path escapes repository boundary: ${subdir}`, {\n exit: EXIT_CODES.INVALID_ARGS,\n });\n }\n\n if (!(await directoryExists(skillsDir))) {\n this.error(\n `Skills directory not found: ${flags.subdir}\\n` +\n `The repository doesn't have a '${flags.subdir}' directory.\\n` +\n `Use --subdir to specify a different location.`,\n { exit: EXIT_CODES.INVALID_ARGS },\n );\n }\n\n const skillDirs = await listDirectories(skillsDir);\n const availableSkills = await discoverValidSkills(skillsDir, skillDirs);\n\n if (availableSkills.length === 0) {\n this.error(`No valid skills found in ${flags.subdir}/\\nSkills must have a SKILL.md file.`, {\n exit: EXIT_CODES.ERROR,\n });\n }\n\n if (flags.list) {\n this.log(\"\");\n this.log(`Available skills (${availableSkills.length}):`);\n this.log(\"\");\n for (const skill of availableSkills) {\n this.log(` - ${skill}`);\n }\n this.log(\"\");\n this.log(\"Use --skill <name> to import a specific skill, or --all to import all.\");\n return;\n }\n\n let skillsToImport: string[] = [];\n\n if (flags.all) {\n skillsToImport = availableSkills;\n } else if (flags.skill) {\n if (!availableSkills.includes(flags.skill)) {\n this.error(\n `Skill '${flags.skill}' not found in repository.\\n` +\n `Available skills: ${availableSkills.join(\", \")}\\n` +\n `Use --list to see all available skills.`,\n { exit: EXIT_CODES.INVALID_ARGS },\n );\n }\n skillsToImport = [flags.skill];\n }\n\n const destDir = path.join(projectDir, LOCAL_SKILLS_PATH);\n\n this.log(\"\");\n this.log(`Importing ${skillsToImport.length} skill(s)...`);\n\n let imported = 0;\n let skipped = 0;\n\n for (const skillName of skillsToImport) {\n const sourcePath = path.join(skillsDir, skillName);\n const destPath = path.join(destDir, skillName);\n\n if (await directoryExists(destPath)) {\n if (!flags.force) {\n this.warn(`Skipping '${skillName}': already exists. Use --force to overwrite.`);\n skipped++;\n continue;\n }\n }\n\n try {\n await this.importSkill(sourcePath, destPath, skillName, displaySource);\n this.logSuccess(`Imported: ${skillName}`);\n imported++;\n } catch (error) {\n this.warn(`Failed to import '${skillName}': ${getErrorMessage(error)}`);\n skipped++;\n }\n }\n\n this.log(\"\");\n this.logSuccess(`Import complete: ${imported} imported, ${skipped} skipped`);\n this.log(`Skills location: ${destDir}`);\n this.log(\"\");\n this.log(INFO_MESSAGES.RUN_COMPILE);\n this.log(\"\");\n }\n\n private async importSkill(\n sourcePath: string,\n destPath: string,\n skillName: string,\n source: string,\n ): Promise<void> {\n const skillMdPath = path.join(sourcePath, SKILL_MD_FILE);\n if (!(await fileExists(skillMdPath))) {\n throw new Error(\n `Missing required SKILL.md file at ${skillMdPath}\\n` +\n `Every skill must have a SKILL.md file containing the skill's prompt content.\\n` +\n `Create one with:\\n` +\n ` echo \"# ${skillName}\" > ${path.join(sourcePath, SKILL_MD_FILE)}`,\n );\n }\n\n const contentHash = await computeFileHash(skillMdPath);\n\n await ensureDir(path.dirname(destPath));\n await copy(sourcePath, destPath);\n\n await this.injectForkedFromMetadata(destPath, skillName, source, contentHash);\n }\n\n private async injectForkedFromMetadata(\n destPath: string,\n skillName: string,\n source: string,\n contentHash: string,\n ): Promise<void> {\n const metadataYamlPath = path.join(destPath, METADATA_YAML_FILE);\n const metadataJsonPath = path.join(destPath, METADATA_JSON_FILE);\n\n const forkedFrom: ImportedForkedFromMetadata = {\n source,\n skillName: skillName,\n contentHash: contentHash,\n date: getCurrentDate(),\n };\n\n if (await fileExists(metadataYamlPath)) {\n const rawContent = await readFile(metadataYamlPath);\n const lines = rawContent.split(\"\\n\");\n let yamlContent = rawContent;\n let schemaComment = \"\";\n\n if (lines[0]?.startsWith(\"# yaml-language-server:\")) {\n schemaComment = `${lines[0]}\\n`;\n yamlContent = lines.slice(1).join(\"\\n\");\n }\n\n const raw = parseYaml(yamlContent);\n const parseResult = importedSkillMetadataSchema.safeParse(raw);\n if (!parseResult.success) {\n this.warn(\n `Malformed metadata.yaml at ${metadataYamlPath} — existing fields may be lost\\n` +\n ` Validation errors: ${parseResult.error.issues.map((i) => i.message).join(\", \")}\\n` +\n ` Expected fields: displayName (string), cliDescription (string), category (string)\\n` +\n ` Validate your YAML syntax at https://yamllint.com`,\n );\n }\n const metadata = parseResult.success\n ? (parseResult.data as SkillMetadata)\n : { forkedFrom: undefined };\n metadata.forkedFrom = forkedFrom;\n\n const newYamlContent = stringifyYaml(metadata, {\n lineWidth: YAML_FORMATTING.LINE_WIDTH_NONE,\n });\n await writeFile(metadataYamlPath, schemaComment + newYamlContent);\n return;\n }\n\n if (await fileExists(metadataJsonPath)) {\n const rawContent = await readFile(metadataJsonPath);\n let jsonParsed: unknown;\n try {\n jsonParsed = JSON.parse(rawContent);\n } catch {\n this.warn(\n `Malformed JSON in ${metadataJsonPath} — skipping metadata injection\\n` +\n ` Common issues: trailing commas, unquoted keys, single quotes instead of double quotes\\n` +\n ` Validate your JSON at https://jsonlint.com`,\n );\n return;\n }\n const jsonResult = importedSkillMetadataSchema.safeParse(jsonParsed);\n const metadata = jsonResult.success\n ? (jsonResult.data as SkillMetadata)\n : { forkedFrom: undefined };\n metadata.forkedFrom = forkedFrom;\n\n const yamlContent = stringifyYaml(metadata, { lineWidth: YAML_FORMATTING.LINE_WIDTH_NONE });\n await writeFile(metadataYamlPath, yamlContent);\n return;\n }\n\n const minimalMetadata: SkillMetadata = {\n displayName: skillName\n .split(\"-\")\n .map((word) => word.charAt(0).toUpperCase() + word.slice(1))\n .join(\" \"),\n cliDescription: \"Imported from third-party repository\",\n category: IMPORT_DEFAULTS.CATEGORY,\n author: IMPORT_DEFAULTS.AUTHOR,\n forkedFrom: forkedFrom,\n };\n\n const yamlContent = stringifyYaml(minimalMetadata, {\n lineWidth: YAML_FORMATTING.LINE_WIDTH_NONE,\n });\n await writeFile(metadataYamlPath, yamlContent);\n }\n}\n"],"mappings":"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","names":["path","yamlContent"]}
|
|
1
|
+
{"version":3,"sources":["../../../src/cli/commands/import/skill.ts"],"sourcesContent":["import { Args, Flags } from \"@oclif/core\";\nimport path from \"path\";\nimport { parse as parseYaml, stringify as stringifyYaml } from \"yaml\";\nimport { BaseCommand } from \"../../base-command.js\";\nimport { getErrorMessage } from \"../../utils/errors.js\";\nimport { EXIT_CODES } from \"../../lib/exit-codes.js\";\nimport { fetchFromSource } from \"../../lib/loading/index.js\";\nimport { importedSkillMetadataSchema } from \"../../lib/schemas.js\";\nimport { getCurrentDate, computeFileHash } from \"../../lib/versioning.js\";\nimport {\n copy,\n directoryExists,\n fileExists,\n listDirectories,\n readFile,\n writeFile,\n ensureDir,\n} from \"../../utils/fs.js\";\nimport { warn } from \"../../utils/logger.js\";\nimport {\n DEFAULT_SKILLS_SUBDIR,\n GITHUB_SOURCE,\n LOCAL_SKILLS_PATH,\n STANDARD_FILES,\n YAML_FORMATTING,\n} from \"../../consts.js\";\nimport { IMPORT_DEFAULTS } from \"../../lib/metadata-keys.js\";\nimport { STATUS_MESSAGES, INFO_MESSAGES } from \"../../utils/messages.js\";\n\nexport default class ImportSkill extends BaseCommand {\n static summary = \"Import a skill from a third-party GitHub repository\";\n static description =\n \"Download and import skills from external GitHub repositories into your local \" +\n \".claude/skills/ directory. Supports importing specific skills or listing available skills.\";\n\n static examples = [\n {\n description: \"List available skills from a repository\",\n command: \"<%= config.bin %> import skill github:vercel-labs/agent-skills --list\",\n },\n {\n description: \"Import a specific skill\",\n command:\n \"<%= config.bin %> import skill github:vercel-labs/agent-skills --skill react-best-practices\",\n },\n {\n description: \"Import all skills from a repository\",\n command: \"<%= config.bin %> import skill github:vercel-labs/agent-skills --all\",\n },\n {\n description: \"Import with custom skills directory\",\n command:\n \"<%= config.bin %> import skill github:owner/repo --skill my-skill --subdir custom-skills\",\n },\n ];\n\n static args = {\n source: Args.string({\n description:\n \"GitHub repository source (github:owner/repo, https://github.com/owner/repo, or owner/repo)\",\n required: true,\n }),\n };\n\n static flags = {\n ...BaseCommand.baseFlags,\n skill: Flags.string({\n char: \"n\",\n description: \"Name of the specific skill to import\",\n required: false,\n }),\n all: Flags.boolean({\n char: \"a\",\n description: \"Import all skills from the repository\",\n default: false,\n }),\n list: Flags.boolean({\n char: \"l\",\n description: \"List available skills without importing\",\n default: false,\n }),\n subdir: Flags.string({\n description: \"Subdirectory containing skills (default: skills)\",\n default: DEFAULT_SKILLS_SUBDIR,\n }),\n force: Flags.boolean({\n char: \"f\",\n description: \"Overwrite existing skills\",\n default: false,\n }),\n refresh: Flags.boolean({\n description: \"Force refresh from remote (ignore cache)\",\n default: false,\n }),\n };\n\n async run(): Promise<void> {\n const { args, flags } = await this.parse(ImportSkill);\n const projectDir = process.cwd();\n\n this.printHeader();\n this.validateFlags(flags);\n\n const { gigetSource, displaySource } = parseGitHubSource(args.source);\n this.log(`Source: ${displaySource}`);\n\n const repoPath = await this.fetchRepository(gigetSource, args.source, flags.refresh);\n const skillsDir = this.resolveSkillsDir(repoPath, flags.subdir);\n const availableSkills = await this.discoverAndValidate(skillsDir, flags.subdir);\n\n if (flags.list) {\n this.listAvailableSkills(availableSkills);\n return;\n }\n\n const skillsToImport = this.resolveSkillsToImport(flags, availableSkills);\n await this.importSkills(skillsToImport, skillsDir, projectDir, displaySource, flags.force);\n }\n\n private printHeader(): void {\n this.log(\"\");\n this.log(\"Import Third-Party Skill\");\n this.log(\"\");\n }\n\n private validateFlags(flags: { list: boolean; skill?: string; all: boolean }): void {\n if (!flags.list && !flags.skill && !flags.all) {\n this.error(\"Please specify --skill <name>, --all, or --list to list available skills\", {\n exit: EXIT_CODES.INVALID_ARGS,\n });\n }\n\n if (flags.skill && flags.all) {\n this.error(\"Cannot use --skill and --all together\", {\n exit: EXIT_CODES.INVALID_ARGS,\n });\n }\n }\n\n private async fetchRepository(\n gigetSource: string,\n sourceArg: string,\n refresh: boolean,\n ): Promise<string> {\n this.log(STATUS_MESSAGES.FETCHING_REPOSITORY);\n\n try {\n const result = await fetchSkillSource({\n gigetSource,\n forceRefresh: refresh,\n });\n this.log(result.fromCache ? \"Using cached source\" : \"Downloaded fresh copy\");\n return result.path;\n } catch (error) {\n this.error(error instanceof Error ? error.message : `Failed to fetch: ${sourceArg}`, {\n exit: EXIT_CODES.NETWORK_ERROR,\n });\n }\n }\n\n private resolveSkillsDir(repoPath: string, subdir: string): string {\n if (/\\0/.test(subdir)) {\n this.error(\"--subdir contains null bytes\", {\n exit: EXIT_CODES.INVALID_ARGS,\n });\n }\n if (path.isAbsolute(subdir)) {\n this.error(`--subdir must be a relative path, got: ${subdir}`, {\n exit: EXIT_CODES.INVALID_ARGS,\n });\n }\n const skillsDir = path.resolve(path.join(repoPath, subdir));\n const resolvedRepoPath = path.resolve(repoPath);\n if (!skillsDir.startsWith(resolvedRepoPath + path.sep) && skillsDir !== resolvedRepoPath) {\n this.error(`--subdir path escapes repository boundary: ${subdir}`, {\n exit: EXIT_CODES.INVALID_ARGS,\n });\n }\n return skillsDir;\n }\n\n private async discoverAndValidate(skillsDir: string, subdir: string): Promise<string[]> {\n if (!(await directoryExists(skillsDir))) {\n this.error(\n `Skills directory not found: ${subdir}\\n` +\n `The repository doesn't have a '${subdir}' directory.\\n` +\n `Use --subdir to specify a different location.`,\n { exit: EXIT_CODES.INVALID_ARGS },\n );\n }\n\n const availableSkills = await discoverValidSkills(skillsDir);\n\n if (availableSkills.length === 0) {\n this.error(`No valid skills found in ${subdir}/\\nSkills must have a SKILL.md file.`, {\n exit: EXIT_CODES.ERROR,\n });\n }\n\n return availableSkills;\n }\n\n private listAvailableSkills(skills: string[]): void {\n this.log(\"\");\n this.log(`Available skills (${skills.length}):`);\n this.log(\"\");\n for (const skill of skills) {\n this.log(` - ${skill}`);\n }\n this.log(\"\");\n this.log(\"Use --skill <name> to import a specific skill, or --all to import all.\");\n }\n\n private resolveSkillsToImport(\n flags: { all: boolean; skill?: string },\n availableSkills: string[],\n ): string[] {\n if (flags.all) {\n return availableSkills;\n }\n\n if (flags.skill) {\n if (!availableSkills.includes(flags.skill)) {\n this.error(\n `Skill '${flags.skill}' not found in repository.\\n` +\n `Available skills: ${availableSkills.join(\", \")}\\n` +\n `Use --list to see all available skills.`,\n { exit: EXIT_CODES.INVALID_ARGS },\n );\n }\n return [flags.skill];\n }\n\n return [];\n }\n\n private async importSkills(\n skillsToImport: string[],\n skillsDir: string,\n projectDir: string,\n displaySource: string,\n force: boolean,\n ): Promise<void> {\n const destDir = path.join(projectDir, LOCAL_SKILLS_PATH);\n\n this.log(\"\");\n this.log(`Importing ${skillsToImport.length} skill(s)...`);\n\n let imported = 0;\n let skipped = 0;\n\n for (const skillName of skillsToImport) {\n const sourcePath = path.join(skillsDir, skillName);\n const destPath = path.join(destDir, skillName);\n\n if (await directoryExists(destPath)) {\n if (!force) {\n this.warn(`Skipping '${skillName}': already exists. Use --force to overwrite.`);\n skipped++;\n continue;\n }\n }\n\n try {\n await importSkillFromSource({ sourcePath, destPath, skillName, displaySource });\n this.logSuccess(`Imported: ${skillName}`);\n imported++;\n } catch (error) {\n this.warn(`Failed to import '${skillName}': ${getErrorMessage(error)}`);\n skipped++;\n }\n }\n\n this.log(\"\");\n this.logSuccess(`Import complete: ${imported} imported, ${skipped} skipped`);\n this.log(`Skills location: ${destDir}`);\n this.log(\"\");\n this.log(INFO_MESSAGES.RUN_COMPILE);\n this.log(\"\");\n }\n}\n\ntype ImportedForkedFromMetadata = {\n source: string;\n skillName: string;\n contentHash: string;\n date: string;\n};\n\ntype SkillMetadata = {\n forkedFrom?: ImportedForkedFromMetadata;\n [key: string]: unknown;\n};\n\ntype ParsedGitHubSource = {\n gigetSource: string;\n displaySource: string;\n};\n\ntype FetchSourceOptions = {\n gigetSource: string;\n forceRefresh?: boolean;\n};\n\ntype FetchedSource = {\n path: string;\n fromCache: boolean;\n};\n\ntype ImportSkillOptions = {\n sourcePath: string;\n destPath: string;\n skillName: string;\n displaySource: string;\n};\n\n/**\n * Parses various GitHub URL formats into a normalized giget source string\n * and a human-readable display URL.\n *\n * Supports: `https://github.com/owner/repo`, `github:owner/repo`,\n * `gh:owner/repo`, and bare `owner/repo` formats.\n */\nfunction parseGitHubSource(source: string): ParsedGitHubSource {\n if (source.startsWith(GITHUB_SOURCE.HTTPS_PREFIX)) {\n const path = source.replace(GITHUB_SOURCE.HTTPS_PREFIX, \"\");\n return {\n gigetSource: `${GITHUB_SOURCE.GITHUB_PREFIX}${path}`,\n displaySource: source,\n };\n }\n\n if (\n source.startsWith(GITHUB_SOURCE.GITHUB_PREFIX) ||\n source.startsWith(GITHUB_SOURCE.GH_PREFIX)\n ) {\n const normalized = source.startsWith(GITHUB_SOURCE.GH_PREFIX)\n ? GITHUB_SOURCE.GITHUB_PREFIX + source.slice(GITHUB_SOURCE.GH_PREFIX.length)\n : source;\n return {\n gigetSource: normalized,\n displaySource: `${GITHUB_SOURCE.HTTPS_PREFIX}${normalized.replace(GITHUB_SOURCE.GITHUB_PREFIX, \"\")}`,\n };\n }\n\n if (source.includes(\"/\") && !source.includes(\":\")) {\n return {\n gigetSource: `${GITHUB_SOURCE.GITHUB_PREFIX}${source}`,\n displaySource: `${GITHUB_SOURCE.HTTPS_PREFIX}${source}`,\n };\n }\n\n return {\n gigetSource: source,\n displaySource: source,\n };\n}\n\n/**\n * Fetches a source repository using giget. Wraps `fetchFromSource` from the\n * loading layer.\n */\nasync function fetchSkillSource(options: FetchSourceOptions): Promise<FetchedSource> {\n const result = await fetchFromSource(options.gigetSource, {\n forceRefresh: options.forceRefresh,\n });\n return { path: result.path, fromCache: result.fromCache };\n}\n\n/**\n * Discovers valid skill directories within a source path by checking\n * for the presence of SKILL.md files.\n *\n * @returns Sorted list of directory names that contain a SKILL.md file.\n */\nasync function discoverValidSkills(skillsDir: string): Promise<string[]> {\n const skillDirs = await listDirectories(skillsDir);\n const validSkills: string[] = [];\n\n for (const skillDir of skillDirs) {\n const skillMdPath = path.join(skillsDir, skillDir, STANDARD_FILES.SKILL_MD);\n if (await fileExists(skillMdPath)) {\n validSkills.push(skillDir);\n }\n }\n\n return validSkills.sort();\n}\n\n/**\n * Imports a single skill from a source directory into the destination.\n *\n * Validates that the source skill has a SKILL.md file, copies the directory,\n * and injects `forkedFrom` metadata into the destination's metadata.yaml.\n *\n * @throws {Error} If the source skill is missing a SKILL.md file.\n */\nasync function importSkillFromSource(options: ImportSkillOptions): Promise<void> {\n const { sourcePath, destPath, skillName, displaySource } = options;\n const skillMdPath = path.join(sourcePath, STANDARD_FILES.SKILL_MD);\n\n if (!(await fileExists(skillMdPath))) {\n throw new Error(\n `Missing required SKILL.md file at ${skillMdPath}\\n` +\n `Every skill must have a SKILL.md file containing the skill's prompt content.\\n` +\n `Create one with:\\n` +\n ` echo \"# ${skillName}\" > ${path.join(sourcePath, STANDARD_FILES.SKILL_MD)}`,\n );\n }\n\n const contentHash = await computeFileHash(skillMdPath);\n\n await ensureDir(path.dirname(destPath));\n await copy(sourcePath, destPath);\n\n await injectImportedForkedFromMetadata(destPath, skillName, displaySource, contentHash);\n}\n\n/**\n * Injects `forkedFrom` metadata into a third-party imported skill's metadata.yaml.\n *\n * Handles three cases:\n * 1. Existing metadata.yaml -- preserves fields, adds/overwrites forkedFrom\n * 2. Existing metadata.json -- converts to YAML, adds forkedFrom\n * 3. No metadata file -- creates minimal metadata.yaml with forkedFrom\n *\n * Different from `injectForkedFromMetadata` in `skill-metadata.ts` which tracks\n * internal marketplace fork lineage using `skillId`. This function tracks\n * third-party imports using `source` + `skillName`.\n */\nasync function injectImportedForkedFromMetadata(\n destPath: string,\n skillName: string,\n source: string,\n contentHash: string,\n): Promise<void> {\n const metadataYamlPath = path.join(destPath, STANDARD_FILES.METADATA_YAML);\n const metadataJsonPath = path.join(destPath, STANDARD_FILES.METADATA_JSON);\n\n const forkedFrom: ImportedForkedFromMetadata = {\n source,\n skillName,\n contentHash,\n date: getCurrentDate(),\n };\n\n if (await fileExists(metadataYamlPath)) {\n const rawContent = await readFile(metadataYamlPath);\n const lines = rawContent.split(\"\\n\");\n let yamlContent = rawContent;\n let schemaComment = \"\";\n\n if (lines[0]?.startsWith(\"# yaml-language-server:\")) {\n schemaComment = `${lines[0]}\\n`;\n yamlContent = lines.slice(1).join(\"\\n\");\n }\n\n const raw = parseYaml(yamlContent);\n const parseResult = importedSkillMetadataSchema.safeParse(raw);\n if (!parseResult.success) {\n warn(\n `Malformed metadata.yaml at ${metadataYamlPath} — existing fields may be lost\\n` +\n ` Validation errors: ${parseResult.error.issues.map((i) => i.message).join(\", \")}\\n` +\n ` Expected fields: displayName (string), cliDescription (string), category (string)\\n` +\n ` Validate your YAML syntax at https://yamllint.com`,\n );\n }\n const metadata = parseResult.success\n ? (parseResult.data as SkillMetadata)\n : { forkedFrom: undefined };\n metadata.forkedFrom = forkedFrom;\n\n const newYamlContent = stringifyYaml(metadata, {\n lineWidth: YAML_FORMATTING.LINE_WIDTH_NONE,\n });\n await writeFile(metadataYamlPath, schemaComment + newYamlContent);\n return;\n }\n\n if (await fileExists(metadataJsonPath)) {\n const rawContent = await readFile(metadataJsonPath);\n let jsonParsed: unknown;\n try {\n jsonParsed = JSON.parse(rawContent);\n } catch {\n warn(\n `Malformed JSON in ${metadataJsonPath} — skipping metadata injection\\n` +\n ` Common issues: trailing commas, unquoted keys, single quotes instead of double quotes\\n` +\n ` Validate your JSON at https://jsonlint.com`,\n );\n return;\n }\n const jsonResult = importedSkillMetadataSchema.safeParse(jsonParsed);\n const metadata = jsonResult.success\n ? (jsonResult.data as SkillMetadata)\n : { forkedFrom: undefined };\n metadata.forkedFrom = forkedFrom;\n\n const yamlContent = stringifyYaml(metadata, { lineWidth: YAML_FORMATTING.LINE_WIDTH_NONE });\n await writeFile(metadataYamlPath, yamlContent);\n return;\n }\n\n const minimalMetadata: SkillMetadata = {\n displayName: skillName\n .split(\"-\")\n .map((word) => word.charAt(0).toUpperCase() + word.slice(1))\n .join(\" \"),\n cliDescription: \"Imported from third-party repository\",\n category: IMPORT_DEFAULTS.CATEGORY,\n author: IMPORT_DEFAULTS.AUTHOR,\n forkedFrom,\n };\n\n const yamlContent = stringifyYaml(minimalMetadata, {\n lineWidth: YAML_FORMATTING.LINE_WIDTH_NONE,\n });\n await writeFile(metadataYamlPath, yamlContent);\n}\n"],"mappings":"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","names":["path","yamlContent"]}
|