@agents-inc/cli 0.86.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 +10 -0
- package/dist/chunk-5UJJQFET.js +564 -0
- package/dist/chunk-5UJJQFET.js.map +1 -0
- package/dist/{chunk-GED2F75H.js → chunk-7FFNNDJQ.js} +176 -120
- package/dist/chunk-7FFNNDJQ.js.map +1 -0
- package/dist/{chunk-BV2MIQ3O.js → chunk-I5AZKNNL.js} +1 -1
- 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/commands/compile.js +26 -20
- package/dist/commands/compile.js.map +1 -1
- package/dist/commands/diff.js +681 -82
- package/dist/commands/diff.js.map +1 -1
- package/dist/commands/doctor.js +30 -58
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/edit.js +164 -32
- package/dist/commands/edit.js.map +1 -1
- package/dist/commands/eject.js +177 -27
- package/dist/commands/eject.js.map +1 -1
- package/dist/commands/import/skill.js +197 -33
- package/dist/commands/import/skill.js.map +1 -1
- package/dist/commands/info.js +41 -34
- package/dist/commands/info.js.map +1 -1
- package/dist/commands/init.js +3 -6
- package/dist/commands/new/agent.js +140 -44
- package/dist/commands/new/agent.js.map +1 -1
- package/dist/commands/new/marketplace.js +4 -4
- package/dist/commands/new/marketplace.js.map +1 -1
- package/dist/commands/new/skill.js +194 -30
- package/dist/commands/new/skill.js.map +1 -1
- package/dist/commands/outdated.js +1 -3
- package/dist/commands/outdated.js.map +1 -1
- package/dist/commands/search.js +162 -65
- package/dist/commands/search.js.map +1 -1
- package/dist/commands/uninstall.js +259 -62
- package/dist/commands/uninstall.js.map +1 -1
- package/dist/commands/update.js +232 -163
- package/dist/commands/update.js.map +1 -1
- package/dist/components/skill-search/skill-search.js +1 -1
- package/dist/hooks/init.js +2 -4
- package/dist/hooks/init.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-BV2MIQ3O.js.map +0 -1
- package/dist/chunk-DCVCFBQ7.js +0 -1800
- package/dist/chunk-DCVCFBQ7.js.map +0 -1
- package/dist/chunk-GED2F75H.js.map +0 -1
- package/dist/chunk-O5ZWS26C.js +0 -166
- package/dist/chunk-O5ZWS26C.js.map +0 -1
- package/dist/chunk-XQK4S22C.js +0 -202
- package/dist/chunk-XQK4S22C.js.map +0 -1
|
@@ -4,12 +4,11 @@ import {
|
|
|
4
4
|
STATUS_MESSAGES
|
|
5
5
|
} from "../../chunk-B7KZLXHV.js";
|
|
6
6
|
import {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
} from "../../chunk-
|
|
12
|
-
import "../../chunk-TMTUTUEV.js";
|
|
7
|
+
IMPORT_DEFAULTS,
|
|
8
|
+
computeFileHash,
|
|
9
|
+
fetchFromSource,
|
|
10
|
+
getCurrentDate
|
|
11
|
+
} from "../../chunk-TMTUTUEV.js";
|
|
13
12
|
import "../../chunk-B6MYECV6.js";
|
|
14
13
|
import "../../chunk-ANXHMG32.js";
|
|
15
14
|
import {
|
|
@@ -17,13 +16,24 @@ import {
|
|
|
17
16
|
EXIT_CODES
|
|
18
17
|
} from "../../chunk-MMTMXLI4.js";
|
|
19
18
|
import {
|
|
19
|
+
copy,
|
|
20
20
|
directoryExists,
|
|
21
|
-
|
|
21
|
+
ensureDir,
|
|
22
|
+
fileExists,
|
|
23
|
+
getErrorMessage,
|
|
24
|
+
importedSkillMetadataSchema,
|
|
25
|
+
listDirectories,
|
|
26
|
+
readFile,
|
|
27
|
+
warn,
|
|
28
|
+
writeFile
|
|
22
29
|
} from "../../chunk-NUU3U43A.js";
|
|
23
30
|
import "../../chunk-6XWHJHNZ.js";
|
|
24
31
|
import {
|
|
25
32
|
DEFAULT_SKILLS_SUBDIR,
|
|
26
|
-
|
|
33
|
+
GITHUB_SOURCE,
|
|
34
|
+
LOCAL_SKILLS_PATH,
|
|
35
|
+
STANDARD_FILES,
|
|
36
|
+
YAML_FORMATTING
|
|
27
37
|
} from "../../chunk-6PGL2XMY.js";
|
|
28
38
|
import "../../chunk-NPMMU4GY.js";
|
|
29
39
|
import {
|
|
@@ -34,6 +44,7 @@ import {
|
|
|
34
44
|
init_esm_shims();
|
|
35
45
|
import { Args, Flags } from "@oclif/core";
|
|
36
46
|
import path from "path";
|
|
47
|
+
import { parse as parseYaml, stringify as stringifyYaml } from "yaml";
|
|
37
48
|
var ImportSkill = class _ImportSkill extends BaseCommand {
|
|
38
49
|
static summary = "Import a skill from a third-party GitHub repository";
|
|
39
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.";
|
|
@@ -95,9 +106,26 @@ var ImportSkill = class _ImportSkill extends BaseCommand {
|
|
|
95
106
|
async run() {
|
|
96
107
|
const { args, flags } = await this.parse(_ImportSkill);
|
|
97
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() {
|
|
98
124
|
this.log("");
|
|
99
125
|
this.log("Import Third-Party Skill");
|
|
100
126
|
this.log("");
|
|
127
|
+
}
|
|
128
|
+
validateFlags(flags) {
|
|
101
129
|
if (!flags.list && !flags.skill && !flags.all) {
|
|
102
130
|
this.error("Please specify --skill <name>, --all, or --list to list available skills", {
|
|
103
131
|
exit: EXIT_CODES.INVALID_ARGS
|
|
@@ -108,23 +136,23 @@ var ImportSkill = class _ImportSkill extends BaseCommand {
|
|
|
108
136
|
exit: EXIT_CODES.INVALID_ARGS
|
|
109
137
|
});
|
|
110
138
|
}
|
|
111
|
-
|
|
112
|
-
|
|
139
|
+
}
|
|
140
|
+
async fetchRepository(gigetSource, sourceArg, refresh) {
|
|
113
141
|
this.log(STATUS_MESSAGES.FETCHING_REPOSITORY);
|
|
114
|
-
let repoPath;
|
|
115
142
|
try {
|
|
116
143
|
const result = await fetchSkillSource({
|
|
117
144
|
gigetSource,
|
|
118
|
-
forceRefresh:
|
|
145
|
+
forceRefresh: refresh
|
|
119
146
|
});
|
|
120
|
-
repoPath = result.path;
|
|
121
147
|
this.log(result.fromCache ? "Using cached source" : "Downloaded fresh copy");
|
|
148
|
+
return result.path;
|
|
122
149
|
} catch (error) {
|
|
123
|
-
this.error(error instanceof Error ? error.message : `Failed to fetch: ${
|
|
150
|
+
this.error(error instanceof Error ? error.message : `Failed to fetch: ${sourceArg}`, {
|
|
124
151
|
exit: EXIT_CODES.NETWORK_ERROR
|
|
125
152
|
});
|
|
126
153
|
}
|
|
127
|
-
|
|
154
|
+
}
|
|
155
|
+
resolveSkillsDir(repoPath, subdir) {
|
|
128
156
|
if (/\0/.test(subdir)) {
|
|
129
157
|
this.error("--subdir contains null bytes", {
|
|
130
158
|
exit: EXIT_CODES.INVALID_ARGS
|
|
@@ -142,36 +170,41 @@ var ImportSkill = class _ImportSkill extends BaseCommand {
|
|
|
142
170
|
exit: EXIT_CODES.INVALID_ARGS
|
|
143
171
|
});
|
|
144
172
|
}
|
|
173
|
+
return skillsDir;
|
|
174
|
+
}
|
|
175
|
+
async discoverAndValidate(skillsDir, subdir) {
|
|
145
176
|
if (!await directoryExists(skillsDir)) {
|
|
146
177
|
this.error(
|
|
147
|
-
`Skills directory not found: ${
|
|
148
|
-
The repository doesn't have a '${
|
|
178
|
+
`Skills directory not found: ${subdir}
|
|
179
|
+
The repository doesn't have a '${subdir}' directory.
|
|
149
180
|
Use --subdir to specify a different location.`,
|
|
150
181
|
{ exit: EXIT_CODES.INVALID_ARGS }
|
|
151
182
|
);
|
|
152
183
|
}
|
|
153
184
|
const availableSkills = await discoverValidSkills(skillsDir);
|
|
154
185
|
if (availableSkills.length === 0) {
|
|
155
|
-
this.error(`No valid skills found in ${
|
|
186
|
+
this.error(`No valid skills found in ${subdir}/
|
|
156
187
|
Skills must have a SKILL.md file.`, {
|
|
157
188
|
exit: EXIT_CODES.ERROR
|
|
158
189
|
});
|
|
159
190
|
}
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
this.log(
|
|
168
|
-
this.log("Use --skill <name> to import a specific skill, or --all to import all.");
|
|
169
|
-
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}`);
|
|
170
199
|
}
|
|
171
|
-
|
|
200
|
+
this.log("");
|
|
201
|
+
this.log("Use --skill <name> to import a specific skill, or --all to import all.");
|
|
202
|
+
}
|
|
203
|
+
resolveSkillsToImport(flags, availableSkills) {
|
|
172
204
|
if (flags.all) {
|
|
173
|
-
|
|
174
|
-
}
|
|
205
|
+
return availableSkills;
|
|
206
|
+
}
|
|
207
|
+
if (flags.skill) {
|
|
175
208
|
if (!availableSkills.includes(flags.skill)) {
|
|
176
209
|
this.error(
|
|
177
210
|
`Skill '${flags.skill}' not found in repository.
|
|
@@ -180,8 +213,11 @@ Use --list to see all available skills.`,
|
|
|
180
213
|
{ exit: EXIT_CODES.INVALID_ARGS }
|
|
181
214
|
);
|
|
182
215
|
}
|
|
183
|
-
|
|
216
|
+
return [flags.skill];
|
|
184
217
|
}
|
|
218
|
+
return [];
|
|
219
|
+
}
|
|
220
|
+
async importSkills(skillsToImport, skillsDir, projectDir, displaySource, force) {
|
|
185
221
|
const destDir = path.join(projectDir, LOCAL_SKILLS_PATH);
|
|
186
222
|
this.log("");
|
|
187
223
|
this.log(`Importing ${skillsToImport.length} skill(s)...`);
|
|
@@ -191,7 +227,7 @@ Use --list to see all available skills.`,
|
|
|
191
227
|
const sourcePath = path.join(skillsDir, skillName);
|
|
192
228
|
const destPath = path.join(destDir, skillName);
|
|
193
229
|
if (await directoryExists(destPath)) {
|
|
194
|
-
if (!
|
|
230
|
+
if (!force) {
|
|
195
231
|
this.warn(`Skipping '${skillName}': already exists. Use --force to overwrite.`);
|
|
196
232
|
skipped++;
|
|
197
233
|
continue;
|
|
@@ -214,6 +250,134 @@ Use --list to see all available skills.`,
|
|
|
214
250
|
this.log("");
|
|
215
251
|
}
|
|
216
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}
|
|
302
|
+
Every skill must have a SKILL.md file containing the skill's prompt content.
|
|
303
|
+
Create one with:
|
|
304
|
+
echo "# ${skillName}" > ${path.join(sourcePath, STANDARD_FILES.SKILL_MD)}`
|
|
305
|
+
);
|
|
306
|
+
}
|
|
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]}
|
|
328
|
+
`;
|
|
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
|
|
336
|
+
Validation errors: ${parseResult.error.issues.map((i) => i.message).join(", ")}
|
|
337
|
+
Expected fields: displayName (string), cliDescription (string), category (string)
|
|
338
|
+
Validate your YAML syntax at https://yamllint.com`
|
|
339
|
+
);
|
|
340
|
+
}
|
|
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
|
|
357
|
+
Common issues: trailing commas, unquoted keys, single quotes instead of double quotes
|
|
358
|
+
Validate your JSON at https://jsonlint.com`
|
|
359
|
+
);
|
|
360
|
+
return;
|
|
361
|
+
}
|
|
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;
|
|
368
|
+
}
|
|
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
|
+
}
|
|
217
381
|
export {
|
|
218
382
|
ImportSkill as default
|
|
219
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 { BaseCommand } from \"../../base-command.js\";\nimport { getErrorMessage } from \"../../utils/errors.js\";\nimport { EXIT_CODES } from \"../../lib/exit-codes.js\";\nimport { directoryExists } from \"../../utils/fs.js\";\nimport { DEFAULT_SKILLS_SUBDIR, LOCAL_SKILLS_PATH } from \"../../consts.js\";\nimport { STATUS_MESSAGES, INFO_MESSAGES } from \"../../utils/messages.js\";\nimport {\n parseGitHubSource,\n fetchSkillSource,\n discoverValidSkills,\n importSkillFromSource,\n} from \"../../lib/operations/import-skill.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.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 fetchSkillSource({\n 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 availableSkills = await discoverValidSkills(skillsDir);\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 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"],"mappings":"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","names":[]}
|
|
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"]}
|
package/dist/commands/info.js
CHANGED
|
@@ -5,10 +5,8 @@ import {
|
|
|
5
5
|
import {
|
|
6
6
|
loadSource,
|
|
7
7
|
resolveSkillInfo
|
|
8
|
-
} from "../chunk-
|
|
8
|
+
} from "../chunk-5UJJQFET.js";
|
|
9
9
|
import "../chunk-N6A7A4RA.js";
|
|
10
|
-
import "../chunk-O5ZWS26C.js";
|
|
11
|
-
import "../chunk-XQK4S22C.js";
|
|
12
10
|
import "../chunk-FBZR46GC.js";
|
|
13
11
|
import "../chunk-TMTUTUEV.js";
|
|
14
12
|
import "../chunk-B6MYECV6.js";
|
|
@@ -104,52 +102,61 @@ var Info = class _Info extends BaseCommand {
|
|
|
104
102
|
};
|
|
105
103
|
async run() {
|
|
106
104
|
const { args, flags } = await this.parse(_Info);
|
|
105
|
+
const projectDir = process.cwd();
|
|
107
106
|
try {
|
|
108
|
-
this.
|
|
109
|
-
const { sourceResult } = await loadSource({
|
|
110
|
-
sourceFlag: flags.source,
|
|
111
|
-
projectDir: process.cwd()
|
|
112
|
-
});
|
|
113
|
-
const { sourcePath, isLocal } = sourceResult;
|
|
114
|
-
this.log(`Loaded from ${isLocal ? "local" : "remote"}: ${sourcePath}`);
|
|
107
|
+
const { sourcePath, isLocal } = await this.loadSourceAndLog(flags.source, projectDir);
|
|
115
108
|
const result = await resolveSkillInfo({
|
|
116
109
|
query: args.skill,
|
|
117
110
|
skills: matrix.skills,
|
|
118
111
|
slugToId: matrix.slugMap.slugToId,
|
|
119
|
-
projectDir
|
|
112
|
+
projectDir,
|
|
120
113
|
sourcePath,
|
|
121
114
|
isLocal,
|
|
122
115
|
includePreview: flags.preview
|
|
123
116
|
});
|
|
124
117
|
if (!result.resolved) {
|
|
125
|
-
this.
|
|
126
|
-
|
|
127
|
-
if (result.suggestions.length > 0) {
|
|
128
|
-
this.log("");
|
|
129
|
-
this.log("Did you mean one of these?");
|
|
130
|
-
for (const suggestion of result.suggestions) {
|
|
131
|
-
this.log(` - ${suggestion}`);
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
this.log("");
|
|
135
|
-
this.logInfo(`Use '${CLI_BIN_NAME} search <query>' to find available skills.`);
|
|
136
|
-
this.log("");
|
|
137
|
-
this.exit(EXIT_CODES.ERROR);
|
|
118
|
+
this.reportNotFound(args.skill, result.suggestions);
|
|
119
|
+
return;
|
|
138
120
|
}
|
|
139
|
-
|
|
121
|
+
this.displaySkillInfo(result.resolved, flags.preview);
|
|
122
|
+
} catch (error) {
|
|
123
|
+
this.handleError(error);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
async loadSourceAndLog(sourceFlag, projectDir) {
|
|
127
|
+
this.log(STATUS_MESSAGES.LOADING_SKILLS);
|
|
128
|
+
const { sourceResult } = await loadSource({ sourceFlag, projectDir });
|
|
129
|
+
const { sourcePath, isLocal } = sourceResult;
|
|
130
|
+
this.log(`Loaded from ${isLocal ? "local" : "remote"}: ${sourcePath}`);
|
|
131
|
+
return { sourcePath, isLocal };
|
|
132
|
+
}
|
|
133
|
+
reportNotFound(query, suggestions) {
|
|
134
|
+
this.log("");
|
|
135
|
+
this.error(`Skill "${query}" not found.`, { exit: false });
|
|
136
|
+
if (suggestions.length > 0) {
|
|
140
137
|
this.log("");
|
|
141
|
-
this.log(
|
|
142
|
-
|
|
143
|
-
this.log(
|
|
144
|
-
this.log(`--- Content Preview (first ${CONTENT_PREVIEW_LINES} lines) ---`);
|
|
145
|
-
for (const line of preview) {
|
|
146
|
-
this.log(line);
|
|
147
|
-
}
|
|
138
|
+
this.log("Did you mean one of these?");
|
|
139
|
+
for (const suggestion of suggestions) {
|
|
140
|
+
this.log(` - ${suggestion}`);
|
|
148
141
|
}
|
|
142
|
+
}
|
|
143
|
+
this.log("");
|
|
144
|
+
this.logInfo(`Use '${CLI_BIN_NAME} search <query>' to find available skills.`);
|
|
145
|
+
this.log("");
|
|
146
|
+
this.exit(EXIT_CODES.ERROR);
|
|
147
|
+
}
|
|
148
|
+
displaySkillInfo(resolved, showPreview) {
|
|
149
|
+
const { skill, isInstalled, preview } = resolved;
|
|
150
|
+
this.log("");
|
|
151
|
+
this.log(formatSkillInfo(skill, isInstalled));
|
|
152
|
+
if (showPreview && preview.length > 0) {
|
|
149
153
|
this.log("");
|
|
150
|
-
|
|
151
|
-
|
|
154
|
+
this.log(`--- Content Preview (first ${CONTENT_PREVIEW_LINES} lines) ---`);
|
|
155
|
+
for (const line of preview) {
|
|
156
|
+
this.log(line);
|
|
157
|
+
}
|
|
152
158
|
}
|
|
159
|
+
this.log("");
|
|
153
160
|
}
|
|
154
161
|
};
|
|
155
162
|
export {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/cli/commands/info.ts"],"sourcesContent":["import { Args, Flags } from \"@oclif/core\";\nimport { BaseCommand } from \"../base-command.js\";\nimport { loadSource, resolveSkillInfo } from \"../lib/operations/index.js\";\nimport { matrix } from \"../lib/matrix/matrix-provider\";\nimport { CLI_BIN_NAME } from \"../consts.js\";\nimport { EXIT_CODES } from \"../lib/exit-codes.js\";\nimport { STATUS_MESSAGES } from \"../utils/messages.js\";\nimport type { ResolvedSkill, SkillRequirement } from \"../types/index.js\";\n\nconst CONTENT_PREVIEW_LINES = 10;\n\nfunction formatRequirements(requirements: SkillRequirement[]): string {\n if (requirements.length === 0) {\n return \"(none)\";\n }\n return requirements\n .map((req) => {\n const prefix = req.needsAny ? \"any of: \" : \"\";\n return prefix + req.skillIds.join(\", \");\n })\n .join(\"; \");\n}\n\nfunction formatSkillInfo(skill: ResolvedSkill, isInstalled: boolean): string {\n const lines: string[] = [];\n\n lines.push(`Skill: ${skill.id}`);\n if (skill.slug) {\n lines.push(`Slug: ${skill.slug}`);\n }\n lines.push(`Display Name: ${skill.displayName}`);\n lines.push(`Author: ${skill.author}`);\n lines.push(`Category: ${skill.category}`);\n lines.push(\"\");\n lines.push(\"Description:\");\n lines.push(` ${skill.description}`);\n lines.push(\"\");\n lines.push(`Requires: ${formatRequirements(skill.requires)}`);\n lines.push(\n `Conflicts with: ${skill.conflictsWith.length > 0 ? skill.conflictsWith.map((r) => r.skillId).join(\", \") : \"(none)\"}`,\n );\n lines.push(\n `Recommended: ${skill.isRecommended ? `Yes${skill.recommendedReason ? ` — ${skill.recommendedReason}` : \"\"}` : \"No\"}`,\n );\n\n if (skill.usageGuidance) {\n lines.push(\"\");\n lines.push(\"Usage Guidance:\");\n lines.push(` ${skill.usageGuidance}`);\n }\n\n lines.push(\"\");\n lines.push(`Local Status: ${isInstalled ? \"Installed\" : \"Not installed\"}`);\n\n return lines.join(\"\\n\");\n}\n\nexport default class Info extends BaseCommand {\n static summary = \"Show detailed information about a skill\";\n static description =\n \"Display comprehensive information about a skill including metadata, relationships, and content preview\";\n\n static examples = [\n {\n description: \"Show info for a skill by ID\",\n command: \"<%= config.bin %> <%= command.id %> web-framework-react\",\n },\n {\n description: \"Show info without content preview\",\n command: \"<%= config.bin %> <%= command.id %> web-framework-react --no-preview\",\n },\n {\n description: \"Show info from a custom source\",\n command: \"<%= config.bin %> <%= command.id %> my-skill --source github:org/marketplace\",\n },\n ];\n\n static args = {\n skill: Args.string({\n description: \"Skill ID or alias to look up\",\n required: true,\n }),\n };\n\n static flags = {\n ...BaseCommand.baseFlags,\n preview: Flags.boolean({\n description: \"Show content preview from SKILL.md\",\n default: true,\n allowNo: true,\n }),\n };\n\n async run(): Promise<void> {\n const { args, flags } = await this.parse(Info);\n\n try {\n this.
|
|
1
|
+
{"version":3,"sources":["../../src/cli/commands/info.ts"],"sourcesContent":["import { Args, Flags } from \"@oclif/core\";\nimport { BaseCommand } from \"../base-command.js\";\nimport { loadSource, resolveSkillInfo } from \"../lib/operations/index.js\";\nimport { matrix } from \"../lib/matrix/matrix-provider\";\nimport { CLI_BIN_NAME } from \"../consts.js\";\nimport { EXIT_CODES } from \"../lib/exit-codes.js\";\nimport { STATUS_MESSAGES } from \"../utils/messages.js\";\nimport type { ResolvedSkill, SkillRequirement } from \"../types/index.js\";\n\nconst CONTENT_PREVIEW_LINES = 10;\n\nfunction formatRequirements(requirements: SkillRequirement[]): string {\n if (requirements.length === 0) {\n return \"(none)\";\n }\n return requirements\n .map((req) => {\n const prefix = req.needsAny ? \"any of: \" : \"\";\n return prefix + req.skillIds.join(\", \");\n })\n .join(\"; \");\n}\n\nfunction formatSkillInfo(skill: ResolvedSkill, isInstalled: boolean): string {\n const lines: string[] = [];\n\n lines.push(`Skill: ${skill.id}`);\n if (skill.slug) {\n lines.push(`Slug: ${skill.slug}`);\n }\n lines.push(`Display Name: ${skill.displayName}`);\n lines.push(`Author: ${skill.author}`);\n lines.push(`Category: ${skill.category}`);\n lines.push(\"\");\n lines.push(\"Description:\");\n lines.push(` ${skill.description}`);\n lines.push(\"\");\n lines.push(`Requires: ${formatRequirements(skill.requires)}`);\n lines.push(\n `Conflicts with: ${skill.conflictsWith.length > 0 ? skill.conflictsWith.map((r) => r.skillId).join(\", \") : \"(none)\"}`,\n );\n lines.push(\n `Recommended: ${skill.isRecommended ? `Yes${skill.recommendedReason ? ` — ${skill.recommendedReason}` : \"\"}` : \"No\"}`,\n );\n\n if (skill.usageGuidance) {\n lines.push(\"\");\n lines.push(\"Usage Guidance:\");\n lines.push(` ${skill.usageGuidance}`);\n }\n\n lines.push(\"\");\n lines.push(`Local Status: ${isInstalled ? \"Installed\" : \"Not installed\"}`);\n\n return lines.join(\"\\n\");\n}\n\nexport default class Info extends BaseCommand {\n static summary = \"Show detailed information about a skill\";\n static description =\n \"Display comprehensive information about a skill including metadata, relationships, and content preview\";\n\n static examples = [\n {\n description: \"Show info for a skill by ID\",\n command: \"<%= config.bin %> <%= command.id %> web-framework-react\",\n },\n {\n description: \"Show info without content preview\",\n command: \"<%= config.bin %> <%= command.id %> web-framework-react --no-preview\",\n },\n {\n description: \"Show info from a custom source\",\n command: \"<%= config.bin %> <%= command.id %> my-skill --source github:org/marketplace\",\n },\n ];\n\n static args = {\n skill: Args.string({\n description: \"Skill ID or alias to look up\",\n required: true,\n }),\n };\n\n static flags = {\n ...BaseCommand.baseFlags,\n preview: Flags.boolean({\n description: \"Show content preview from SKILL.md\",\n default: true,\n allowNo: true,\n }),\n };\n\n async run(): Promise<void> {\n const { args, flags } = await this.parse(Info);\n const projectDir = process.cwd();\n\n try {\n const { sourcePath, isLocal } = await this.loadSourceAndLog(flags.source, projectDir);\n const result = await resolveSkillInfo({\n query: args.skill,\n skills: matrix.skills,\n slugToId: matrix.slugMap.slugToId,\n projectDir,\n sourcePath,\n isLocal,\n includePreview: flags.preview,\n });\n\n if (!result.resolved) {\n this.reportNotFound(args.skill, result.suggestions);\n return;\n }\n\n this.displaySkillInfo(result.resolved, flags.preview);\n } catch (error) {\n this.handleError(error);\n }\n }\n\n private async loadSourceAndLog(\n sourceFlag: string | undefined,\n projectDir: string,\n ): Promise<{ sourcePath: string; isLocal: boolean }> {\n this.log(STATUS_MESSAGES.LOADING_SKILLS);\n\n const { sourceResult } = await loadSource({ sourceFlag, projectDir });\n const { sourcePath, isLocal } = sourceResult;\n\n this.log(`Loaded from ${isLocal ? \"local\" : \"remote\"}: ${sourcePath}`);\n return { sourcePath, isLocal };\n }\n\n private reportNotFound(query: string, suggestions: string[]): never {\n this.log(\"\");\n this.error(`Skill \"${query}\" not found.`, { exit: false });\n\n if (suggestions.length > 0) {\n this.log(\"\");\n this.log(\"Did you mean one of these?\");\n for (const suggestion of suggestions) {\n this.log(` - ${suggestion}`);\n }\n }\n\n this.log(\"\");\n this.logInfo(`Use '${CLI_BIN_NAME} search <query>' to find available skills.`);\n this.log(\"\");\n this.exit(EXIT_CODES.ERROR);\n }\n\n private displaySkillInfo(\n resolved: { skill: ResolvedSkill; isInstalled: boolean; preview: string[] },\n showPreview: boolean,\n ): void {\n const { skill, isInstalled, preview } = resolved;\n\n this.log(\"\");\n this.log(formatSkillInfo(skill, isInstalled));\n\n if (showPreview && preview.length > 0) {\n this.log(\"\");\n this.log(`--- Content Preview (first ${CONTENT_PREVIEW_LINES} lines) ---`);\n for (const line of preview) {\n this.log(line);\n }\n }\n\n this.log(\"\");\n }\n}\n"],"mappings":"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","names":[]}
|
package/dist/commands/init.js
CHANGED
|
@@ -2,8 +2,9 @@
|
|
|
2
2
|
import {
|
|
3
3
|
Init,
|
|
4
4
|
formatDashboardText,
|
|
5
|
+
getDashboardData,
|
|
5
6
|
showDashboard
|
|
6
|
-
} from "../chunk-
|
|
7
|
+
} from "../chunk-7FFNNDJQ.js";
|
|
7
8
|
import "../chunk-HZQOFFKA.js";
|
|
8
9
|
import "../chunk-UNEJKTLP.js";
|
|
9
10
|
import "../chunk-YVFGISUO.js";
|
|
@@ -36,12 +37,8 @@ import "../chunk-HEQVUIHQ.js";
|
|
|
36
37
|
import "../chunk-U3IGFMCY.js";
|
|
37
38
|
import "../chunk-HK53FRMU.js";
|
|
38
39
|
import "../chunk-B7KZLXHV.js";
|
|
39
|
-
import
|
|
40
|
-
getDashboardData
|
|
41
|
-
} from "../chunk-DCVCFBQ7.js";
|
|
40
|
+
import "../chunk-5UJJQFET.js";
|
|
42
41
|
import "../chunk-N6A7A4RA.js";
|
|
43
|
-
import "../chunk-O5ZWS26C.js";
|
|
44
|
-
import "../chunk-XQK4S22C.js";
|
|
45
42
|
import "../chunk-FBZR46GC.js";
|
|
46
43
|
import "../chunk-TMTUTUEV.js";
|
|
47
44
|
import "../chunk-B6MYECV6.js";
|