@claude-collective/cli 0.6.0 → 0.13.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 +192 -0
- package/README.md +26 -9
- package/dist/{chunk-TOPAIL5W.js → chunk-3U3R4NCG.js} +2 -2
- package/dist/chunk-3U3R4NCG.js.map +1 -0
- package/dist/{chunk-TFV6Z7F7.js → chunk-57Y5RALO.js} +10 -10
- package/dist/chunk-57Y5RALO.js.map +1 -0
- package/dist/chunk-66UDJBF6.js +96 -0
- package/dist/chunk-66UDJBF6.js.map +1 -0
- package/dist/chunk-6DCSSORF.js +264 -0
- package/dist/chunk-6DCSSORF.js.map +1 -0
- package/dist/chunk-6Q3Y7KVB.js +31 -0
- package/dist/chunk-6Q3Y7KVB.js.map +1 -0
- package/dist/{chunk-SJYG4EJZ.js → chunk-76DWXGQE.js} +10 -8
- package/dist/chunk-76DWXGQE.js.map +1 -0
- package/dist/{chunk-AZP2AA5M.js → chunk-7Q44DMSP.js} +241 -84
- package/dist/chunk-7Q44DMSP.js.map +1 -0
- package/dist/chunk-ACNBKXXJ.js +321 -0
- package/dist/chunk-ACNBKXXJ.js.map +1 -0
- package/dist/{chunk-JMQGWQZU.js → chunk-B7CCVP6Q.js} +42 -10
- package/dist/chunk-B7CCVP6Q.js.map +1 -0
- package/dist/chunk-BDLUZVKU.js +54 -0
- package/dist/chunk-BDLUZVKU.js.map +1 -0
- package/dist/chunk-CDX4W4DM.js +120 -0
- package/dist/chunk-CDX4W4DM.js.map +1 -0
- package/dist/{chunk-MYAVQ23U.js → chunk-CJEHB4TB.js} +23 -9
- package/dist/chunk-CJEHB4TB.js.map +1 -0
- package/dist/{chunk-6WEQADPL.js → chunk-CPZOTVCI.js} +15 -14
- package/dist/chunk-CPZOTVCI.js.map +1 -0
- package/dist/chunk-D237EVNB.js +187 -0
- package/dist/chunk-D237EVNB.js.map +1 -0
- package/dist/{chunk-UFWNMW3G.js → chunk-DRXPNNPB.js} +19 -18
- package/dist/chunk-DRXPNNPB.js.map +1 -0
- package/dist/chunk-E3FJH4TF.js +80 -0
- package/dist/chunk-E3FJH4TF.js.map +1 -0
- package/dist/{chunk-D4IQAT27.js → chunk-ED4E6Q2T.js} +10 -10
- package/dist/chunk-ED4E6Q2T.js.map +1 -0
- package/dist/{chunk-SYQ7R2JO.js → chunk-EHS3TWWP.js} +3 -3
- package/dist/chunk-EHS3TWWP.js.map +1 -0
- package/dist/{chunk-AU7XVCLO.js → chunk-GDH553MV.js} +6 -6
- package/dist/chunk-GDH553MV.js.map +1 -0
- package/dist/chunk-HLJX2FTL.js +95 -0
- package/dist/chunk-HLJX2FTL.js.map +1 -0
- package/dist/chunk-I2DSLOXZ.js +75 -0
- package/dist/chunk-I2DSLOXZ.js.map +1 -0
- package/dist/{chunk-J2Y4A3LP.js → chunk-I4TPKIYX.js} +33 -18
- package/dist/chunk-I4TPKIYX.js.map +1 -0
- package/dist/{chunk-ZSKHDU5P.js → chunk-IMDW5ZUP.js} +19 -11
- package/dist/chunk-IMDW5ZUP.js.map +1 -0
- package/dist/{chunk-U4VYHKPM.js → chunk-JIPWV2FX.js} +6 -6
- package/dist/chunk-JIPWV2FX.js.map +1 -0
- package/dist/{chunk-OSQDDJXX.js → chunk-K7EVM5LY.js} +5 -10
- package/dist/chunk-K7EVM5LY.js.map +1 -0
- package/dist/{chunk-MJSFR562.js → chunk-KAAEN2PO.js} +3 -3
- package/dist/chunk-KAAEN2PO.js.map +1 -0
- package/dist/{chunk-URDV4OCP.js → chunk-LE6IY6IT.js} +22 -17
- package/dist/chunk-LE6IY6IT.js.map +1 -0
- package/dist/{chunk-FKU7VSUD.js → chunk-NDY25DTL.js} +6 -6
- package/dist/chunk-NDY25DTL.js.map +1 -0
- package/dist/{chunk-UNHCZRO4.js → chunk-P26A2K5N.js} +7 -7
- package/dist/chunk-P26A2K5N.js.map +1 -0
- package/dist/{chunk-DHFFRMF6.js → chunk-RTE64SJA.js} +2 -2
- package/dist/chunk-RTE64SJA.js.map +1 -0
- package/dist/{chunk-6ESUJMM7.js → chunk-SGJ23HIP.js} +14 -11
- package/dist/chunk-SGJ23HIP.js.map +1 -0
- package/dist/{chunk-367K3JB3.js → chunk-SVYPSDWY.js} +10 -10
- package/dist/chunk-SVYPSDWY.js.map +1 -0
- package/dist/{chunk-MMDXNZPF.js → chunk-TKFPKEV3.js} +2 -2
- package/dist/chunk-TKFPKEV3.js.map +1 -0
- package/dist/{chunk-M7YCPFIX.js → chunk-UQTEPWU7.js} +2 -2
- package/dist/chunk-UQTEPWU7.js.map +1 -0
- package/dist/{chunk-QESUUPOE.js → chunk-V46GGCCI.js} +80 -27
- package/dist/chunk-V46GGCCI.js.map +1 -0
- package/dist/chunk-X6QONICW.js +86 -0
- package/dist/chunk-X6QONICW.js.map +1 -0
- package/dist/chunk-XY3XDVMI.js +15599 -0
- package/dist/chunk-XY3XDVMI.js.map +1 -0
- package/dist/chunk-Y2LW7R3Y.js +23 -0
- package/dist/chunk-Y2LW7R3Y.js.map +1 -0
- package/dist/chunk-Z2CWURZ6.js +78 -0
- package/dist/chunk-Z2CWURZ6.js.map +1 -0
- package/dist/chunk-Z7G4B5HJ.js +377 -0
- package/dist/chunk-Z7G4B5HJ.js.map +1 -0
- package/dist/{chunk-ZDQIUHAM.js → chunk-ZENYS6KW.js} +16 -15
- package/dist/chunk-ZENYS6KW.js.map +1 -0
- package/dist/{cli-v2 → cli}/defaults/agent-mappings.yaml +5 -5
- package/dist/commands/build/marketplace.js +19 -60
- package/dist/commands/build/marketplace.js.map +1 -1
- package/dist/commands/build/plugins.js +21 -59
- package/dist/commands/build/plugins.js.map +1 -1
- package/dist/commands/build/stack.js +15 -15
- package/dist/commands/build/stack.js.map +1 -1
- package/dist/commands/compile.js +21 -21
- package/dist/commands/compile.js.map +1 -1
- package/dist/commands/config/get.js +9 -8
- package/dist/commands/config/get.js.map +1 -1
- package/dist/commands/config/index.js +7 -6
- package/dist/commands/config/index.js.map +1 -1
- package/dist/commands/config/path.js +8 -7
- package/dist/commands/config/path.js.map +1 -1
- package/dist/commands/config/set-project.js +9 -8
- package/dist/commands/config/set-project.js.map +1 -1
- package/dist/commands/config/set.js +9 -8
- package/dist/commands/config/set.js.map +1 -1
- package/dist/commands/config/show.js +6 -5
- package/dist/commands/config/unset-project.js +9 -8
- package/dist/commands/config/unset-project.js.map +1 -1
- package/dist/commands/config/unset.js +9 -8
- package/dist/commands/config/unset.js.map +1 -1
- package/dist/commands/diff.js +12 -12
- package/dist/commands/diff.js.map +1 -1
- package/dist/commands/doctor.js +10 -10
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/edit.js +52 -48
- package/dist/commands/edit.js.map +1 -1
- package/dist/commands/eject.js +180 -97
- package/dist/commands/eject.js.map +1 -1
- package/dist/commands/import/skill.js +339 -0
- package/dist/commands/import/skill.js.map +1 -0
- package/dist/commands/info.js +9 -9
- package/dist/commands/info.js.map +1 -1
- package/dist/commands/init.js +205 -77
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/list.js +9 -9
- package/dist/commands/list.js.map +1 -1
- package/dist/commands/new/agent.js +19 -21
- package/dist/commands/new/agent.js.map +1 -1
- package/dist/commands/new/skill.js +11 -12
- package/dist/commands/new/skill.js.map +1 -1
- package/dist/commands/outdated.js +12 -12
- package/dist/commands/outdated.js.map +1 -1
- package/dist/commands/search.js +205 -17
- package/dist/commands/search.js.map +1 -1
- package/dist/commands/test-imports.js +18 -18
- package/dist/commands/test-imports.js.map +1 -1
- package/dist/commands/uninstall.js +70 -83
- package/dist/commands/uninstall.js.map +1 -1
- package/dist/commands/update.js +22 -22
- package/dist/commands/update.js.map +1 -1
- package/dist/commands/validate.js +9 -9
- package/dist/commands/validate.js.map +1 -1
- package/dist/commands/version/bump.js +8 -8
- package/dist/commands/version/bump.js.map +1 -1
- package/dist/commands/version/index.js +8 -8
- package/dist/commands/version/index.js.map +1 -1
- package/dist/commands/version/set.js +7 -7
- package/dist/commands/version/set.js.map +1 -1
- package/dist/commands/version/show.js +8 -8
- package/dist/commands/version/show.js.map +1 -1
- package/dist/components/common/confirm.js +1 -1
- package/dist/components/common/message.js +1 -1
- package/dist/components/common/message.js.map +1 -1
- package/dist/components/common/spinner.js +1 -1
- package/dist/components/common/spinner.js.map +1 -1
- package/dist/components/skill-search/skill-search.js +10 -0
- package/dist/components/wizard/category-grid.js +9 -0
- package/dist/components/wizard/category-grid.test.js +861 -0
- package/dist/components/wizard/category-grid.test.js.map +1 -0
- package/dist/components/wizard/section-progress.js +9 -0
- package/dist/components/wizard/section-progress.test.js +281 -0
- package/dist/components/wizard/section-progress.test.js.map +1 -0
- package/dist/components/wizard/step-approach.js +4 -3
- package/dist/components/wizard/step-build.js +16 -0
- package/dist/components/wizard/step-build.js.map +1 -0
- package/dist/components/wizard/step-build.test.js +741 -0
- package/dist/components/wizard/step-build.test.js.map +1 -0
- package/dist/components/wizard/step-confirm.js +2 -4
- package/dist/components/wizard/step-refine.js +10 -0
- package/dist/components/wizard/step-refine.js.map +1 -0
- package/dist/components/wizard/step-refine.test.js +236 -0
- package/dist/components/wizard/step-refine.test.js.map +1 -0
- package/dist/components/wizard/step-stack-options.js +11 -0
- package/dist/components/wizard/step-stack-options.js.map +1 -0
- package/dist/components/wizard/step-stack.js +3 -3
- package/dist/components/wizard/wizard-footer.js +9 -0
- package/dist/components/wizard/wizard-footer.js.map +1 -0
- package/dist/components/wizard/wizard-tabs.js +11 -0
- package/dist/components/wizard/wizard-tabs.js.map +1 -0
- package/dist/components/wizard/wizard.js +14 -11
- package/dist/hooks/init.js +5 -4
- package/dist/hooks/init.js.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/stores/wizard-store.js +2 -2
- package/dist/stores/wizard-store.test.js +249 -15835
- package/dist/stores/wizard-store.test.js.map +1 -1
- package/package.json +3 -2
- package/dist/chunk-367K3JB3.js.map +0 -1
- package/dist/chunk-6ESUJMM7.js.map +0 -1
- package/dist/chunk-6OY6ZYQF.js +0 -93
- package/dist/chunk-6OY6ZYQF.js.map +0 -1
- package/dist/chunk-6WEQADPL.js.map +0 -1
- package/dist/chunk-AU7XVCLO.js.map +0 -1
- package/dist/chunk-AZP2AA5M.js.map +0 -1
- package/dist/chunk-D4IQAT27.js.map +0 -1
- package/dist/chunk-DHFFRMF6.js.map +0 -1
- package/dist/chunk-FKU7VSUD.js.map +0 -1
- package/dist/chunk-J2Y4A3LP.js.map +0 -1
- package/dist/chunk-JMQGWQZU.js.map +0 -1
- package/dist/chunk-JY4RO76L.js +0 -73
- package/dist/chunk-JY4RO76L.js.map +0 -1
- package/dist/chunk-M7YCPFIX.js.map +0 -1
- package/dist/chunk-MJSFR562.js.map +0 -1
- package/dist/chunk-MMDXNZPF.js.map +0 -1
- package/dist/chunk-MYAVQ23U.js.map +0 -1
- package/dist/chunk-OSQDDJXX.js.map +0 -1
- package/dist/chunk-QESUUPOE.js.map +0 -1
- package/dist/chunk-SJYG4EJZ.js.map +0 -1
- package/dist/chunk-SYQ7R2JO.js.map +0 -1
- package/dist/chunk-TD643KB3.js +0 -245
- package/dist/chunk-TD643KB3.js.map +0 -1
- package/dist/chunk-TFV6Z7F7.js.map +0 -1
- package/dist/chunk-TGOHJCQ4.js +0 -83
- package/dist/chunk-TGOHJCQ4.js.map +0 -1
- package/dist/chunk-TOPAIL5W.js.map +0 -1
- package/dist/chunk-U4VYHKPM.js.map +0 -1
- package/dist/chunk-UFWNMW3G.js.map +0 -1
- package/dist/chunk-UNHCZRO4.js.map +0 -1
- package/dist/chunk-URDV4OCP.js.map +0 -1
- package/dist/chunk-YI6JVSFO.js +0 -43
- package/dist/chunk-YI6JVSFO.js.map +0 -1
- package/dist/chunk-YNSNRR5D.js +0 -184
- package/dist/chunk-YNSNRR5D.js.map +0 -1
- package/dist/chunk-Z6DLWTBY.js +0 -46
- package/dist/chunk-Z6DLWTBY.js.map +0 -1
- package/dist/chunk-ZDQIUHAM.js.map +0 -1
- package/dist/chunk-ZSKHDU5P.js.map +0 -1
- package/dist/components/wizard/selection-header.js +0 -11
- package/dist/components/wizard/step-category.js +0 -12
- package/dist/components/wizard/step-subcategory.js +0 -13
- /package/dist/components/{wizard/selection-header.js.map → skill-search/skill-search.js.map} +0 -0
- /package/dist/components/wizard/{step-category.js.map → category-grid.js.map} +0 -0
- /package/dist/components/wizard/{step-subcategory.js.map → section-progress.js.map} +0 -0
|
@@ -0,0 +1,339 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
hashFile
|
|
4
|
+
} from "../../chunk-KAAEN2PO.js";
|
|
5
|
+
import {
|
|
6
|
+
fetchFromSource
|
|
7
|
+
} from "../../chunk-IMDW5ZUP.js";
|
|
8
|
+
import {
|
|
9
|
+
BaseCommand,
|
|
10
|
+
EXIT_CODES
|
|
11
|
+
} from "../../chunk-EHS3TWWP.js";
|
|
12
|
+
import "../../chunk-V46GGCCI.js";
|
|
13
|
+
import "../../chunk-3U3R4NCG.js";
|
|
14
|
+
import {
|
|
15
|
+
copy,
|
|
16
|
+
directoryExists,
|
|
17
|
+
ensureDir,
|
|
18
|
+
fileExists,
|
|
19
|
+
listDirectories,
|
|
20
|
+
readFile,
|
|
21
|
+
writeFile
|
|
22
|
+
} from "../../chunk-TKFPKEV3.js";
|
|
23
|
+
import {
|
|
24
|
+
LOCAL_SKILLS_PATH
|
|
25
|
+
} from "../../chunk-76DWXGQE.js";
|
|
26
|
+
import {
|
|
27
|
+
init_esm_shims
|
|
28
|
+
} from "../../chunk-DHET7RCE.js";
|
|
29
|
+
|
|
30
|
+
// src/cli/commands/import/skill.ts
|
|
31
|
+
init_esm_shims();
|
|
32
|
+
import { Args, Flags } from "@oclif/core";
|
|
33
|
+
import path from "path";
|
|
34
|
+
import { parse as parseYaml, stringify as stringifyYaml } from "yaml";
|
|
35
|
+
var SKILL_MD_FILE = "SKILL.md";
|
|
36
|
+
var METADATA_YAML_FILE = "metadata.yaml";
|
|
37
|
+
var METADATA_JSON_FILE = "metadata.json";
|
|
38
|
+
var DEFAULT_SKILLS_SUBDIR = "skills";
|
|
39
|
+
function parseGitHubSource(source) {
|
|
40
|
+
if (source.startsWith("https://github.com/")) {
|
|
41
|
+
const path2 = source.replace("https://github.com/", "");
|
|
42
|
+
return {
|
|
43
|
+
gigetSource: `github:${path2}`,
|
|
44
|
+
displaySource: source
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
if (source.startsWith("github:") || source.startsWith("gh:")) {
|
|
48
|
+
const normalized = source.replace(/^gh:/, "github:");
|
|
49
|
+
return {
|
|
50
|
+
gigetSource: normalized,
|
|
51
|
+
displaySource: `https://github.com/${normalized.replace("github:", "")}`
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
if (source.includes("/") && !source.includes(":")) {
|
|
55
|
+
return {
|
|
56
|
+
gigetSource: `github:${source}`,
|
|
57
|
+
displaySource: `https://github.com/${source}`
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
return {
|
|
61
|
+
gigetSource: source,
|
|
62
|
+
displaySource: source
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
function getCurrentDate() {
|
|
66
|
+
return (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
67
|
+
}
|
|
68
|
+
var ImportSkill = class _ImportSkill extends BaseCommand {
|
|
69
|
+
static summary = "Import a skill from a third-party GitHub repository";
|
|
70
|
+
static description = "Download and import skills from external GitHub repositories into your local .claude/skills/ directory. Supports importing specific skills or listing available skills.";
|
|
71
|
+
static examples = [
|
|
72
|
+
{
|
|
73
|
+
description: "List available skills from a repository",
|
|
74
|
+
command: "<%= config.bin %> import skill github:vercel-labs/agent-skills --list"
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
description: "Import a specific skill",
|
|
78
|
+
command: "<%= config.bin %> import skill github:vercel-labs/agent-skills --skill react-best-practices"
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
description: "Import all skills from a repository",
|
|
82
|
+
command: "<%= config.bin %> import skill github:vercel-labs/agent-skills --all"
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
description: "Import with custom skills directory",
|
|
86
|
+
command: "<%= config.bin %> import skill github:owner/repo --skill my-skill --subdir custom-skills"
|
|
87
|
+
}
|
|
88
|
+
];
|
|
89
|
+
static args = {
|
|
90
|
+
source: Args.string({
|
|
91
|
+
description: "GitHub repository source (github:owner/repo, https://github.com/owner/repo, or owner/repo)",
|
|
92
|
+
required: true
|
|
93
|
+
})
|
|
94
|
+
};
|
|
95
|
+
static flags = {
|
|
96
|
+
...BaseCommand.baseFlags,
|
|
97
|
+
skill: Flags.string({
|
|
98
|
+
char: "n",
|
|
99
|
+
description: "Name of the specific skill to import",
|
|
100
|
+
required: false
|
|
101
|
+
}),
|
|
102
|
+
all: Flags.boolean({
|
|
103
|
+
char: "a",
|
|
104
|
+
description: "Import all skills from the repository",
|
|
105
|
+
default: false
|
|
106
|
+
}),
|
|
107
|
+
list: Flags.boolean({
|
|
108
|
+
char: "l",
|
|
109
|
+
description: "List available skills without importing",
|
|
110
|
+
default: false
|
|
111
|
+
}),
|
|
112
|
+
subdir: Flags.string({
|
|
113
|
+
description: "Subdirectory containing skills (default: skills)",
|
|
114
|
+
default: DEFAULT_SKILLS_SUBDIR
|
|
115
|
+
}),
|
|
116
|
+
force: Flags.boolean({
|
|
117
|
+
char: "f",
|
|
118
|
+
description: "Overwrite existing skills",
|
|
119
|
+
default: false
|
|
120
|
+
}),
|
|
121
|
+
refresh: Flags.boolean({
|
|
122
|
+
description: "Force refresh from remote (ignore cache)",
|
|
123
|
+
default: false
|
|
124
|
+
})
|
|
125
|
+
};
|
|
126
|
+
async run() {
|
|
127
|
+
const { args, flags } = await this.parse(_ImportSkill);
|
|
128
|
+
const projectDir = process.cwd();
|
|
129
|
+
this.log("");
|
|
130
|
+
this.log("Import Third-Party Skill");
|
|
131
|
+
this.log("");
|
|
132
|
+
if (!flags.list && !flags.skill && !flags.all) {
|
|
133
|
+
this.error(
|
|
134
|
+
"Please specify --skill <name>, --all, or --list to list available skills",
|
|
135
|
+
{ exit: EXIT_CODES.INVALID_ARGS }
|
|
136
|
+
);
|
|
137
|
+
}
|
|
138
|
+
if (flags.skill && flags.all) {
|
|
139
|
+
this.error("Cannot use --skill and --all together", {
|
|
140
|
+
exit: EXIT_CODES.INVALID_ARGS
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
const { gigetSource, displaySource } = parseGitHubSource(args.source);
|
|
144
|
+
this.log(`Source: ${displaySource}`);
|
|
145
|
+
this.log("Fetching repository...");
|
|
146
|
+
let repoPath;
|
|
147
|
+
try {
|
|
148
|
+
const result = await fetchFromSource(gigetSource, {
|
|
149
|
+
forceRefresh: flags.refresh
|
|
150
|
+
});
|
|
151
|
+
repoPath = result.path;
|
|
152
|
+
this.log(
|
|
153
|
+
result.fromCache ? "Using cached source" : "Downloaded fresh copy"
|
|
154
|
+
);
|
|
155
|
+
} catch (error) {
|
|
156
|
+
this.error(
|
|
157
|
+
error instanceof Error ? error.message : `Failed to fetch: ${args.source}`,
|
|
158
|
+
{ exit: EXIT_CODES.NETWORK_ERROR }
|
|
159
|
+
);
|
|
160
|
+
}
|
|
161
|
+
const skillsDir = path.join(repoPath, flags.subdir);
|
|
162
|
+
if (!await directoryExists(skillsDir)) {
|
|
163
|
+
this.error(
|
|
164
|
+
`Skills directory not found: ${flags.subdir}
|
|
165
|
+
The repository doesn't have a '${flags.subdir}' directory.
|
|
166
|
+
Use --subdir to specify a different location.`,
|
|
167
|
+
{ exit: EXIT_CODES.INVALID_ARGS }
|
|
168
|
+
);
|
|
169
|
+
}
|
|
170
|
+
const skillDirs = await listDirectories(skillsDir);
|
|
171
|
+
const availableSkills = await this.discoverValidSkills(
|
|
172
|
+
skillsDir,
|
|
173
|
+
skillDirs
|
|
174
|
+
);
|
|
175
|
+
if (availableSkills.length === 0) {
|
|
176
|
+
this.error(
|
|
177
|
+
`No valid skills found in ${flags.subdir}/
|
|
178
|
+
Skills must have a SKILL.md file.`,
|
|
179
|
+
{ exit: EXIT_CODES.ERROR }
|
|
180
|
+
);
|
|
181
|
+
}
|
|
182
|
+
if (flags.list) {
|
|
183
|
+
this.log("");
|
|
184
|
+
this.log(`Available skills (${availableSkills.length}):`);
|
|
185
|
+
this.log("");
|
|
186
|
+
for (const skill of availableSkills) {
|
|
187
|
+
this.log(` - ${skill}`);
|
|
188
|
+
}
|
|
189
|
+
this.log("");
|
|
190
|
+
this.log(
|
|
191
|
+
"Use --skill <name> to import a specific skill, or --all to import all."
|
|
192
|
+
);
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
let skillsToImport = [];
|
|
196
|
+
if (flags.all) {
|
|
197
|
+
skillsToImport = availableSkills;
|
|
198
|
+
} else if (flags.skill) {
|
|
199
|
+
if (!availableSkills.includes(flags.skill)) {
|
|
200
|
+
this.error(
|
|
201
|
+
`Skill '${flags.skill}' not found in repository.
|
|
202
|
+
Available skills: ${availableSkills.join(", ")}
|
|
203
|
+
Use --list to see all available skills.`,
|
|
204
|
+
{ exit: EXIT_CODES.INVALID_ARGS }
|
|
205
|
+
);
|
|
206
|
+
}
|
|
207
|
+
skillsToImport = [flags.skill];
|
|
208
|
+
}
|
|
209
|
+
const destDir = path.join(projectDir, LOCAL_SKILLS_PATH);
|
|
210
|
+
if (flags["dry-run"]) {
|
|
211
|
+
this.log("");
|
|
212
|
+
this.log("[DRY RUN] Would import the following skills:");
|
|
213
|
+
for (const skill of skillsToImport) {
|
|
214
|
+
const destPath = path.join(destDir, skill);
|
|
215
|
+
const exists = await directoryExists(destPath);
|
|
216
|
+
this.log(` - ${skill} -> ${destPath}${exists ? " (exists)" : ""}`);
|
|
217
|
+
}
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
this.log("");
|
|
221
|
+
this.log(`Importing ${skillsToImport.length} skill(s)...`);
|
|
222
|
+
let imported = 0;
|
|
223
|
+
let skipped = 0;
|
|
224
|
+
for (const skillName of skillsToImport) {
|
|
225
|
+
const sourcePath = path.join(skillsDir, skillName);
|
|
226
|
+
const destPath = path.join(destDir, skillName);
|
|
227
|
+
if (await directoryExists(destPath)) {
|
|
228
|
+
if (!flags.force) {
|
|
229
|
+
this.warn(
|
|
230
|
+
`Skipping '${skillName}': already exists. Use --force to overwrite.`
|
|
231
|
+
);
|
|
232
|
+
skipped++;
|
|
233
|
+
continue;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
try {
|
|
237
|
+
await this.importSkill(sourcePath, destPath, skillName, displaySource);
|
|
238
|
+
this.logSuccess(`Imported: ${skillName}`);
|
|
239
|
+
imported++;
|
|
240
|
+
} catch (error) {
|
|
241
|
+
this.warn(
|
|
242
|
+
`Failed to import '${skillName}': ${error instanceof Error ? error.message : String(error)}`
|
|
243
|
+
);
|
|
244
|
+
skipped++;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
this.log("");
|
|
248
|
+
this.logSuccess(
|
|
249
|
+
`Import complete: ${imported} imported, ${skipped} skipped`
|
|
250
|
+
);
|
|
251
|
+
this.log(`Skills location: ${destDir}`);
|
|
252
|
+
this.log("");
|
|
253
|
+
this.log("Run 'cc compile' to include imported skills in your agents.");
|
|
254
|
+
this.log("");
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
257
|
+
* Discover valid skills in a directory.
|
|
258
|
+
* A valid skill must have a SKILL.md file.
|
|
259
|
+
*/
|
|
260
|
+
async discoverValidSkills(skillsDir, skillDirs) {
|
|
261
|
+
const validSkills = [];
|
|
262
|
+
for (const skillDir of skillDirs) {
|
|
263
|
+
const skillMdPath = path.join(skillsDir, skillDir, SKILL_MD_FILE);
|
|
264
|
+
if (await fileExists(skillMdPath)) {
|
|
265
|
+
validSkills.push(skillDir);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
return validSkills.sort();
|
|
269
|
+
}
|
|
270
|
+
/**
|
|
271
|
+
* Import a single skill to the destination directory.
|
|
272
|
+
*/
|
|
273
|
+
async importSkill(sourcePath, destPath, skillName, source) {
|
|
274
|
+
const skillMdPath = path.join(sourcePath, SKILL_MD_FILE);
|
|
275
|
+
if (!await fileExists(skillMdPath)) {
|
|
276
|
+
throw new Error("Missing required SKILL.md file");
|
|
277
|
+
}
|
|
278
|
+
const contentHash = await hashFile(skillMdPath);
|
|
279
|
+
await ensureDir(path.dirname(destPath));
|
|
280
|
+
await copy(sourcePath, destPath);
|
|
281
|
+
await this.injectForkedFromMetadata(
|
|
282
|
+
destPath,
|
|
283
|
+
skillName,
|
|
284
|
+
source,
|
|
285
|
+
contentHash
|
|
286
|
+
);
|
|
287
|
+
}
|
|
288
|
+
/**
|
|
289
|
+
* Inject forked_from metadata into the skill's metadata file.
|
|
290
|
+
* Creates metadata.yaml if it doesn't exist.
|
|
291
|
+
*/
|
|
292
|
+
async injectForkedFromMetadata(destPath, skillName, source, contentHash) {
|
|
293
|
+
const metadataYamlPath = path.join(destPath, METADATA_YAML_FILE);
|
|
294
|
+
const metadataJsonPath = path.join(destPath, METADATA_JSON_FILE);
|
|
295
|
+
const forkedFrom = {
|
|
296
|
+
source,
|
|
297
|
+
skill_name: skillName,
|
|
298
|
+
content_hash: contentHash,
|
|
299
|
+
date: getCurrentDate()
|
|
300
|
+
};
|
|
301
|
+
if (await fileExists(metadataYamlPath)) {
|
|
302
|
+
const rawContent = await readFile(metadataYamlPath);
|
|
303
|
+
const lines = rawContent.split("\n");
|
|
304
|
+
let yamlContent2 = rawContent;
|
|
305
|
+
let schemaComment = "";
|
|
306
|
+
if (lines[0]?.startsWith("# yaml-language-server:")) {
|
|
307
|
+
schemaComment = lines[0] + "\n";
|
|
308
|
+
yamlContent2 = lines.slice(1).join("\n");
|
|
309
|
+
}
|
|
310
|
+
const metadata = parseYaml(yamlContent2);
|
|
311
|
+
metadata.forked_from = forkedFrom;
|
|
312
|
+
const newYamlContent = stringifyYaml(metadata, { lineWidth: 0 });
|
|
313
|
+
await writeFile(metadataYamlPath, schemaComment + newYamlContent);
|
|
314
|
+
return;
|
|
315
|
+
}
|
|
316
|
+
if (await fileExists(metadataJsonPath)) {
|
|
317
|
+
const rawContent = await readFile(metadataJsonPath);
|
|
318
|
+
const metadata = JSON.parse(rawContent);
|
|
319
|
+
metadata.forked_from = forkedFrom;
|
|
320
|
+
const yamlContent2 = stringifyYaml(metadata, { lineWidth: 0 });
|
|
321
|
+
await writeFile(metadataYamlPath, yamlContent2);
|
|
322
|
+
return;
|
|
323
|
+
}
|
|
324
|
+
const minimalMetadata = {
|
|
325
|
+
cli_name: skillName.split("-").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" "),
|
|
326
|
+
cli_description: "Imported from third-party repository",
|
|
327
|
+
category: "imported",
|
|
328
|
+
category_exclusive: false,
|
|
329
|
+
author: "@imported",
|
|
330
|
+
forked_from: forkedFrom
|
|
331
|
+
};
|
|
332
|
+
const yamlContent = stringifyYaml(minimalMetadata, { lineWidth: 0 });
|
|
333
|
+
await writeFile(metadataYamlPath, yamlContent);
|
|
334
|
+
}
|
|
335
|
+
};
|
|
336
|
+
export {
|
|
337
|
+
ImportSkill as default
|
|
338
|
+
};
|
|
339
|
+
//# sourceMappingURL=skill.js.map
|
|
@@ -0,0 +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/source-fetcher.js\";\nimport { 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 where a skill was imported from.\n */\ninterface ForkedFromMetadata {\n source: string;\n skill_name: string;\n content_hash: string;\n date: string;\n}\n\ninterface SkillMetadata {\n forked_from?: ForkedFromMetadata;\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\n/**\n * Parse a GitHub source string into owner/repo and optional subdir.\n *\n * Supported formats:\n * - https://github.com/owner/repo\n * - github:owner/repo\n * - gh:owner/repo\n * - owner/repo (assumes GitHub)\n */\nfunction parseGitHubSource(source: string): {\n gigetSource: string;\n displaySource: string;\n} {\n // Full GitHub URL\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 // Already in giget format\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 // Assume owner/repo format\n if (source.includes(\"/\") && !source.includes(\":\")) {\n return {\n gigetSource: `github:${source}`,\n displaySource: `https://github.com/${source}`,\n };\n }\n\n // Return as-is for other sources (might be a local path or other provider)\n return {\n gigetSource: source,\n displaySource: source,\n };\n}\n\nfunction getCurrentDate(): string {\n return new Date().toISOString().split(\"T\")[0];\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:\n \"<%= 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:\n \"<%= 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 // Validate flags\n if (!flags.list && !flags.skill && !flags.all) {\n this.error(\n \"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 // Parse the source\n const { gigetSource, displaySource } = parseGitHubSource(args.source);\n this.log(`Source: ${displaySource}`);\n\n // Fetch the repository\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(\n result.fromCache ? \"Using cached source\" : \"Downloaded fresh copy\",\n );\n } catch (error) {\n this.error(\n error instanceof Error\n ? error.message\n : `Failed to fetch: ${args.source}`,\n { exit: EXIT_CODES.NETWORK_ERROR },\n );\n }\n\n // Find skills directory\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 // Discover available skills\n const skillDirs = await listDirectories(skillsDir);\n const availableSkills = await this.discoverValidSkills(\n skillsDir,\n skillDirs,\n );\n\n if (availableSkills.length === 0) {\n this.error(\n `No valid skills found in ${flags.subdir}/\\n` +\n `Skills must have a SKILL.md file.`,\n { exit: EXIT_CODES.ERROR },\n );\n }\n\n // Handle --list\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(\n \"Use --skill <name> to import a specific skill, or --all to import all.\",\n );\n return;\n }\n\n // Determine which skills to import\n let skillsToImport: string[] = [];\n\n if (flags.all) {\n skillsToImport = availableSkills;\n } else if (flags.skill) {\n // Validate the skill exists\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 // Destination directory\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 // Import skills\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 // Check if already exists\n if (await directoryExists(destPath)) {\n if (!flags.force) {\n this.warn(\n `Skipping '${skillName}': already exists. Use --force to overwrite.`,\n );\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(\n `Import complete: ${imported} imported, ${skipped} skipped`,\n );\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 /**\n * Discover valid skills in a directory.\n * A valid skill must have a SKILL.md file.\n */\n private async discoverValidSkills(\n skillsDir: string,\n skillDirs: string[],\n ): 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 /**\n * Import a single skill to the destination directory.\n */\n private async importSkill(\n sourcePath: string,\n destPath: string,\n skillName: string,\n source: string,\n ): Promise<void> {\n // Validate SKILL.md exists\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 // Generate content hash from SKILL.md\n const contentHash = await hashFile(skillMdPath);\n\n // Copy the entire skill directory\n await ensureDir(path.dirname(destPath));\n await copy(sourcePath, destPath);\n\n // Inject forked_from metadata\n await this.injectForkedFromMetadata(\n destPath,\n skillName,\n source,\n contentHash,\n );\n }\n\n /**\n * Inject forked_from metadata into the skill's metadata file.\n * Creates metadata.yaml if it doesn't exist.\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: ForkedFromMetadata = {\n source,\n skill_name: skillName,\n content_hash: contentHash,\n date: getCurrentDate(),\n };\n\n // Try to update existing metadata.yaml\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 metadata = parseYaml(yamlContent) as SkillMetadata;\n metadata.forked_from = forkedFrom;\n\n const newYamlContent = stringifyYaml(metadata, { lineWidth: 0 });\n await writeFile(metadataYamlPath, schemaComment + newYamlContent);\n return;\n }\n\n // Try to update existing metadata.json and convert to YAML\n if (await fileExists(metadataJsonPath)) {\n const rawContent = await readFile(metadataJsonPath);\n const metadata = JSON.parse(rawContent) as SkillMetadata;\n metadata.forked_from = forkedFrom;\n\n // Create metadata.yaml with converted content\n const yamlContent = stringifyYaml(metadata, { lineWidth: 0 });\n await writeFile(metadataYamlPath, yamlContent);\n return;\n }\n\n // Create minimal metadata.yaml if neither exists\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":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA,SAAS,MAAM,aAAa;AAC5B,OAAO,UAAU;AACjB,SAAS,SAAS,WAAW,aAAa,qBAAqB;AA+B/D,IAAM,gBAAgB;AACtB,IAAM,qBAAqB;AAC3B,IAAM,qBAAqB;AAC3B,IAAM,wBAAwB;AAW9B,SAAS,kBAAkB,QAGzB;AAEA,MAAI,OAAO,WAAW,qBAAqB,GAAG;AAC5C,UAAMA,QAAO,OAAO,QAAQ,uBAAuB,EAAE;AACrD,WAAO;AAAA,MACL,aAAa,UAAUA,KAAI;AAAA,MAC3B,eAAe;AAAA,IACjB;AAAA,EACF;AAGA,MAAI,OAAO,WAAW,SAAS,KAAK,OAAO,WAAW,KAAK,GAAG;AAC5D,UAAM,aAAa,OAAO,QAAQ,QAAQ,SAAS;AACnD,WAAO;AAAA,MACL,aAAa;AAAA,MACb,eAAe,sBAAsB,WAAW,QAAQ,WAAW,EAAE,CAAC;AAAA,IACxE;AAAA,EACF;AAGA,MAAI,OAAO,SAAS,GAAG,KAAK,CAAC,OAAO,SAAS,GAAG,GAAG;AACjD,WAAO;AAAA,MACL,aAAa,UAAU,MAAM;AAAA,MAC7B,eAAe,sBAAsB,MAAM;AAAA,IAC7C;AAAA,EACF;AAGA,SAAO;AAAA,IACL,aAAa;AAAA,IACb,eAAe;AAAA,EACjB;AACF;AAEA,SAAS,iBAAyB;AAChC,UAAO,oBAAI,KAAK,GAAE,YAAY,EAAE,MAAM,GAAG,EAAE,CAAC;AAC9C;AAEA,IAAqB,cAArB,MAAqB,qBAAoB,YAAY;AAAA,EACnD,OAAO,UAAU;AAAA,EACjB,OAAO,cACL;AAAA,EAGF,OAAO,WAAW;AAAA,IAChB;AAAA,MACE,aAAa;AAAA,MACb,SACE;AAAA,IACJ;AAAA,IACA;AAAA,MACE,aAAa;AAAA,MACb,SACE;AAAA,IACJ;AAAA,IACA;AAAA,MACE,aAAa;AAAA,MACb,SACE;AAAA,IACJ;AAAA,IACA;AAAA,MACE,aAAa;AAAA,MACb,SACE;AAAA,IACJ;AAAA,EACF;AAAA,EAEA,OAAO,OAAO;AAAA,IACZ,QAAQ,KAAK,OAAO;AAAA,MAClB,aACE;AAAA,MACF,UAAU;AAAA,IACZ,CAAC;AAAA,EACH;AAAA,EAEA,OAAO,QAAQ;AAAA,IACb,GAAG,YAAY;AAAA,IACf,OAAO,MAAM,OAAO;AAAA,MAClB,MAAM;AAAA,MACN,aAAa;AAAA,MACb,UAAU;AAAA,IACZ,CAAC;AAAA,IACD,KAAK,MAAM,QAAQ;AAAA,MACjB,MAAM;AAAA,MACN,aAAa;AAAA,MACb,SAAS;AAAA,IACX,CAAC;AAAA,IACD,MAAM,MAAM,QAAQ;AAAA,MAClB,MAAM;AAAA,MACN,aAAa;AAAA,MACb,SAAS;AAAA,IACX,CAAC;AAAA,IACD,QAAQ,MAAM,OAAO;AAAA,MACnB,aAAa;AAAA,MACb,SAAS;AAAA,IACX,CAAC;AAAA,IACD,OAAO,MAAM,QAAQ;AAAA,MACnB,MAAM;AAAA,MACN,aAAa;AAAA,MACb,SAAS;AAAA,IACX,CAAC;AAAA,IACD,SAAS,MAAM,QAAQ;AAAA,MACrB,aAAa;AAAA,MACb,SAAS;AAAA,IACX,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,MAAqB;AACzB,UAAM,EAAE,MAAM,MAAM,IAAI,MAAM,KAAK,MAAM,YAAW;AACpD,UAAM,aAAa,QAAQ,IAAI;AAE/B,SAAK,IAAI,EAAE;AACX,SAAK,IAAI,0BAA0B;AACnC,SAAK,IAAI,EAAE;AAGX,QAAI,CAAC,MAAM,QAAQ,CAAC,MAAM,SAAS,CAAC,MAAM,KAAK;AAC7C,WAAK;AAAA,QACH;AAAA,QACA,EAAE,MAAM,WAAW,aAAa;AAAA,MAClC;AAAA,IACF;AAEA,QAAI,MAAM,SAAS,MAAM,KAAK;AAC5B,WAAK,MAAM,yCAAyC;AAAA,QAClD,MAAM,WAAW;AAAA,MACnB,CAAC;AAAA,IACH;AAGA,UAAM,EAAE,aAAa,cAAc,IAAI,kBAAkB,KAAK,MAAM;AACpE,SAAK,IAAI,WAAW,aAAa,EAAE;AAGnC,SAAK,IAAI,wBAAwB;AAEjC,QAAI;AACJ,QAAI;AACF,YAAM,SAAS,MAAM,gBAAgB,aAAa;AAAA,QAChD,cAAc,MAAM;AAAA,MACtB,CAAC;AACD,iBAAW,OAAO;AAClB,WAAK;AAAA,QACH,OAAO,YAAY,wBAAwB;AAAA,MAC7C;AAAA,IACF,SAAS,OAAO;AACd,WAAK;AAAA,QACH,iBAAiB,QACb,MAAM,UACN,oBAAoB,KAAK,MAAM;AAAA,QACnC,EAAE,MAAM,WAAW,cAAc;AAAA,MACnC;AAAA,IACF;AAGA,UAAM,YAAY,KAAK,KAAK,UAAU,MAAM,MAAM;AAClD,QAAI,CAAE,MAAM,gBAAgB,SAAS,GAAI;AACvC,WAAK;AAAA,QACH,+BAA+B,MAAM,MAAM;AAAA,iCACP,MAAM,MAAM;AAAA;AAAA,QAEhD,EAAE,MAAM,WAAW,aAAa;AAAA,MAClC;AAAA,IACF;AAGA,UAAM,YAAY,MAAM,gBAAgB,SAAS;AACjD,UAAM,kBAAkB,MAAM,KAAK;AAAA,MACjC;AAAA,MACA;AAAA,IACF;AAEA,QAAI,gBAAgB,WAAW,GAAG;AAChC,WAAK;AAAA,QACH,4BAA4B,MAAM,MAAM;AAAA;AAAA,QAExC,EAAE,MAAM,WAAW,MAAM;AAAA,MAC3B;AAAA,IACF;AAGA,QAAI,MAAM,MAAM;AACd,WAAK,IAAI,EAAE;AACX,WAAK,IAAI,qBAAqB,gBAAgB,MAAM,IAAI;AACxD,WAAK,IAAI,EAAE;AACX,iBAAW,SAAS,iBAAiB;AACnC,aAAK,IAAI,OAAO,KAAK,EAAE;AAAA,MACzB;AACA,WAAK,IAAI,EAAE;AACX,WAAK;AAAA,QACH;AAAA,MACF;AACA;AAAA,IACF;AAGA,QAAI,iBAA2B,CAAC;AAEhC,QAAI,MAAM,KAAK;AACb,uBAAiB;AAAA,IACnB,WAAW,MAAM,OAAO;AAEtB,UAAI,CAAC,gBAAgB,SAAS,MAAM,KAAK,GAAG;AAC1C,aAAK;AAAA,UACH,UAAU,MAAM,KAAK;AAAA,oBACE,gBAAgB,KAAK,IAAI,CAAC;AAAA;AAAA,UAEjD,EAAE,MAAM,WAAW,aAAa;AAAA,QAClC;AAAA,MACF;AACA,uBAAiB,CAAC,MAAM,KAAK;AAAA,IAC/B;AAGA,UAAM,UAAU,KAAK,KAAK,YAAY,iBAAiB;AAEvD,QAAI,MAAM,SAAS,GAAG;AACpB,WAAK,IAAI,EAAE;AACX,WAAK,IAAI,8CAA8C;AACvD,iBAAW,SAAS,gBAAgB;AAClC,cAAM,WAAW,KAAK,KAAK,SAAS,KAAK;AACzC,cAAM,SAAS,MAAM,gBAAgB,QAAQ;AAC7C,aAAK,IAAI,OAAO,KAAK,OAAO,QAAQ,GAAG,SAAS,cAAc,EAAE,EAAE;AAAA,MACpE;AACA;AAAA,IACF;AAGA,SAAK,IAAI,EAAE;AACX,SAAK,IAAI,aAAa,eAAe,MAAM,cAAc;AAEzD,QAAI,WAAW;AACf,QAAI,UAAU;AAEd,eAAW,aAAa,gBAAgB;AACtC,YAAM,aAAa,KAAK,KAAK,WAAW,SAAS;AACjD,YAAM,WAAW,KAAK,KAAK,SAAS,SAAS;AAG7C,UAAI,MAAM,gBAAgB,QAAQ,GAAG;AACnC,YAAI,CAAC,MAAM,OAAO;AAChB,eAAK;AAAA,YACH,aAAa,SAAS;AAAA,UACxB;AACA;AACA;AAAA,QACF;AAAA,MACF;AAEA,UAAI;AACF,cAAM,KAAK,YAAY,YAAY,UAAU,WAAW,aAAa;AACrE,aAAK,WAAW,aAAa,SAAS,EAAE;AACxC;AAAA,MACF,SAAS,OAAO;AACd,aAAK;AAAA,UACH,qBAAqB,SAAS,MAAM,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC;AAAA,QAC5F;AACA;AAAA,MACF;AAAA,IACF;AAEA,SAAK,IAAI,EAAE;AACX,SAAK;AAAA,MACH,oBAAoB,QAAQ,cAAc,OAAO;AAAA,IACnD;AACA,SAAK,IAAI,oBAAoB,OAAO,EAAE;AACtC,SAAK,IAAI,EAAE;AACX,SAAK,IAAI,6DAA6D;AACtE,SAAK,IAAI,EAAE;AAAA,EACb;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAc,oBACZ,WACA,WACmB;AACnB,UAAM,cAAwB,CAAC;AAE/B,eAAW,YAAY,WAAW;AAChC,YAAM,cAAc,KAAK,KAAK,WAAW,UAAU,aAAa;AAChE,UAAI,MAAM,WAAW,WAAW,GAAG;AACjC,oBAAY,KAAK,QAAQ;AAAA,MAC3B;AAAA,IACF;AAEA,WAAO,YAAY,KAAK;AAAA,EAC1B;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,YACZ,YACA,UACA,WACA,QACe;AAEf,UAAM,cAAc,KAAK,KAAK,YAAY,aAAa;AACvD,QAAI,CAAE,MAAM,WAAW,WAAW,GAAI;AACpC,YAAM,IAAI,MAAM,gCAAgC;AAAA,IAClD;AAGA,UAAM,cAAc,MAAM,SAAS,WAAW;AAG9C,UAAM,UAAU,KAAK,QAAQ,QAAQ,CAAC;AACtC,UAAM,KAAK,YAAY,QAAQ;AAG/B,UAAM,KAAK;AAAA,MACT;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAc,yBACZ,UACA,WACA,QACA,aACe;AACf,UAAM,mBAAmB,KAAK,KAAK,UAAU,kBAAkB;AAC/D,UAAM,mBAAmB,KAAK,KAAK,UAAU,kBAAkB;AAE/D,UAAM,aAAiC;AAAA,MACrC;AAAA,MACA,YAAY;AAAA,MACZ,cAAc;AAAA,MACd,MAAM,eAAe;AAAA,IACvB;AAGA,QAAI,MAAM,WAAW,gBAAgB,GAAG;AACtC,YAAM,aAAa,MAAM,SAAS,gBAAgB;AAClD,YAAM,QAAQ,WAAW,MAAM,IAAI;AACnC,UAAIC,eAAc;AAClB,UAAI,gBAAgB;AAEpB,UAAI,MAAM,CAAC,GAAG,WAAW,yBAAyB,GAAG;AACnD,wBAAgB,MAAM,CAAC,IAAI;AAC3B,QAAAA,eAAc,MAAM,MAAM,CAAC,EAAE,KAAK,IAAI;AAAA,MACxC;AAEA,YAAM,WAAW,UAAUA,YAAW;AACtC,eAAS,cAAc;AAEvB,YAAM,iBAAiB,cAAc,UAAU,EAAE,WAAW,EAAE,CAAC;AAC/D,YAAM,UAAU,kBAAkB,gBAAgB,cAAc;AAChE;AAAA,IACF;AAGA,QAAI,MAAM,WAAW,gBAAgB,GAAG;AACtC,YAAM,aAAa,MAAM,SAAS,gBAAgB;AAClD,YAAM,WAAW,KAAK,MAAM,UAAU;AACtC,eAAS,cAAc;AAGvB,YAAMA,eAAc,cAAc,UAAU,EAAE,WAAW,EAAE,CAAC;AAC5D,YAAM,UAAU,kBAAkBA,YAAW;AAC7C;AAAA,IACF;AAGA,UAAM,kBAAiC;AAAA,MACrC,UAAU,UACP,MAAM,GAAG,EACT,IAAI,CAAC,SAAS,KAAK,OAAO,CAAC,EAAE,YAAY,IAAI,KAAK,MAAM,CAAC,CAAC,EAC1D,KAAK,GAAG;AAAA,MACX,iBAAiB;AAAA,MACjB,UAAU;AAAA,MACV,oBAAoB;AAAA,MACpB,QAAQ;AAAA,MACR,aAAa;AAAA,IACf;AAEA,UAAM,cAAc,cAAc,iBAAiB,EAAE,WAAW,EAAE,CAAC;AACnE,UAAM,UAAU,kBAAkB,WAAW;AAAA,EAC/C;AACF;","names":["path","yamlContent"]}
|
package/dist/commands/info.js
CHANGED
|
@@ -2,24 +2,24 @@
|
|
|
2
2
|
import {
|
|
3
3
|
discoverLocalSkills,
|
|
4
4
|
loadSkillsMatrixFromSource
|
|
5
|
-
} from "../chunk-
|
|
6
|
-
import "../chunk-
|
|
7
|
-
import "../chunk-
|
|
8
|
-
import "../chunk-QESUUPOE.js";
|
|
9
|
-
import "../chunk-SJYG4EJZ.js";
|
|
5
|
+
} from "../chunk-CPZOTVCI.js";
|
|
6
|
+
import "../chunk-B7CCVP6Q.js";
|
|
7
|
+
import "../chunk-IMDW5ZUP.js";
|
|
10
8
|
import {
|
|
11
9
|
BaseCommand
|
|
12
|
-
} from "../chunk-
|
|
13
|
-
import "../chunk-
|
|
10
|
+
} from "../chunk-EHS3TWWP.js";
|
|
11
|
+
import "../chunk-V46GGCCI.js";
|
|
12
|
+
import "../chunk-3U3R4NCG.js";
|
|
14
13
|
import {
|
|
15
14
|
fileExists,
|
|
16
15
|
readFile
|
|
17
|
-
} from "../chunk-
|
|
16
|
+
} from "../chunk-TKFPKEV3.js";
|
|
17
|
+
import "../chunk-76DWXGQE.js";
|
|
18
18
|
import {
|
|
19
19
|
init_esm_shims
|
|
20
20
|
} from "../chunk-DHET7RCE.js";
|
|
21
21
|
|
|
22
|
-
// src/cli
|
|
22
|
+
// src/cli/commands/info.ts
|
|
23
23
|
init_esm_shims();
|
|
24
24
|
import { Args, Flags } from "@oclif/core";
|
|
25
25
|
import path from "path";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/cli-v2/commands/info.ts"],"sourcesContent":["import { Args, Flags } from \"@oclif/core\";\nimport path from \"path\";\nimport { BaseCommand } from \"../base-command.js\";\nimport { loadSkillsMatrixFromSource } from \"../lib/source-loader.js\";\nimport { discoverLocalSkills } from \"../lib/local-skill-loader.js\";\nimport { fileExists, readFile } from \"../utils/fs.js\";\nimport type {\n ResolvedSkill,\n SkillRelation,\n SkillRequirement,\n} from \"../types-matrix.js\";\n\n/**\n * Maximum number of lines to show in content preview\n */\nconst CONTENT_PREVIEW_LINES = 10;\n\n/**\n * Maximum line length before truncation\n */\nconst MAX_LINE_LENGTH = 80;\n\n/**\n * Maximum number of suggestions to show when skill not found\n */\nconst MAX_SUGGESTIONS = 5;\n\n/**\n * Strip frontmatter from SKILL.md content and return body\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\n/**\n * Get first N non-empty lines from content\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 // Include non-empty lines or blank lines after content has started\n if (line.trim() || result.length > 0) {\n const truncated =\n line.length > MAX_LINE_LENGTH\n ? line.slice(0, MAX_LINE_LENGTH - 3) + \"...\"\n : line;\n result.push(truncated);\n }\n }\n\n return result;\n}\n\n/**\n * Format an array of skill relations for display\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\n/**\n * Format an array of skill requirements for display\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\n/**\n * Format tags array for display\n */\nfunction formatTags(tags: string[]): string {\n if (tags.length === 0) {\n return \"(none)\";\n }\n return tags.join(\", \");\n}\n\n/**\n * Find skills that match a partial query for suggestions\n */\nfunction findSuggestions(\n skills: Record<string, 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 (matches.length >= maxSuggestions) break;\n if (\n skill.id.toLowerCase().includes(lowerQuery) ||\n skill.alias?.toLowerCase().includes(lowerQuery) ||\n skill.name.toLowerCase().includes(lowerQuery)\n ) {\n matches.push(skill.id);\n }\n }\n\n return matches;\n}\n\n/**\n * Format skill info for display\n */\nfunction formatSkillInfo(skill: ResolvedSkill, isInstalled: boolean): string {\n const lines: string[] = [];\n\n lines.push(`Skill: ${skill.id}`);\n if (skill.alias) {\n lines.push(`Alias: ${skill.alias}`);\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 // Look up skill by ID or alias\n let skill: ResolvedSkill | undefined = matrix.skills[args.skill];\n\n if (!skill) {\n // Try alias lookup\n const fullId = matrix.aliases[args.skill];\n if (fullId) {\n skill = matrix.skills[fullId];\n }\n }\n\n if (!skill) {\n // Skill not found - show error with suggestions\n const suggestions = findSuggestions(\n matrix.skills,\n args.skill,\n MAX_SUGGESTIONS,\n );\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(1);\n }\n\n // Check local installation status\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 // Display skill info\n this.log(\"\");\n this.log(formatSkillInfo(skill, isInstalled));\n\n // Show content preview if enabled\n if (flags.preview) {\n // Determine source path for SKILL.md\n let skillMdPath: string;\n\n if (skill.local && skill.localPath) {\n // Local skill - path is relative to cwd\n skillMdPath = path.join(process.cwd(), skill.localPath, \"SKILL.md\");\n } else {\n // Remote skill - path is relative to source\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(\n `--- Content Preview (first ${CONTENT_PREVIEW_LINES} lines) ---`,\n );\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/source-loader.js\";\nimport { discoverLocalSkills } from \"../lib/local-skill-loader.js\";\nimport { fileExists, readFile } from \"../utils/fs.js\";\nimport type {\n ResolvedSkill,\n SkillRelation,\n SkillRequirement,\n} from \"../types-matrix.js\";\n\n/**\n * Maximum number of lines to show in content preview\n */\nconst CONTENT_PREVIEW_LINES = 10;\n\n/**\n * Maximum line length before truncation\n */\nconst MAX_LINE_LENGTH = 80;\n\n/**\n * Maximum number of suggestions to show when skill not found\n */\nconst MAX_SUGGESTIONS = 5;\n\n/**\n * Strip frontmatter from SKILL.md content and return body\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\n/**\n * Get first N non-empty lines from content\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 // Include non-empty lines or blank lines after content has started\n if (line.trim() || result.length > 0) {\n const truncated =\n line.length > MAX_LINE_LENGTH\n ? line.slice(0, MAX_LINE_LENGTH - 3) + \"...\"\n : line;\n result.push(truncated);\n }\n }\n\n return result;\n}\n\n/**\n * Format an array of skill relations for display\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\n/**\n * Format an array of skill requirements for display\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\n/**\n * Format tags array for display\n */\nfunction formatTags(tags: string[]): string {\n if (tags.length === 0) {\n return \"(none)\";\n }\n return tags.join(\", \");\n}\n\n/**\n * Find skills that match a partial query for suggestions\n */\nfunction findSuggestions(\n skills: Record<string, 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 (matches.length >= maxSuggestions) break;\n if (\n skill.id.toLowerCase().includes(lowerQuery) ||\n skill.alias?.toLowerCase().includes(lowerQuery) ||\n skill.name.toLowerCase().includes(lowerQuery)\n ) {\n matches.push(skill.id);\n }\n }\n\n return matches;\n}\n\n/**\n * Format skill info for display\n */\nfunction formatSkillInfo(skill: ResolvedSkill, isInstalled: boolean): string {\n const lines: string[] = [];\n\n lines.push(`Skill: ${skill.id}`);\n if (skill.alias) {\n lines.push(`Alias: ${skill.alias}`);\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 // Look up skill by ID or alias\n let skill: ResolvedSkill | undefined = matrix.skills[args.skill];\n\n if (!skill) {\n // Try alias lookup\n const fullId = matrix.aliases[args.skill];\n if (fullId) {\n skill = matrix.skills[fullId];\n }\n }\n\n if (!skill) {\n // Skill not found - show error with suggestions\n const suggestions = findSuggestions(\n matrix.skills,\n args.skill,\n MAX_SUGGESTIONS,\n );\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(1);\n }\n\n // Check local installation status\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 // Display skill info\n this.log(\"\");\n this.log(formatSkillInfo(skill, isInstalled));\n\n // Show content preview if enabled\n if (flags.preview) {\n // Determine source path for SKILL.md\n let skillMdPath: string;\n\n if (skill.local && skill.localPath) {\n // Local skill - path is relative to cwd\n skillMdPath = path.join(process.cwd(), skill.localPath, \"SKILL.md\");\n } else {\n // Remote skill - path is relative to source\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(\n `--- Content Preview (first ${CONTENT_PREVIEW_LINES} lines) ---`,\n );\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":[]}
|