@claude-collective/cli 0.26.0 → 0.29.4
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 +125 -0
- package/README.md +47 -13
- package/config/stacks.yaml +330 -93
- package/dist/chunk-56ERY7H7.js +29 -0
- package/dist/chunk-56ERY7H7.js.map +1 -0
- package/dist/{chunk-OBXAY23Y.js → chunk-5I6VY2E7.js} +5 -5
- package/dist/chunk-5I6VY2E7.js.map +1 -0
- package/dist/{chunk-ZDREFYD2.js → chunk-5WIHSJRO.js} +234 -59
- package/dist/chunk-5WIHSJRO.js.map +1 -0
- package/dist/{chunk-GGFOD5PK.js → chunk-6F3ZKDVE.js} +122 -66
- package/dist/chunk-6F3ZKDVE.js.map +1 -0
- package/dist/{chunk-DBRUQQUF.js → chunk-7GHTQSWI.js} +5 -1
- package/dist/{chunk-DBRUQQUF.js.map → chunk-7GHTQSWI.js.map} +1 -1
- package/dist/chunk-7ICBJZV2.js +63 -0
- package/dist/chunk-7ICBJZV2.js.map +1 -0
- package/dist/{chunk-3X5D7RM5.js → chunk-7UKQZSWT.js} +15 -4
- package/dist/chunk-7UKQZSWT.js.map +1 -0
- package/dist/{chunk-F4RD5FYM.js → chunk-A4T4YSV4.js} +5 -2
- package/dist/chunk-A4T4YSV4.js.map +1 -0
- package/dist/{chunk-VVYNZZUX.js → chunk-AG5YGYJT.js} +9 -5
- package/dist/chunk-AG5YGYJT.js.map +1 -0
- package/dist/chunk-AJFSCLJ7.js +81 -0
- package/dist/chunk-AJFSCLJ7.js.map +1 -0
- package/dist/{chunk-NQJ47R4N.js → chunk-CQZAKMPJ.js} +66 -14
- package/dist/chunk-CQZAKMPJ.js.map +1 -0
- package/dist/chunk-DIRH4PDF.js +24 -0
- package/dist/chunk-DIRH4PDF.js.map +1 -0
- package/dist/{chunk-R7B63JAP.js → chunk-DUIYVKFK.js} +123 -86
- package/dist/chunk-DUIYVKFK.js.map +1 -0
- package/dist/chunk-EP6J44I4.js +142 -0
- package/dist/chunk-EP6J44I4.js.map +1 -0
- package/dist/{chunk-TDZE4TDG.js → chunk-EUPMWSM3.js} +92 -29
- package/dist/chunk-EUPMWSM3.js.map +1 -0
- package/dist/chunk-FUPBGSRA.js +66 -0
- package/dist/chunk-FUPBGSRA.js.map +1 -0
- package/dist/{chunk-U7HFKR74.js → chunk-FY5D4KIC.js} +5 -2
- package/dist/chunk-FY5D4KIC.js.map +1 -0
- package/dist/chunk-G5WXKKQM.js +233 -0
- package/dist/chunk-G5WXKKQM.js.map +1 -0
- package/dist/{chunk-KWYO3M5Q.js → chunk-GVVEPVR7.js} +25 -24
- package/dist/chunk-GVVEPVR7.js.map +1 -0
- package/dist/chunk-IFODQTCX.js +162 -0
- package/dist/chunk-IFODQTCX.js.map +1 -0
- package/dist/chunk-IQUBOWWU.js +366 -0
- package/dist/chunk-IQUBOWWU.js.map +1 -0
- package/dist/{chunk-ETCVEV3S.js → chunk-IRG52AN5.js} +242 -155
- package/dist/chunk-IRG52AN5.js.map +1 -0
- package/dist/chunk-MQAYAISQ.js +88 -0
- package/dist/chunk-MQAYAISQ.js.map +1 -0
- package/dist/{chunk-4357L7VK.js → chunk-N73GQTCK.js} +37 -104
- package/dist/chunk-N73GQTCK.js.map +1 -0
- package/dist/{chunk-H7SSBSPR.js → chunk-OA5RCL2L.js} +8 -5
- package/dist/chunk-OA5RCL2L.js.map +1 -0
- package/dist/{chunk-I3YYG5IO.js → chunk-PNXFJPXF.js} +3 -3
- package/dist/{chunk-MCTSHLAF.js → chunk-RI5QEK5W.js} +41 -14
- package/dist/chunk-RI5QEK5W.js.map +1 -0
- package/dist/chunk-RXC7AF7N.js +31 -0
- package/dist/chunk-RXC7AF7N.js.map +1 -0
- package/dist/{chunk-ETQ3BPGU.js → chunk-SSHG7MEE.js} +1252 -728
- package/dist/chunk-SSHG7MEE.js.map +1 -0
- package/dist/{chunk-4S4FCAA2.js → chunk-VTUPUKFD.js} +26 -31
- package/dist/chunk-VTUPUKFD.js.map +1 -0
- package/dist/{chunk-XENOESJZ.js → chunk-WLQUQXWO.js} +10 -67
- package/dist/chunk-WLQUQXWO.js.map +1 -0
- package/dist/chunk-WPED6CL3.js +105 -0
- package/dist/chunk-WPED6CL3.js.map +1 -0
- package/dist/{chunk-R5KJVI54.js → chunk-XPMEGGJK.js} +97 -76
- package/dist/chunk-XPMEGGJK.js.map +1 -0
- package/dist/chunk-XZKVOPCR.js +75 -0
- package/dist/chunk-XZKVOPCR.js.map +1 -0
- package/dist/{chunk-ZW2PELOH.js → chunk-ZX5DM4D5.js} +106 -69
- package/dist/chunk-ZX5DM4D5.js.map +1 -0
- package/dist/commands/build/marketplace.js +21 -20
- package/dist/commands/build/marketplace.js.map +1 -1
- package/dist/commands/build/plugins.js +7 -11
- package/dist/commands/build/plugins.js.map +1 -1
- package/dist/commands/build/stack.js +8 -13
- package/dist/commands/build/stack.js.map +1 -1
- package/dist/commands/compile.js +109 -135
- package/dist/commands/compile.js.map +1 -1
- package/dist/commands/config/get.js +4 -5
- package/dist/commands/config/get.js.map +1 -1
- package/dist/commands/config/index.js +5 -6
- package/dist/commands/config/index.js.map +1 -1
- package/dist/commands/config/path.js +4 -5
- package/dist/commands/config/path.js.map +1 -1
- package/dist/commands/config/set-project.js +4 -5
- package/dist/commands/config/set-project.js.map +1 -1
- package/dist/commands/config/show.js +5 -6
- package/dist/commands/config/unset-project.js +4 -5
- package/dist/commands/config/unset-project.js.map +1 -1
- package/dist/commands/diff.js +26 -11
- package/dist/commands/diff.js.map +1 -1
- package/dist/commands/doctor.js +13 -16
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/edit.js +71 -42
- package/dist/commands/edit.js.map +1 -1
- package/dist/commands/eject.js +34 -14
- package/dist/commands/eject.js.map +1 -1
- package/dist/commands/import/skill.js +93 -52
- package/dist/commands/import/skill.js.map +1 -1
- package/dist/commands/info.js +27 -9
- package/dist/commands/info.js.map +1 -1
- package/dist/commands/init.js +98 -48
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/list.js +10 -5
- package/dist/commands/list.js.map +1 -1
- package/dist/commands/new/agent.js +8 -11
- package/dist/commands/new/agent.js.map +1 -1
- package/dist/commands/new/skill.js +17 -18
- package/dist/commands/new/skill.js.map +1 -1
- package/dist/commands/outdated.js +23 -9
- package/dist/commands/outdated.js.map +1 -1
- package/dist/commands/search.js +23 -20
- package/dist/commands/search.js.map +1 -1
- package/dist/commands/uninstall.js +28 -21
- package/dist/commands/uninstall.js.map +1 -1
- package/dist/commands/update.js +30 -22
- package/dist/commands/update.js.map +1 -1
- package/dist/commands/validate.js +103 -39
- package/dist/commands/validate.js.map +1 -1
- package/dist/commands/version/bump.js +4 -5
- package/dist/commands/version/bump.js.map +1 -1
- package/dist/commands/version/index.js +4 -5
- package/dist/commands/version/index.js.map +1 -1
- package/dist/commands/version/set.js +4 -5
- package/dist/commands/version/set.js.map +1 -1
- package/dist/commands/version/show.js +4 -5
- package/dist/commands/version/show.js.map +1 -1
- package/dist/components/common/confirm.test.js +2 -2
- package/dist/components/common/confirm.test.js.map +1 -1
- package/dist/components/skill-search/skill-search.js +4 -2
- package/dist/components/wizard/category-grid.js +3 -1
- package/dist/components/wizard/category-grid.test.js +63 -64
- package/dist/components/wizard/category-grid.test.js.map +1 -1
- package/dist/components/wizard/domain-selection.js +13 -0
- package/dist/components/wizard/help-modal.js +10 -0
- package/dist/components/wizard/help-modal.js.map +1 -0
- package/dist/components/wizard/menu-item.js +2 -1
- package/dist/components/wizard/search-modal.js +3 -1
- package/dist/components/wizard/search-modal.test.js +4 -2
- package/dist/components/wizard/search-modal.test.js.map +1 -1
- package/dist/components/wizard/section-progress.js +2 -1
- package/dist/components/wizard/section-progress.test.js +2 -1
- package/dist/components/wizard/section-progress.test.js.map +1 -1
- package/dist/components/wizard/source-grid.js +6 -2
- package/dist/components/wizard/source-grid.test.js +49 -45
- package/dist/components/wizard/source-grid.test.js.map +1 -1
- package/dist/components/wizard/stack-selection.js +15 -0
- package/dist/components/wizard/stack-selection.js.map +1 -0
- package/dist/components/wizard/step-approach.js +8 -6
- package/dist/components/wizard/step-approach.test.js +11 -9
- package/dist/components/wizard/step-approach.test.js.map +1 -1
- package/dist/components/wizard/step-build.js +9 -13
- package/dist/components/wizard/step-build.test.js +27 -45
- package/dist/components/wizard/step-build.test.js.map +1 -1
- package/dist/components/wizard/step-confirm.js +2 -1
- package/dist/components/wizard/step-confirm.test.js +6 -5
- package/dist/components/wizard/step-confirm.test.js.map +1 -1
- package/dist/components/wizard/step-refine.js +2 -1
- package/dist/components/wizard/step-refine.test.js +3 -2
- package/dist/components/wizard/step-refine.test.js.map +1 -1
- package/dist/components/wizard/step-settings.js +8 -6
- package/dist/components/wizard/step-settings.test.js +12 -10
- package/dist/components/wizard/step-settings.test.js.map +1 -1
- package/dist/components/wizard/step-sources.js +11 -9
- package/dist/components/wizard/step-sources.test.js +16 -15
- package/dist/components/wizard/step-sources.test.js.map +1 -1
- package/dist/components/wizard/step-stack.js +9 -6
- package/dist/components/wizard/step-stack.test.js +15 -12
- package/dist/components/wizard/step-stack.test.js.map +1 -1
- package/dist/components/wizard/view-title.js +2 -1
- package/dist/components/wizard/wizard-layout.js +7 -9
- package/dist/components/wizard/wizard-tabs.js +2 -1
- package/dist/components/wizard/wizard-tabs.test.js +2 -1
- package/dist/components/wizard/wizard-tabs.test.js.map +1 -1
- package/dist/components/wizard/wizard.js +26 -20
- package/dist/config/stacks.yaml +330 -93
- package/dist/hooks/init.js +3 -4
- package/dist/hooks/init.js.map +1 -1
- package/dist/source-manager-TV2YGPAN.js +15 -0
- package/dist/source-manager-TV2YGPAN.js.map +1 -0
- package/dist/stores/wizard-store.js +4 -3
- package/dist/stores/wizard-store.test.js +272 -25
- package/dist/stores/wizard-store.test.js.map +1 -1
- package/package.json +2 -1
- package/src/schemas/agent-frontmatter.schema.json +84 -0
- package/src/schemas/agent.schema.json +93 -0
- package/src/schemas/hooks.schema.json +47 -0
- package/src/schemas/marketplace.schema.json +119 -0
- package/src/schemas/metadata.schema.json +113 -0
- package/src/schemas/plugin.schema.json +130 -0
- package/src/schemas/project-config.schema.json +125 -0
- package/src/schemas/project-source-config.schema.json +81 -0
- package/src/schemas/skill-frontmatter.schema.json +42 -0
- package/src/schemas/skills-matrix.schema.json +467 -0
- package/src/schemas/stack.schema.json +191 -0
- package/src/schemas/stacks.schema.json +111 -0
- package/dist/chunk-3X5D7RM5.js.map +0 -1
- package/dist/chunk-4357L7VK.js.map +0 -1
- package/dist/chunk-4S4FCAA2.js.map +0 -1
- package/dist/chunk-7UPXT32F.js +0 -197
- package/dist/chunk-7UPXT32F.js.map +0 -1
- package/dist/chunk-ETCVEV3S.js.map +0 -1
- package/dist/chunk-ETQ3BPGU.js.map +0 -1
- package/dist/chunk-F4RD5FYM.js.map +0 -1
- package/dist/chunk-GGFOD5PK.js.map +0 -1
- package/dist/chunk-H7SSBSPR.js.map +0 -1
- package/dist/chunk-HWD32NP7.js +0 -19
- package/dist/chunk-HWD32NP7.js.map +0 -1
- package/dist/chunk-KWYO3M5Q.js.map +0 -1
- package/dist/chunk-MCTSHLAF.js.map +0 -1
- package/dist/chunk-NQJ47R4N.js.map +0 -1
- package/dist/chunk-O6ZTD7ZI.js +0 -70
- package/dist/chunk-O6ZTD7ZI.js.map +0 -1
- package/dist/chunk-OBXAY23Y.js.map +0 -1
- package/dist/chunk-R5KJVI54.js.map +0 -1
- package/dist/chunk-R7B63JAP.js.map +0 -1
- package/dist/chunk-TDZE4TDG.js.map +0 -1
- package/dist/chunk-TMED5DQ2.js +0 -210
- package/dist/chunk-TMED5DQ2.js.map +0 -1
- package/dist/chunk-U7HFKR74.js.map +0 -1
- package/dist/chunk-UEMRJI2K.js +0 -146
- package/dist/chunk-UEMRJI2K.js.map +0 -1
- package/dist/chunk-UNN7523L.js +0 -78
- package/dist/chunk-UNN7523L.js.map +0 -1
- package/dist/chunk-VVYNZZUX.js.map +0 -1
- package/dist/chunk-XENOESJZ.js.map +0 -1
- package/dist/chunk-ZDREFYD2.js.map +0 -1
- package/dist/chunk-ZW2PELOH.js.map +0 -1
- package/dist/source-manager-EYO3F2DV.js +0 -16
- /package/dist/{chunk-I3YYG5IO.js.map → chunk-PNXFJPXF.js.map} +0 -0
- /package/dist/{source-manager-EYO3F2DV.js.map → components/wizard/domain-selection.js.map} +0 -0
|
@@ -1,27 +1,36 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
INFO_MESSAGES,
|
|
4
|
+
STATUS_MESSAGES
|
|
5
|
+
} from "../../chunk-FUPBGSRA.js";
|
|
2
6
|
import {
|
|
3
7
|
BaseCommand,
|
|
4
8
|
EXIT_CODES
|
|
5
|
-
} from "../../chunk-
|
|
9
|
+
} from "../../chunk-5I6VY2E7.js";
|
|
6
10
|
import {
|
|
11
|
+
IMPORT_DEFAULTS,
|
|
12
|
+
computeFileHash,
|
|
7
13
|
fetchFromSource,
|
|
8
|
-
getCurrentDate
|
|
9
|
-
|
|
10
|
-
} from "../../chunk-ETQ3BPGU.js";
|
|
14
|
+
getCurrentDate
|
|
15
|
+
} from "../../chunk-SSHG7MEE.js";
|
|
11
16
|
import {
|
|
12
17
|
copy,
|
|
13
18
|
directoryExists,
|
|
14
19
|
ensureDir,
|
|
15
20
|
fileExists,
|
|
21
|
+
getErrorMessage,
|
|
16
22
|
importedSkillMetadataSchema,
|
|
17
23
|
listDirectories,
|
|
18
24
|
readFile,
|
|
19
25
|
writeFile
|
|
20
|
-
} from "../../chunk-
|
|
21
|
-
import "../../chunk-HWD32NP7.js";
|
|
26
|
+
} from "../../chunk-5WIHSJRO.js";
|
|
22
27
|
import {
|
|
23
|
-
|
|
24
|
-
|
|
28
|
+
DEFAULT_SKILLS_SUBDIR,
|
|
29
|
+
GITHUB_SOURCE,
|
|
30
|
+
LOCAL_SKILLS_PATH,
|
|
31
|
+
STANDARD_FILES,
|
|
32
|
+
YAML_FORMATTING
|
|
33
|
+
} from "../../chunk-IFODQTCX.js";
|
|
25
34
|
import {
|
|
26
35
|
init_esm_shims
|
|
27
36
|
} from "../../chunk-AWKZ5BDL.js";
|
|
@@ -31,29 +40,28 @@ init_esm_shims();
|
|
|
31
40
|
import { Args, Flags } from "@oclif/core";
|
|
32
41
|
import path from "path";
|
|
33
42
|
import { parse as parseYaml, stringify as stringifyYaml } from "yaml";
|
|
34
|
-
var SKILL_MD_FILE =
|
|
35
|
-
var METADATA_YAML_FILE =
|
|
36
|
-
var METADATA_JSON_FILE =
|
|
37
|
-
var DEFAULT_SKILLS_SUBDIR = "skills";
|
|
43
|
+
var SKILL_MD_FILE = STANDARD_FILES.SKILL_MD;
|
|
44
|
+
var METADATA_YAML_FILE = STANDARD_FILES.METADATA_YAML;
|
|
45
|
+
var METADATA_JSON_FILE = STANDARD_FILES.METADATA_JSON;
|
|
38
46
|
function parseGitHubSource(source) {
|
|
39
|
-
if (source.startsWith(
|
|
40
|
-
const path2 = source.replace(
|
|
47
|
+
if (source.startsWith(GITHUB_SOURCE.HTTPS_PREFIX)) {
|
|
48
|
+
const path2 = source.replace(GITHUB_SOURCE.HTTPS_PREFIX, "");
|
|
41
49
|
return {
|
|
42
|
-
gigetSource:
|
|
50
|
+
gigetSource: `${GITHUB_SOURCE.GITHUB_PREFIX}${path2}`,
|
|
43
51
|
displaySource: source
|
|
44
52
|
};
|
|
45
53
|
}
|
|
46
|
-
if (source.startsWith(
|
|
47
|
-
const normalized = source.
|
|
54
|
+
if (source.startsWith(GITHUB_SOURCE.GITHUB_PREFIX) || source.startsWith(GITHUB_SOURCE.GH_PREFIX)) {
|
|
55
|
+
const normalized = source.startsWith(GITHUB_SOURCE.GH_PREFIX) ? GITHUB_SOURCE.GITHUB_PREFIX + source.slice(GITHUB_SOURCE.GH_PREFIX.length) : source;
|
|
48
56
|
return {
|
|
49
57
|
gigetSource: normalized,
|
|
50
|
-
displaySource:
|
|
58
|
+
displaySource: `${GITHUB_SOURCE.HTTPS_PREFIX}${normalized.replace(GITHUB_SOURCE.GITHUB_PREFIX, "")}`
|
|
51
59
|
};
|
|
52
60
|
}
|
|
53
61
|
if (source.includes("/") && !source.includes(":")) {
|
|
54
62
|
return {
|
|
55
|
-
gigetSource:
|
|
56
|
-
displaySource:
|
|
63
|
+
gigetSource: `${GITHUB_SOURCE.GITHUB_PREFIX}${source}`,
|
|
64
|
+
displaySource: `${GITHUB_SOURCE.HTTPS_PREFIX}${source}`
|
|
57
65
|
};
|
|
58
66
|
}
|
|
59
67
|
return {
|
|
@@ -61,6 +69,16 @@ function parseGitHubSource(source) {
|
|
|
61
69
|
displaySource: source
|
|
62
70
|
};
|
|
63
71
|
}
|
|
72
|
+
async function discoverValidSkills(skillsDir, skillDirs) {
|
|
73
|
+
const validSkills = [];
|
|
74
|
+
for (const skillDir of skillDirs) {
|
|
75
|
+
const skillMdPath = path.join(skillsDir, skillDir, SKILL_MD_FILE);
|
|
76
|
+
if (await fileExists(skillMdPath)) {
|
|
77
|
+
validSkills.push(skillDir);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return validSkills.sort();
|
|
81
|
+
}
|
|
64
82
|
var ImportSkill = class _ImportSkill extends BaseCommand {
|
|
65
83
|
static summary = "Import a skill from a third-party GitHub repository";
|
|
66
84
|
static description = "Download and import skills from external GitHub repositories into your local .claude/skills/ directory. Supports importing specific skills or listing available skills.";
|
|
@@ -137,7 +155,7 @@ var ImportSkill = class _ImportSkill extends BaseCommand {
|
|
|
137
155
|
}
|
|
138
156
|
const { gigetSource, displaySource } = parseGitHubSource(args.source);
|
|
139
157
|
this.log(`Source: ${displaySource}`);
|
|
140
|
-
this.log(
|
|
158
|
+
this.log(STATUS_MESSAGES.FETCHING_REPOSITORY);
|
|
141
159
|
let repoPath;
|
|
142
160
|
try {
|
|
143
161
|
const result = await fetchFromSource(gigetSource, {
|
|
@@ -150,7 +168,24 @@ var ImportSkill = class _ImportSkill extends BaseCommand {
|
|
|
150
168
|
exit: EXIT_CODES.NETWORK_ERROR
|
|
151
169
|
});
|
|
152
170
|
}
|
|
153
|
-
const
|
|
171
|
+
const subdir = flags.subdir;
|
|
172
|
+
if (/\0/.test(subdir)) {
|
|
173
|
+
this.error("--subdir contains null bytes", {
|
|
174
|
+
exit: EXIT_CODES.INVALID_ARGS
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
if (path.isAbsolute(subdir)) {
|
|
178
|
+
this.error(`--subdir must be a relative path, got: ${subdir}`, {
|
|
179
|
+
exit: EXIT_CODES.INVALID_ARGS
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
const skillsDir = path.resolve(path.join(repoPath, subdir));
|
|
183
|
+
const resolvedRepoPath = path.resolve(repoPath);
|
|
184
|
+
if (!skillsDir.startsWith(resolvedRepoPath + path.sep) && skillsDir !== resolvedRepoPath) {
|
|
185
|
+
this.error(`--subdir path escapes repository boundary: ${subdir}`, {
|
|
186
|
+
exit: EXIT_CODES.INVALID_ARGS
|
|
187
|
+
});
|
|
188
|
+
}
|
|
154
189
|
if (!await directoryExists(skillsDir)) {
|
|
155
190
|
this.error(
|
|
156
191
|
`Skills directory not found: ${flags.subdir}
|
|
@@ -160,13 +195,12 @@ Use --subdir to specify a different location.`,
|
|
|
160
195
|
);
|
|
161
196
|
}
|
|
162
197
|
const skillDirs = await listDirectories(skillsDir);
|
|
163
|
-
const availableSkills = await
|
|
198
|
+
const availableSkills = await discoverValidSkills(skillsDir, skillDirs);
|
|
164
199
|
if (availableSkills.length === 0) {
|
|
165
|
-
this.error(
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
);
|
|
200
|
+
this.error(`No valid skills found in ${flags.subdir}/
|
|
201
|
+
Skills must have a SKILL.md file.`, {
|
|
202
|
+
exit: EXIT_CODES.ERROR
|
|
203
|
+
});
|
|
170
204
|
}
|
|
171
205
|
if (flags.list) {
|
|
172
206
|
this.log("");
|
|
@@ -223,9 +257,7 @@ Use --list to see all available skills.`,
|
|
|
223
257
|
this.logSuccess(`Imported: ${skillName}`);
|
|
224
258
|
imported++;
|
|
225
259
|
} catch (error) {
|
|
226
|
-
this.warn(
|
|
227
|
-
`Failed to import '${skillName}': ${error instanceof Error ? error.message : String(error)}`
|
|
228
|
-
);
|
|
260
|
+
this.warn(`Failed to import '${skillName}': ${getErrorMessage(error)}`);
|
|
229
261
|
skipped++;
|
|
230
262
|
}
|
|
231
263
|
}
|
|
@@ -233,25 +265,20 @@ Use --list to see all available skills.`,
|
|
|
233
265
|
this.logSuccess(`Import complete: ${imported} imported, ${skipped} skipped`);
|
|
234
266
|
this.log(`Skills location: ${destDir}`);
|
|
235
267
|
this.log("");
|
|
236
|
-
this.log(
|
|
268
|
+
this.log(INFO_MESSAGES.RUN_COMPILE);
|
|
237
269
|
this.log("");
|
|
238
270
|
}
|
|
239
|
-
async discoverValidSkills(skillsDir, skillDirs) {
|
|
240
|
-
const validSkills = [];
|
|
241
|
-
for (const skillDir of skillDirs) {
|
|
242
|
-
const skillMdPath = path.join(skillsDir, skillDir, SKILL_MD_FILE);
|
|
243
|
-
if (await fileExists(skillMdPath)) {
|
|
244
|
-
validSkills.push(skillDir);
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
return validSkills.sort();
|
|
248
|
-
}
|
|
249
271
|
async importSkill(sourcePath, destPath, skillName, source) {
|
|
250
272
|
const skillMdPath = path.join(sourcePath, SKILL_MD_FILE);
|
|
251
273
|
if (!await fileExists(skillMdPath)) {
|
|
252
|
-
throw new Error(
|
|
274
|
+
throw new Error(
|
|
275
|
+
`Missing required SKILL.md file at ${skillMdPath}
|
|
276
|
+
Every skill must have a SKILL.md file containing the skill's prompt content.
|
|
277
|
+
Create one with:
|
|
278
|
+
echo "# ${skillName}" > ${path.join(sourcePath, SKILL_MD_FILE)}`
|
|
279
|
+
);
|
|
253
280
|
}
|
|
254
|
-
const contentHash = await
|
|
281
|
+
const contentHash = await computeFileHash(skillMdPath);
|
|
255
282
|
await ensureDir(path.dirname(destPath));
|
|
256
283
|
await copy(sourcePath, destPath);
|
|
257
284
|
await this.injectForkedFromMetadata(destPath, skillName, source, contentHash);
|
|
@@ -271,17 +298,25 @@ Use --list to see all available skills.`,
|
|
|
271
298
|
let yamlContent2 = rawContent;
|
|
272
299
|
let schemaComment = "";
|
|
273
300
|
if (lines[0]?.startsWith("# yaml-language-server:")) {
|
|
274
|
-
schemaComment = lines[0]
|
|
301
|
+
schemaComment = `${lines[0]}
|
|
302
|
+
`;
|
|
275
303
|
yamlContent2 = lines.slice(1).join("\n");
|
|
276
304
|
}
|
|
277
305
|
const raw = parseYaml(yamlContent2);
|
|
278
306
|
const parseResult = importedSkillMetadataSchema.safeParse(raw);
|
|
279
307
|
if (!parseResult.success) {
|
|
280
|
-
this.warn(
|
|
308
|
+
this.warn(
|
|
309
|
+
`Malformed metadata.yaml at ${metadataYamlPath} \u2014 existing fields may be lost
|
|
310
|
+
Validation errors: ${parseResult.error.issues.map((i) => i.message).join(", ")}
|
|
311
|
+
Expected fields: cli_name (string), cli_description (string), category (string)
|
|
312
|
+
Validate your YAML syntax at https://yamllint.com`
|
|
313
|
+
);
|
|
281
314
|
}
|
|
282
315
|
const metadata = parseResult.success ? parseResult.data : { forked_from: void 0 };
|
|
283
316
|
metadata.forked_from = forkedFrom;
|
|
284
|
-
const newYamlContent = stringifyYaml(metadata, {
|
|
317
|
+
const newYamlContent = stringifyYaml(metadata, {
|
|
318
|
+
lineWidth: YAML_FORMATTING.LINE_WIDTH_NONE
|
|
319
|
+
});
|
|
285
320
|
await writeFile(metadataYamlPath, schemaComment + newYamlContent);
|
|
286
321
|
return;
|
|
287
322
|
}
|
|
@@ -291,25 +326,31 @@ Use --list to see all available skills.`,
|
|
|
291
326
|
try {
|
|
292
327
|
jsonParsed = JSON.parse(rawContent);
|
|
293
328
|
} catch {
|
|
294
|
-
this.warn(
|
|
329
|
+
this.warn(
|
|
330
|
+
`Malformed JSON in ${metadataJsonPath} \u2014 skipping metadata injection
|
|
331
|
+
Common issues: trailing commas, unquoted keys, single quotes instead of double quotes
|
|
332
|
+
Validate your JSON at https://jsonlint.com`
|
|
333
|
+
);
|
|
295
334
|
return;
|
|
296
335
|
}
|
|
297
336
|
const jsonResult = importedSkillMetadataSchema.safeParse(jsonParsed);
|
|
298
337
|
const metadata = jsonResult.success ? jsonResult.data : { forked_from: void 0 };
|
|
299
338
|
metadata.forked_from = forkedFrom;
|
|
300
|
-
const yamlContent2 = stringifyYaml(metadata, { lineWidth:
|
|
339
|
+
const yamlContent2 = stringifyYaml(metadata, { lineWidth: YAML_FORMATTING.LINE_WIDTH_NONE });
|
|
301
340
|
await writeFile(metadataYamlPath, yamlContent2);
|
|
302
341
|
return;
|
|
303
342
|
}
|
|
304
343
|
const minimalMetadata = {
|
|
305
344
|
cli_name: skillName.split("-").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" "),
|
|
306
345
|
cli_description: "Imported from third-party repository",
|
|
307
|
-
category:
|
|
346
|
+
category: IMPORT_DEFAULTS.CATEGORY,
|
|
308
347
|
category_exclusive: false,
|
|
309
|
-
author:
|
|
348
|
+
author: IMPORT_DEFAULTS.AUTHOR,
|
|
310
349
|
forked_from: forkedFrom
|
|
311
350
|
};
|
|
312
|
-
const yamlContent = stringifyYaml(minimalMetadata, {
|
|
351
|
+
const yamlContent = stringifyYaml(minimalMetadata, {
|
|
352
|
+
lineWidth: YAML_FORMATTING.LINE_WIDTH_NONE
|
|
353
|
+
});
|
|
313
354
|
await writeFile(metadataYamlPath, yamlContent);
|
|
314
355
|
}
|
|
315
356
|
};
|
|
@@ -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 { EXIT_CODES } from \"../../lib/exit-codes.js\";\nimport { fetchFromSource } from \"../../lib/loading/index.js\";\nimport { importedSkillMetadataSchema } from \"../../lib/schemas.js\";\nimport { getCurrentDate, hashFile } 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 { LOCAL_SKILLS_PATH } from \"../../consts.js\";\n\n/**\n * Metadata for tracking third-party imports. Different from ForkedFromMetadata\n * in skill-metadata.ts which tracks internal fork lineage (uses skill_id\n * instead of source/skill_name).\n */\ntype ImportedForkedFromMetadata = {\n source: string;\n skill_name: string;\n content_hash: string;\n date: string;\n};\n\ntype SkillMetadata = {\n forked_from?: ImportedForkedFromMetadata;\n [key: string]: unknown;\n};\n\nconst SKILL_MD_FILE = \"SKILL.md\";\nconst METADATA_YAML_FILE = \"metadata.yaml\";\nconst METADATA_JSON_FILE = \"metadata.json\";\nconst DEFAULT_SKILLS_SUBDIR = \"skills\";\n\nfunction parseGitHubSource(source: string): {\n gigetSource: string;\n displaySource: string;\n} {\n if (source.startsWith(\"https://github.com/\")) {\n const path = source.replace(\"https://github.com/\", \"\");\n return {\n gigetSource: `github:${path}`,\n displaySource: source,\n };\n }\n\n if (source.startsWith(\"github:\") || source.startsWith(\"gh:\")) {\n const normalized = source.replace(/^gh:/, \"github:\");\n return {\n gigetSource: normalized,\n displaySource: `https://github.com/${normalized.replace(\"github:\", \"\")}`,\n };\n }\n\n if (source.includes(\"/\") && !source.includes(\":\")) {\n return {\n gigetSource: `github:${source}`,\n displaySource: `https://github.com/${source}`,\n };\n }\n\n return {\n gigetSource: source,\n displaySource: source,\n };\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(\"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 const skillsDir = path.join(repoPath, flags.subdir);\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 this.discoverValidSkills(skillsDir, skillDirs);\n\n if (availableSkills.length === 0) {\n this.error(\n `No valid skills found in ${flags.subdir}/\\n` + `Skills 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 if (flags[\"dry-run\"]) {\n this.log(\"\");\n this.log(\"[DRY RUN] Would import the following skills:\");\n for (const skill of skillsToImport) {\n const destPath = path.join(destDir, skill);\n const exists = await directoryExists(destPath);\n this.log(` - ${skill} -> ${destPath}${exists ? \" (exists)\" : \"\"}`);\n }\n return;\n }\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(\n `Failed to import '${skillName}': ${error instanceof Error ? error.message : String(error)}`,\n );\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(\"Run 'cc compile' to include imported skills in your agents.\");\n this.log(\"\");\n }\n\n private async 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\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(\"Missing required SKILL.md file\");\n }\n\n const contentHash = await hashFile(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 skill_name: skillName,\n content_hash: 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(`Malformed metadata.yaml at ${metadataYamlPath} — existing fields may be lost`);\n }\n const metadata = parseResult.success\n ? (parseResult.data as SkillMetadata)\n : { forked_from: undefined };\n metadata.forked_from = forkedFrom;\n\n const newYamlContent = stringifyYaml(metadata, { lineWidth: 0 });\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(`Malformed JSON in ${metadataJsonPath} — skipping metadata injection`);\n return;\n }\n const jsonResult = importedSkillMetadataSchema.safeParse(jsonParsed);\n const metadata = jsonResult.success\n ? (jsonResult.data as SkillMetadata)\n : { forked_from: undefined };\n metadata.forked_from = forkedFrom;\n\n const yamlContent = stringifyYaml(metadata, { lineWidth: 0 });\n await writeFile(metadataYamlPath, yamlContent);\n return;\n }\n\n const minimalMetadata: SkillMetadata = {\n cli_name: skillName\n .split(\"-\")\n .map((word) => word.charAt(0).toUpperCase() + word.slice(1))\n .join(\" \"),\n cli_description: \"Imported from third-party repository\",\n category: \"imported\",\n category_exclusive: false,\n author: \"@imported\",\n forked_from: forkedFrom,\n };\n\n const yamlContent = stringifyYaml(minimalMetadata, { lineWidth: 0 });\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 {\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 skill_id\n * instead of source/skill_name).\n */\ntype ImportedForkedFromMetadata = {\n source: string;\n skill_name: string;\n content_hash: string;\n date: string;\n};\n\ntype SkillMetadata = {\n forked_from?: 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 if (flags[\"dry-run\"]) {\n this.log(\"\");\n this.log(\"[DRY RUN] Would import the following skills:\");\n for (const skill of skillsToImport) {\n const destPath = path.join(destDir, skill);\n const exists = await directoryExists(destPath);\n this.log(` - ${skill} -> ${destPath}${exists ? \" (exists)\" : \"\"}`);\n }\n return;\n }\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 skill_name: skillName,\n content_hash: 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: cli_name (string), cli_description (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 : { forked_from: undefined };\n metadata.forked_from = 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 : { forked_from: undefined };\n metadata.forked_from = 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 cli_name: skillName\n .split(\"-\")\n .map((word) => word.charAt(0).toUpperCase() + word.slice(1))\n .join(\" \"),\n cli_description: \"Imported from third-party repository\",\n category: IMPORT_DEFAULTS.CATEGORY,\n category_exclusive: false,\n author: IMPORT_DEFAULTS.AUTHOR,\n forked_from: 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"]}
|
package/dist/commands/info.js
CHANGED
|
@@ -1,18 +1,22 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
STATUS_MESSAGES
|
|
4
|
+
} from "../chunk-FUPBGSRA.js";
|
|
2
5
|
import {
|
|
3
6
|
BaseCommand,
|
|
4
7
|
EXIT_CODES
|
|
5
|
-
} from "../chunk-
|
|
8
|
+
} from "../chunk-5I6VY2E7.js";
|
|
6
9
|
import {
|
|
7
10
|
discoverLocalSkills,
|
|
8
11
|
loadSkillsMatrixFromSource
|
|
9
|
-
} from "../chunk-
|
|
12
|
+
} from "../chunk-SSHG7MEE.js";
|
|
10
13
|
import {
|
|
11
14
|
fileExists,
|
|
12
15
|
readFile
|
|
13
|
-
} from "../chunk-
|
|
14
|
-
import
|
|
15
|
-
|
|
16
|
+
} from "../chunk-5WIHSJRO.js";
|
|
17
|
+
import {
|
|
18
|
+
STANDARD_FILES
|
|
19
|
+
} from "../chunk-IFODQTCX.js";
|
|
16
20
|
import {
|
|
17
21
|
init_esm_shims
|
|
18
22
|
} from "../chunk-AWKZ5BDL.js";
|
|
@@ -48,7 +52,7 @@ function getPreviewLines(content, maxLines) {
|
|
|
48
52
|
for (const line of lines) {
|
|
49
53
|
if (result.length >= maxLines) break;
|
|
50
54
|
if (line.trim() || result.length > 0) {
|
|
51
|
-
const truncated = line.length > MAX_LINE_LENGTH ? line.slice(0, MAX_LINE_LENGTH - 3)
|
|
55
|
+
const truncated = line.length > MAX_LINE_LENGTH ? `${line.slice(0, MAX_LINE_LENGTH - 3)}...` : line;
|
|
52
56
|
result.push(truncated);
|
|
53
57
|
}
|
|
54
58
|
}
|
|
@@ -116,6 +120,20 @@ function formatSkillInfo(skill, isInstalled) {
|
|
|
116
120
|
var Info = class _Info extends BaseCommand {
|
|
117
121
|
static summary = "Show detailed information about a skill";
|
|
118
122
|
static description = "Display comprehensive information about a skill including metadata, relationships, and content preview";
|
|
123
|
+
static examples = [
|
|
124
|
+
{
|
|
125
|
+
description: "Show info for a skill by ID",
|
|
126
|
+
command: "<%= config.bin %> <%= command.id %> web-framework-react"
|
|
127
|
+
},
|
|
128
|
+
{
|
|
129
|
+
description: "Show info without content preview",
|
|
130
|
+
command: "<%= config.bin %> <%= command.id %> web-framework-react --no-preview"
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
description: "Show info from a custom source",
|
|
134
|
+
command: "<%= config.bin %> <%= command.id %> my-skill --source github:org/marketplace"
|
|
135
|
+
}
|
|
136
|
+
];
|
|
119
137
|
static args = {
|
|
120
138
|
skill: Args.string({
|
|
121
139
|
description: "Skill ID or alias to look up",
|
|
@@ -133,7 +151,7 @@ var Info = class _Info extends BaseCommand {
|
|
|
133
151
|
async run() {
|
|
134
152
|
const { args, flags } = await this.parse(_Info);
|
|
135
153
|
try {
|
|
136
|
-
this.log(
|
|
154
|
+
this.log(STATUS_MESSAGES.LOADING_SKILLS);
|
|
137
155
|
const { matrix, sourcePath, isLocal } = await loadSkillsMatrixFromSource({
|
|
138
156
|
sourceFlag: flags.source
|
|
139
157
|
});
|
|
@@ -169,10 +187,10 @@ var Info = class _Info extends BaseCommand {
|
|
|
169
187
|
if (flags.preview) {
|
|
170
188
|
let skillMdPath;
|
|
171
189
|
if (skill.local && skill.localPath) {
|
|
172
|
-
skillMdPath = path.join(process.cwd(), skill.localPath,
|
|
190
|
+
skillMdPath = path.join(process.cwd(), skill.localPath, STANDARD_FILES.SKILL_MD);
|
|
173
191
|
} else {
|
|
174
192
|
const sourceDir = isLocal ? sourcePath : path.dirname(sourcePath);
|
|
175
|
-
skillMdPath = path.join(sourceDir, skill.path,
|
|
193
|
+
skillMdPath = path.join(sourceDir, skill.path, STANDARD_FILES.SKILL_MD);
|
|
176
194
|
}
|
|
177
195
|
if (await fileExists(skillMdPath)) {
|
|
178
196
|
const content = await readFile(skillMdPath);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/cli/commands/info.ts"],"sourcesContent":["import { Args, Flags } from \"@oclif/core\";\nimport path from \"path\";\nimport { BaseCommand } from \"../base-command.js\";\nimport { loadSkillsMatrixFromSource } from \"../lib/loading/index.js\";\nimport { discoverLocalSkills } from \"../lib/skills/index.js\";\nimport { fileExists, readFile } from \"../utils/fs.js\";\nimport { EXIT_CODES } from \"../lib/exit-codes.js\";\nimport type {\n ResolvedSkill,\n SkillDisplayName,\n SkillId,\n SkillRelation,\n SkillRequirement,\n} from \"../types/index.js\";\n\nconst CONTENT_PREVIEW_LINES = 10;\nconst MAX_LINE_LENGTH = 80;\nconst MAX_SUGGESTIONS = 5;\n\nfunction stripFrontmatter(content: string): string {\n const lines = content.split(\"\\n\");\n let inFrontmatter = false;\n let frontmatterEndIndex = 0;\n\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i].trim();\n if (line === \"---\") {\n if (!inFrontmatter) {\n inFrontmatter = true;\n } else {\n frontmatterEndIndex = i + 1;\n break;\n }\n }\n }\n\n return lines.slice(frontmatterEndIndex).join(\"\\n\");\n}\n\nfunction getPreviewLines(content: string, maxLines: number): string[] {\n const body = stripFrontmatter(content);\n const lines = body.split(\"\\n\");\n const result: string[] = [];\n\n for (const line of lines) {\n if (result.length >= maxLines) break;\n if (line.trim() || result.length > 0) {\n const truncated =\n line.length > MAX_LINE_LENGTH ? line.slice(0, MAX_LINE_LENGTH - 3) + \"...\" : line;\n result.push(truncated);\n }\n }\n\n return result;\n}\n\nfunction formatRelations(relations: SkillRelation[]): string {\n if (relations.length === 0) {\n return \"(none)\";\n }\n return relations.map((r) => r.skillId).join(\", \");\n}\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 formatTags(tags: string[]): string {\n if (tags.length === 0) {\n return \"(none)\";\n }\n return tags.join(\", \");\n}\n\nfunction findSuggestions(\n skills: Partial<Record<SkillId, ResolvedSkill>>,\n query: string,\n maxSuggestions: number,\n): string[] {\n const lowerQuery = query.toLowerCase();\n const matches: string[] = [];\n\n for (const skill of Object.values(skills)) {\n if (!skill) continue;\n if (matches.length >= maxSuggestions) break;\n if (\n skill.id.toLowerCase().includes(lowerQuery) ||\n skill.displayName?.toLowerCase().includes(lowerQuery)\n ) {\n matches.push(skill.id);\n }\n }\n\n return matches;\n}\n\nfunction formatSkillInfo(skill: ResolvedSkill, isInstalled: boolean): string {\n const lines: string[] = [];\n\n lines.push(`Skill: ${skill.id}`);\n if (skill.displayName) {\n lines.push(`Alias: ${skill.displayName}`);\n }\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(`Tags: ${formatTags(skill.tags)}`);\n lines.push(\"\");\n lines.push(`Requires: ${formatRequirements(skill.requires)}`);\n lines.push(`Conflicts with: ${formatRelations(skill.conflictsWith)}`);\n lines.push(`Recommends: ${formatRelations(skill.recommends)}`);\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 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.log(\"Loading skills...\");\n\n const { matrix, sourcePath, isLocal } = await loadSkillsMatrixFromSource({\n sourceFlag: flags.source,\n });\n\n this.log(`Loaded from ${isLocal ? \"local\" : \"remote\"}: ${sourcePath}`);\n\n // CLI arg is an untyped string — cast at data boundary\n let skill: ResolvedSkill | undefined = matrix.skills[args.skill as SkillId];\n\n if (!skill) {\n // Try alias lookup — CLI arg is an untyped string\n const fullId = matrix.displayNameToId[args.skill as SkillDisplayName];\n if (fullId) {\n skill = matrix.skills[fullId];\n }\n }\n\n if (!skill) {\n const suggestions = findSuggestions(matrix.skills, args.skill, MAX_SUGGESTIONS);\n\n this.log(\"\");\n this.error(`Skill \"${args.skill}\" 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 'cc search <query>' to find available skills.\");\n this.log(\"\");\n this.exit(EXIT_CODES.ERROR);\n }\n\n const localSkillsResult = await discoverLocalSkills(process.cwd());\n const localSkillIds = localSkillsResult?.skills.map((s) => s.id) || [];\n const isInstalled = localSkillIds.includes(skill.id);\n\n this.log(\"\");\n this.log(formatSkillInfo(skill, isInstalled));\n\n if (flags.preview) {\n let skillMdPath: string;\n\n if (skill.local && skill.localPath) {\n skillMdPath = path.join(process.cwd(), skill.localPath, \"SKILL.md\");\n } else {\n const sourceDir = isLocal ? sourcePath : path.dirname(sourcePath);\n skillMdPath = path.join(sourceDir, skill.path, \"SKILL.md\");\n }\n\n if (await fileExists(skillMdPath)) {\n const content = await readFile(skillMdPath);\n const previewLines = getPreviewLines(content, CONTENT_PREVIEW_LINES);\n\n if (previewLines.length > 0) {\n this.log(\"\");\n this.log(`--- Content Preview (first ${CONTENT_PREVIEW_LINES} lines) ---`);\n for (const line of previewLines) {\n this.log(line);\n }\n }\n }\n }\n\n this.log(\"\");\n } catch (error) {\n this.handleError(error);\n }\n }\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/cli/commands/info.ts"],"sourcesContent":["import { Args, Flags } from \"@oclif/core\";\nimport path from \"path\";\nimport { BaseCommand } from \"../base-command.js\";\nimport { loadSkillsMatrixFromSource } from \"../lib/loading/index.js\";\nimport { discoverLocalSkills } from \"../lib/skills/index.js\";\nimport { fileExists, readFile } from \"../utils/fs.js\";\nimport { STANDARD_FILES } from \"../consts.js\";\nimport { EXIT_CODES } from \"../lib/exit-codes.js\";\nimport { STATUS_MESSAGES } from \"../utils/messages.js\";\nimport type {\n ResolvedSkill,\n SkillDisplayName,\n SkillId,\n SkillRelation,\n SkillRequirement,\n} from \"../types/index.js\";\n\nconst CONTENT_PREVIEW_LINES = 10;\nconst MAX_LINE_LENGTH = 80;\nconst MAX_SUGGESTIONS = 5;\n\nfunction stripFrontmatter(content: string): string {\n const lines = content.split(\"\\n\");\n let inFrontmatter = false;\n let frontmatterEndIndex = 0;\n\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i].trim();\n if (line === \"---\") {\n if (!inFrontmatter) {\n inFrontmatter = true;\n } else {\n frontmatterEndIndex = i + 1;\n break;\n }\n }\n }\n\n return lines.slice(frontmatterEndIndex).join(\"\\n\");\n}\n\nfunction getPreviewLines(content: string, maxLines: number): string[] {\n const body = stripFrontmatter(content);\n const lines = body.split(\"\\n\");\n const result: string[] = [];\n\n for (const line of lines) {\n if (result.length >= maxLines) break;\n if (line.trim() || result.length > 0) {\n const truncated =\n line.length > MAX_LINE_LENGTH ? `${line.slice(0, MAX_LINE_LENGTH - 3)}...` : line;\n result.push(truncated);\n }\n }\n\n return result;\n}\n\nfunction formatRelations(relations: SkillRelation[]): string {\n if (relations.length === 0) {\n return \"(none)\";\n }\n return relations.map((r) => r.skillId).join(\", \");\n}\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 formatTags(tags: string[]): string {\n if (tags.length === 0) {\n return \"(none)\";\n }\n return tags.join(\", \");\n}\n\nfunction findSuggestions(\n skills: Partial<Record<SkillId, ResolvedSkill>>,\n query: string,\n maxSuggestions: number,\n): string[] {\n const lowerQuery = query.toLowerCase();\n const matches: string[] = [];\n\n for (const skill of Object.values(skills)) {\n if (!skill) continue;\n if (matches.length >= maxSuggestions) break;\n if (\n skill.id.toLowerCase().includes(lowerQuery) ||\n skill.displayName?.toLowerCase().includes(lowerQuery)\n ) {\n matches.push(skill.id);\n }\n }\n\n return matches;\n}\n\nfunction formatSkillInfo(skill: ResolvedSkill, isInstalled: boolean): string {\n const lines: string[] = [];\n\n lines.push(`Skill: ${skill.id}`);\n if (skill.displayName) {\n lines.push(`Alias: ${skill.displayName}`);\n }\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(`Tags: ${formatTags(skill.tags)}`);\n lines.push(\"\");\n lines.push(`Requires: ${formatRequirements(skill.requires)}`);\n lines.push(`Conflicts with: ${formatRelations(skill.conflictsWith)}`);\n lines.push(`Recommends: ${formatRelations(skill.recommends)}`);\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.log(STATUS_MESSAGES.LOADING_SKILLS);\n\n const { matrix, sourcePath, isLocal } = await loadSkillsMatrixFromSource({\n sourceFlag: flags.source,\n });\n\n this.log(`Loaded from ${isLocal ? \"local\" : \"remote\"}: ${sourcePath}`);\n\n // CLI arg is an untyped string — cast at data boundary\n let skill: ResolvedSkill | undefined = matrix.skills[args.skill as SkillId];\n\n if (!skill) {\n // Try alias lookup — CLI arg is an untyped string\n const fullId = matrix.displayNameToId[args.skill as SkillDisplayName];\n if (fullId) {\n skill = matrix.skills[fullId];\n }\n }\n\n if (!skill) {\n const suggestions = findSuggestions(matrix.skills, args.skill, MAX_SUGGESTIONS);\n\n this.log(\"\");\n this.error(`Skill \"${args.skill}\" 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 'cc search <query>' to find available skills.\");\n this.log(\"\");\n this.exit(EXIT_CODES.ERROR);\n }\n\n const localSkillsResult = await discoverLocalSkills(process.cwd());\n const localSkillIds = localSkillsResult?.skills.map((s) => s.id) || [];\n const isInstalled = localSkillIds.includes(skill.id);\n\n this.log(\"\");\n this.log(formatSkillInfo(skill, isInstalled));\n\n if (flags.preview) {\n let skillMdPath: string;\n\n if (skill.local && skill.localPath) {\n skillMdPath = path.join(process.cwd(), skill.localPath, STANDARD_FILES.SKILL_MD);\n } else {\n const sourceDir = isLocal ? sourcePath : path.dirname(sourcePath);\n skillMdPath = path.join(sourceDir, skill.path, STANDARD_FILES.SKILL_MD);\n }\n\n if (await fileExists(skillMdPath)) {\n const content = await readFile(skillMdPath);\n const previewLines = getPreviewLines(content, CONTENT_PREVIEW_LINES);\n\n if (previewLines.length > 0) {\n this.log(\"\");\n this.log(`--- Content Preview (first ${CONTENT_PREVIEW_LINES} lines) ---`);\n for (const line of previewLines) {\n this.log(line);\n }\n }\n }\n }\n\n this.log(\"\");\n } catch (error) {\n this.handleError(error);\n }\n }\n}\n"],"mappings":"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","names":[]}
|