ccski 1.1.0 → 2.0.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/README.md +48 -94
- package/dist/chunk-B7onSSqq.mjs +34 -0
- package/dist/cli.mjs +1648 -3551
- package/dist/cli.mjs.map +1 -1
- package/dist/create-prompt-CkW5qmPT.mjs +3107 -0
- package/dist/create-prompt-CkW5qmPT.mjs.map +1 -0
- package/dist/esm-X74pBEPN.mjs +47 -0
- package/dist/esm-X74pBEPN.mjs.map +1 -0
- package/dist/index.d.mts +23 -8
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +2 -2
- package/dist/{registry-DtGaEhsM.mjs → registry-Do2Htns7.mjs} +325 -134
- package/dist/registry-Do2Htns7.mjs.map +1 -0
- package/package.json +8 -3
- package/dist/registry-DtGaEhsM.mjs.map +0 -1
|
@@ -1,41 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { n as __require, r as __toESM, t as __commonJS } from "./chunk-B7onSSqq.mjs";
|
|
2
2
|
import { existsSync, readFileSync, readdirSync } from "node:fs";
|
|
3
3
|
import { TextDecoder } from "node:util";
|
|
4
4
|
import { homedir } from "node:os";
|
|
5
|
-
import { dirname, isAbsolute, join, resolve } from "node:path";
|
|
5
|
+
import { dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
|
|
6
6
|
import * as tty from "tty";
|
|
7
|
+
import debug from "debug";
|
|
7
8
|
|
|
8
|
-
//#region rolldown:runtime
|
|
9
|
-
var __create = Object.create;
|
|
10
|
-
var __defProp = Object.defineProperty;
|
|
11
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
12
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
13
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
14
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
15
|
-
var __commonJS = (cb, mod) => function() {
|
|
16
|
-
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
17
|
-
};
|
|
18
|
-
var __copyProps = (to, from, except, desc) => {
|
|
19
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
20
|
-
for (var keys = __getOwnPropNames(from), i$1 = 0, n = keys.length, key; i$1 < n; i$1++) {
|
|
21
|
-
key = keys[i$1];
|
|
22
|
-
if (!__hasOwnProp.call(to, key) && key !== except) {
|
|
23
|
-
__defProp(to, key, {
|
|
24
|
-
get: ((k) => from[k]).bind(null, key),
|
|
25
|
-
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
26
|
-
});
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
return to;
|
|
31
|
-
};
|
|
32
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
|
|
33
|
-
value: mod,
|
|
34
|
-
enumerable: true
|
|
35
|
-
}) : target, mod));
|
|
36
|
-
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
37
|
-
|
|
38
|
-
//#endregion
|
|
39
9
|
//#region src/types/errors.ts
|
|
40
10
|
/**
|
|
41
11
|
* Base error class for ccski errors
|
|
@@ -62,8 +32,8 @@ var SkillNotFoundError = class extends CcskiError {
|
|
|
62
32
|
* Error thrown when a skill name is ambiguous
|
|
63
33
|
*/
|
|
64
34
|
var AmbiguousSkillNameError = class extends CcskiError {
|
|
65
|
-
constructor(skillName, matches) {
|
|
66
|
-
super(`Skill name '${skillName}' is ambiguous. Multiple skills found: ${matches.join(", ")}
|
|
35
|
+
constructor(skillName, matches, suggestions = []) {
|
|
36
|
+
super(`Skill name '${skillName}' is ambiguous. Multiple skills found: ${matches.join(", ")}`, suggestions.length ? suggestions : matches);
|
|
67
37
|
this.skillName = skillName;
|
|
68
38
|
this.matches = matches;
|
|
69
39
|
this.name = "AmbiguousSkillNameError";
|
|
@@ -11699,9 +11669,9 @@ var require_excerpt = /* @__PURE__ */ __commonJS({ "node_modules/.pnpm/gray-matt
|
|
|
11699
11669
|
const opts = defaults$2(options);
|
|
11700
11670
|
if (file.data == null) file.data = {};
|
|
11701
11671
|
if (typeof opts.excerpt === "function") return opts.excerpt(file, opts);
|
|
11702
|
-
const sep = file.data.excerpt_separator || opts.excerpt_separator;
|
|
11703
|
-
if (sep == null && (opts.excerpt === false || opts.excerpt == null)) return file;
|
|
11704
|
-
const delimiter = typeof opts.excerpt === "string" ? opts.excerpt : sep || opts.delimiters[0];
|
|
11672
|
+
const sep$1 = file.data.excerpt_separator || opts.excerpt_separator;
|
|
11673
|
+
if (sep$1 == null && (opts.excerpt === false || opts.excerpt == null)) return file;
|
|
11674
|
+
const delimiter = typeof opts.excerpt === "string" ? opts.excerpt : sep$1 || opts.delimiters[0];
|
|
11705
11675
|
const idx = file.content.indexOf(delimiter);
|
|
11706
11676
|
if (idx !== -1) file.excerpt = file.content.slice(0, idx);
|
|
11707
11677
|
return file;
|
|
@@ -12323,9 +12293,37 @@ function error(text) {
|
|
|
12323
12293
|
function warn(text) {
|
|
12324
12294
|
return tone.warning(text);
|
|
12325
12295
|
}
|
|
12296
|
+
function info(text) {
|
|
12297
|
+
return tone.info(text);
|
|
12298
|
+
}
|
|
12326
12299
|
function heading(text) {
|
|
12327
12300
|
return tone.underline(tone.bold(tone.accent(text)));
|
|
12328
12301
|
}
|
|
12302
|
+
const SUPERSCRIPT_DIGITS = [
|
|
12303
|
+
"⁰",
|
|
12304
|
+
"¹",
|
|
12305
|
+
"²",
|
|
12306
|
+
"³",
|
|
12307
|
+
"⁴",
|
|
12308
|
+
"⁵",
|
|
12309
|
+
"⁶",
|
|
12310
|
+
"⁷",
|
|
12311
|
+
"⁸",
|
|
12312
|
+
"⁹"
|
|
12313
|
+
];
|
|
12314
|
+
function toSuperscript(num) {
|
|
12315
|
+
return num.toString().split("").map((d) => SUPERSCRIPT_DIGITS[parseInt(d, 10)] ?? d).join("");
|
|
12316
|
+
}
|
|
12317
|
+
/**
|
|
12318
|
+
* Create a duplicate badge with superscript number.
|
|
12319
|
+
* isPrimary: the chosen skill in auto mode (shows just the number)
|
|
12320
|
+
* !isPrimary: the duplicate that was filtered out (shows [dup] + number)
|
|
12321
|
+
*/
|
|
12322
|
+
function duplicateBadge(groupIndex, isPrimary) {
|
|
12323
|
+
const sup = toSuperscript(groupIndex);
|
|
12324
|
+
if (isPrimary) return tone.accent(sup);
|
|
12325
|
+
return tone.accent(`[dup]${sup}`);
|
|
12326
|
+
}
|
|
12329
12327
|
function escapeRegExp$1(value) {
|
|
12330
12328
|
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
12331
12329
|
}
|
|
@@ -12375,15 +12373,34 @@ function displayWidth(value) {
|
|
|
12375
12373
|
|
|
12376
12374
|
//#endregion
|
|
12377
12375
|
//#region src/core/discovery.ts
|
|
12378
|
-
|
|
12379
|
-
|
|
12380
|
-
|
|
12381
|
-
|
|
12382
|
-
|
|
12383
|
-
|
|
12384
|
-
|
|
12385
|
-
|
|
12386
|
-
|
|
12376
|
+
function getDefaultSkillDirectories(userDir) {
|
|
12377
|
+
return [
|
|
12378
|
+
{
|
|
12379
|
+
path: ".agent/skills",
|
|
12380
|
+
provider: "claude"
|
|
12381
|
+
},
|
|
12382
|
+
{
|
|
12383
|
+
path: ".claude/skills",
|
|
12384
|
+
provider: "claude"
|
|
12385
|
+
},
|
|
12386
|
+
{
|
|
12387
|
+
path: join(userDir, ".agent/skills"),
|
|
12388
|
+
provider: "claude"
|
|
12389
|
+
},
|
|
12390
|
+
{
|
|
12391
|
+
path: join(userDir, ".claude/skills"),
|
|
12392
|
+
provider: "claude"
|
|
12393
|
+
},
|
|
12394
|
+
{
|
|
12395
|
+
path: ".codex/skills",
|
|
12396
|
+
provider: "codex"
|
|
12397
|
+
},
|
|
12398
|
+
{
|
|
12399
|
+
path: join(userDir, ".codex/skills"),
|
|
12400
|
+
provider: "codex"
|
|
12401
|
+
}
|
|
12402
|
+
];
|
|
12403
|
+
}
|
|
12387
12404
|
/**
|
|
12388
12405
|
* Check if a directory has bundled resources
|
|
12389
12406
|
*/
|
|
@@ -12397,12 +12414,12 @@ function checkBundledResources(skillDir) {
|
|
|
12397
12414
|
/**
|
|
12398
12415
|
* Determine skill location type based on directory path
|
|
12399
12416
|
*/
|
|
12400
|
-
function determineLocation(dirPath) {
|
|
12417
|
+
function determineLocation(dirPath, userDir) {
|
|
12401
12418
|
const normalizedPath = resolve(dirPath);
|
|
12402
12419
|
const cwd = process.cwd();
|
|
12403
|
-
const home =
|
|
12404
|
-
if (normalizedPath.startsWith(join(cwd, ".agent")) || normalizedPath.startsWith(join(cwd, ".claude"))) return "project";
|
|
12405
|
-
if (normalizedPath.startsWith(join(home, ".agent")) || normalizedPath.startsWith(join(home, ".claude"))) return "user";
|
|
12420
|
+
const home = userDir;
|
|
12421
|
+
if (normalizedPath.startsWith(join(cwd, ".agent")) || normalizedPath.startsWith(join(cwd, ".claude")) || normalizedPath.startsWith(join(cwd, ".codex"))) return "project";
|
|
12422
|
+
if (normalizedPath.startsWith(join(home, ".agent")) || normalizedPath.startsWith(join(home, ".claude")) || normalizedPath.startsWith(join(home, ".codex"))) return "user";
|
|
12406
12423
|
return "user";
|
|
12407
12424
|
}
|
|
12408
12425
|
function collectSkillDirectories(root, recursive, diagnostics, accumulator, includeDisabled) {
|
|
@@ -12428,7 +12445,7 @@ function collectSkillDirectories(root, recursive, diagnostics, accumulator, incl
|
|
|
12428
12445
|
/**
|
|
12429
12446
|
* Scan a single skill directory and return found skills
|
|
12430
12447
|
*/
|
|
12431
|
-
function scanSkillDirectory(dirPath, { location, recursive = true, diagnostics, includeDisabled = false }) {
|
|
12448
|
+
function scanSkillDirectory(dirPath, { location, recursive = true, diagnostics, includeDisabled = false }, provider, userDir = homedir(), scope) {
|
|
12432
12449
|
const skills = [];
|
|
12433
12450
|
const skillDirectories = /* @__PURE__ */ new Set();
|
|
12434
12451
|
collectSkillDirectories(dirPath, recursive, diagnostics, skillDirectories, includeDisabled);
|
|
@@ -12450,16 +12467,20 @@ function scanSkillDirectory(dirPath, { location, recursive = true, diagnostics,
|
|
|
12450
12467
|
if (candidates.length === 0) continue;
|
|
12451
12468
|
for (const candidate of candidates) try {
|
|
12452
12469
|
const parsed = parseSkillFile(candidate.path);
|
|
12470
|
+
const baseName = parsed.frontmatter.name;
|
|
12471
|
+
const scopedName = scope && !baseName.includes(":") ? `${scope}:${baseName}` : baseName;
|
|
12453
12472
|
const resources = checkBundledResources(skillDir);
|
|
12454
|
-
const skillLocation = location ?? determineLocation(skillDir);
|
|
12473
|
+
const skillLocation = location ?? determineLocation(skillDir, userDir);
|
|
12455
12474
|
skills.push({
|
|
12456
|
-
name:
|
|
12475
|
+
name: scopedName,
|
|
12457
12476
|
description: parsed.frontmatter.description,
|
|
12477
|
+
provider,
|
|
12458
12478
|
location: skillLocation,
|
|
12459
12479
|
path: skillDir,
|
|
12460
12480
|
disabled: candidate.disabled,
|
|
12461
12481
|
...resources
|
|
12462
12482
|
});
|
|
12483
|
+
diagnostics.byProvider[provider] = (diagnostics.byProvider[provider] ?? 0) + 1;
|
|
12463
12484
|
} catch (error$1) {
|
|
12464
12485
|
console.warn(colors.yellow(`Warning: Failed to parse ${candidate.path}: ${error$1 instanceof Error ? error$1.message : String(error$1)}`));
|
|
12465
12486
|
diagnostics.warnings.push(`Failed to parse ${candidate.path}: ${error$1 instanceof Error ? error$1.message : String(error$1)}`);
|
|
@@ -12474,26 +12495,46 @@ function discoverSkills(options = {}) {
|
|
|
12474
12495
|
const diagnostics = {
|
|
12475
12496
|
scannedDirectories: [],
|
|
12476
12497
|
warnings: [],
|
|
12477
|
-
conflicts: []
|
|
12498
|
+
conflicts: [],
|
|
12499
|
+
byProvider: {
|
|
12500
|
+
claude: 0,
|
|
12501
|
+
codex: 0,
|
|
12502
|
+
file: 0
|
|
12503
|
+
}
|
|
12478
12504
|
};
|
|
12505
|
+
const userDir = options.userDir ? resolve(options.userDir) : homedir();
|
|
12479
12506
|
const directories = [];
|
|
12480
|
-
if (options.customDirs?.length)
|
|
12481
|
-
|
|
12482
|
-
|
|
12483
|
-
|
|
12484
|
-
|
|
12507
|
+
if (options.customDirs?.length) for (const entry of options.customDirs) {
|
|
12508
|
+
const provider = options.customProvider ?? "file";
|
|
12509
|
+
if (typeof entry === "string") directories.push({
|
|
12510
|
+
path: entry,
|
|
12511
|
+
provider,
|
|
12512
|
+
scope: provider === "file" ? "other" : void 0
|
|
12513
|
+
});
|
|
12514
|
+
else directories.push({
|
|
12515
|
+
path: entry.path,
|
|
12516
|
+
provider,
|
|
12517
|
+
scope: entry.scope ?? (provider === "file" ? "other" : void 0)
|
|
12518
|
+
});
|
|
12519
|
+
}
|
|
12520
|
+
if (options.scanDefaultDirs !== false) directories.push(...getDefaultSkillDirectories(userDir));
|
|
12521
|
+
const skills = [];
|
|
12522
|
+
const firstPathByName = /* @__PURE__ */ new Map();
|
|
12523
|
+
for (const entry of directories) {
|
|
12524
|
+
const { path: dir, provider, scope } = entry;
|
|
12525
|
+
const skillsFromDir = scanSkillDirectory(dir.startsWith("/") ? dir : resolve(process.cwd(), dir), {
|
|
12485
12526
|
diagnostics,
|
|
12486
12527
|
recursive: true,
|
|
12487
12528
|
includeDisabled: options.includeDisabled === true
|
|
12488
|
-
});
|
|
12489
|
-
for (const skill of
|
|
12490
|
-
|
|
12491
|
-
|
|
12492
|
-
|
|
12529
|
+
}, provider, userDir, scope);
|
|
12530
|
+
for (const skill of skillsFromDir) {
|
|
12531
|
+
if (firstPathByName.has(skill.name)) diagnostics.conflicts.push(`Duplicate skill '${skill.name}' found at ${skill.path} (first seen at ${firstPathByName.get(skill.name)})`);
|
|
12532
|
+
else firstPathByName.set(skill.name, skill.path);
|
|
12533
|
+
skills.push(skill);
|
|
12493
12534
|
}
|
|
12494
12535
|
}
|
|
12495
12536
|
return {
|
|
12496
|
-
skills
|
|
12537
|
+
skills,
|
|
12497
12538
|
diagnostics
|
|
12498
12539
|
};
|
|
12499
12540
|
}
|
|
@@ -12511,15 +12552,19 @@ function loadSkill(metadata) {
|
|
|
12511
12552
|
|
|
12512
12553
|
//#endregion
|
|
12513
12554
|
//#region src/core/plugins.ts
|
|
12514
|
-
|
|
12515
|
-
|
|
12555
|
+
function defaultPluginsFile(userDir) {
|
|
12556
|
+
return join(userDir, ".claude/plugins/installed_plugins.json");
|
|
12557
|
+
}
|
|
12558
|
+
function defaultPluginsRoot(userDir) {
|
|
12559
|
+
return join(userDir, ".claude/plugins");
|
|
12560
|
+
}
|
|
12516
12561
|
function resolveInstallPath(rawPath, pluginsRoot) {
|
|
12517
12562
|
return isAbsolute(rawPath) ? rawPath : join(pluginsRoot, rawPath);
|
|
12518
12563
|
}
|
|
12519
12564
|
/**
|
|
12520
12565
|
* Parse installed_plugins.json
|
|
12521
12566
|
*/
|
|
12522
|
-
function loadInstalledPlugins(pluginsFile
|
|
12567
|
+
function loadInstalledPlugins(pluginsFile, diagnostics) {
|
|
12523
12568
|
if (!existsSync(pluginsFile)) {
|
|
12524
12569
|
console.info(`[ccski] No plugin marketplace skills found at ${pluginsFile}`);
|
|
12525
12570
|
diagnostics?.warnings.push(`Plugins file not found at ${pluginsFile}`);
|
|
@@ -12564,31 +12609,47 @@ function findSkillFiles(dir, diagnostics) {
|
|
|
12564
12609
|
* Discover skills from installed plugins
|
|
12565
12610
|
*/
|
|
12566
12611
|
function discoverPluginSkills(options = {}) {
|
|
12612
|
+
const log = debug("ccski:plugins");
|
|
12567
12613
|
const diagnostics = {
|
|
12568
12614
|
scannedPlugins: [],
|
|
12569
12615
|
warnings: []
|
|
12570
12616
|
};
|
|
12571
|
-
const
|
|
12617
|
+
const userDir = options.userDir ? resolve(options.userDir) : homedir();
|
|
12618
|
+
const pluginsFile = options.pluginsFile ?? defaultPluginsFile(userDir);
|
|
12572
12619
|
diagnostics.scannedPlugins.push(pluginsFile);
|
|
12573
|
-
const plugins = loadInstalledPlugins(pluginsFile, diagnostics);
|
|
12574
|
-
if (!plugins) return {
|
|
12575
|
-
skills: [],
|
|
12576
|
-
diagnostics
|
|
12577
|
-
};
|
|
12578
12620
|
const skills = [];
|
|
12579
|
-
const
|
|
12580
|
-
|
|
12621
|
+
const seenPaths = /* @__PURE__ */ new Set();
|
|
12622
|
+
const pluginsRoot = options.pluginsRoot ?? defaultPluginsRoot(userDir);
|
|
12623
|
+
let missingOrEmpty = false;
|
|
12624
|
+
const plugins = loadInstalledPlugins(pluginsFile, diagnostics);
|
|
12625
|
+
log("plugins file=%s loaded=%s", pluginsFile, Boolean(plugins));
|
|
12626
|
+
if (plugins) for (const [pluginKey, plugin] of Object.entries(plugins.plugins)) {
|
|
12581
12627
|
const [pluginName, marketplace] = pluginKey.split("@");
|
|
12582
12628
|
if (!pluginName || !marketplace) continue;
|
|
12583
12629
|
const installPath = resolveInstallPath(plugin.installPath, pluginsRoot);
|
|
12584
12630
|
const skillFiles = findSkillFiles(installPath, diagnostics);
|
|
12631
|
+
if (!skillFiles.length) {
|
|
12632
|
+
if (!existsSync(installPath)) {
|
|
12633
|
+
diagnostics.warnings.push(`Plugin install path not found: ${installPath}`);
|
|
12634
|
+
log("missing installPath: %s", installPath);
|
|
12635
|
+
} else {
|
|
12636
|
+
diagnostics.warnings.push(`No skills found in plugin install path: ${installPath}`);
|
|
12637
|
+
log("empty installPath: %s", installPath);
|
|
12638
|
+
}
|
|
12639
|
+
missingOrEmpty = true;
|
|
12640
|
+
}
|
|
12585
12641
|
diagnostics.scannedPlugins.push(installPath);
|
|
12642
|
+
log("scanned manifest plugin=%s skills=%d", pluginName, skillFiles.length);
|
|
12586
12643
|
for (const skillFile of skillFiles) try {
|
|
12587
12644
|
const parsed = parseSkillFile(skillFile);
|
|
12588
12645
|
const skillDir = dirname(skillFile);
|
|
12646
|
+
if (seenPaths.has(skillDir)) continue;
|
|
12647
|
+
const skillName = parsed.frontmatter.name;
|
|
12648
|
+
const namespaced = skillName.includes(":") ? skillName : pluginName === skillName ? skillName : `${pluginName}:${skillName}`;
|
|
12589
12649
|
skills.push({
|
|
12590
|
-
name:
|
|
12650
|
+
name: namespaced,
|
|
12591
12651
|
description: parsed.frontmatter.description,
|
|
12652
|
+
provider: "claude",
|
|
12592
12653
|
location: "plugin",
|
|
12593
12654
|
path: skillDir,
|
|
12594
12655
|
hasReferences: existsSync(join(skillDir, "references")),
|
|
@@ -12600,6 +12661,48 @@ function discoverPluginSkills(options = {}) {
|
|
|
12600
12661
|
version: plugin.version
|
|
12601
12662
|
}
|
|
12602
12663
|
});
|
|
12664
|
+
seenPaths.add(skillDir);
|
|
12665
|
+
} catch (error$1) {
|
|
12666
|
+
console.warn(colors.yellow(`Warning: Failed to parse plugin skill ${skillFile}:`), error$1);
|
|
12667
|
+
diagnostics.warnings.push(`Failed to parse plugin skill ${skillFile}: ${error$1 instanceof Error ? error$1.message : String(error$1)}`);
|
|
12668
|
+
}
|
|
12669
|
+
}
|
|
12670
|
+
if (!(process.env.CCSKI_CLAUDE_PLUGINS_FALLBACK === "true")) {
|
|
12671
|
+
log("fallback scan skipped (CCSKI_CLAUDE_PLUGINS_FALLBACK!=true)");
|
|
12672
|
+
return {
|
|
12673
|
+
skills,
|
|
12674
|
+
diagnostics
|
|
12675
|
+
};
|
|
12676
|
+
}
|
|
12677
|
+
if (!plugins || skills.length === 0 || missingOrEmpty) {
|
|
12678
|
+
const fallbackRoot = join(pluginsRoot, "skills");
|
|
12679
|
+
diagnostics.scannedPlugins.push(fallbackRoot);
|
|
12680
|
+
log("running fallback scan at %s", fallbackRoot);
|
|
12681
|
+
const skillFiles = findSkillFiles(fallbackRoot, diagnostics);
|
|
12682
|
+
for (const skillFile of skillFiles) try {
|
|
12683
|
+
const parsed = parseSkillFile(skillFile);
|
|
12684
|
+
const skillDir = dirname(skillFile);
|
|
12685
|
+
if (seenPaths.has(skillDir)) continue;
|
|
12686
|
+
const pluginName = relative(fallbackRoot, skillDir).split(sep).filter(Boolean)[0] ?? "local";
|
|
12687
|
+
const skillName = parsed.frontmatter.name;
|
|
12688
|
+
const namespaced = skillName.includes(":") ? skillName : pluginName === skillName ? skillName : `${pluginName}:${skillName}`;
|
|
12689
|
+
skills.push({
|
|
12690
|
+
name: namespaced,
|
|
12691
|
+
description: parsed.frontmatter.description,
|
|
12692
|
+
provider: "claude",
|
|
12693
|
+
location: "plugin",
|
|
12694
|
+
path: skillDir,
|
|
12695
|
+
hasReferences: existsSync(join(skillDir, "references")),
|
|
12696
|
+
hasScripts: existsSync(join(skillDir, "scripts")),
|
|
12697
|
+
hasAssets: existsSync(join(skillDir, "assets")),
|
|
12698
|
+
pluginInfo: {
|
|
12699
|
+
pluginName,
|
|
12700
|
+
marketplace: "local",
|
|
12701
|
+
version: "unknown"
|
|
12702
|
+
}
|
|
12703
|
+
});
|
|
12704
|
+
seenPaths.add(skillDir);
|
|
12705
|
+
log("fallback skill added %s (%s)", namespaced, skillDir);
|
|
12603
12706
|
} catch (error$1) {
|
|
12604
12707
|
console.warn(colors.yellow(`Warning: Failed to parse plugin skill ${skillFile}:`), error$1);
|
|
12605
12708
|
diagnostics.warnings.push(`Failed to parse plugin skill ${skillFile}: ${error$1 instanceof Error ? error$1.message : String(error$1)}`);
|
|
@@ -12657,8 +12760,8 @@ var require_uFuzzy = /* @__PURE__ */ __commonJS({ "node_modules/.pnpm/@leeoniya+
|
|
|
12657
12760
|
toUpper: (str) => str.toLocaleUpperCase(),
|
|
12658
12761
|
toLower: (str) => str.toLocaleLowerCase(),
|
|
12659
12762
|
compare: null,
|
|
12660
|
-
sort: (info, haystack, needle, compare = cmp) => {
|
|
12661
|
-
let { idx, chars, terms, interLft2, interLft1, start, intraIns, interIns, cases } = info;
|
|
12763
|
+
sort: (info$1, haystack, needle, compare = cmp) => {
|
|
12764
|
+
let { idx, chars, terms, interLft2, interLft1, start, intraIns, interIns, cases } = info$1;
|
|
12662
12765
|
return idx.map((v, i$1) => i$1).sort((ia, ib) => chars[ib] - chars[ia] || intraIns[ia] - intraIns[ib] || terms[ib] + interLft2[ib] + .5 * interLft1[ib] - (terms[ia] + interLft2[ia] + .5 * interLft1[ia]) || interIns[ia] - interIns[ib] || start[ia] - start[ib] || cases[ib] - cases[ia] || compare(haystack[idx[ia]], haystack[idx[ib]]));
|
|
12663
12766
|
}
|
|
12664
12767
|
};
|
|
@@ -12806,7 +12909,7 @@ var require_uFuzzy = /* @__PURE__ */ __commonJS({ "node_modules/.pnpm/@leeoniya+
|
|
|
12806
12909
|
let withIntraBound = !!_intraBound;
|
|
12807
12910
|
let interBound = new RegExp(_interBound, uFlag);
|
|
12808
12911
|
let intraBound = new RegExp(_intraBound, uFlag);
|
|
12809
|
-
const info = (idxs, haystack, needle) => {
|
|
12912
|
+
const info$1 = (idxs, haystack, needle) => {
|
|
12810
12913
|
let [query, parts, contrs] = prepQuery(needle, 1);
|
|
12811
12914
|
let partsCased = split(needle, true);
|
|
12812
12915
|
let [queryR] = prepQuery(needle, 2);
|
|
@@ -12823,7 +12926,7 @@ var require_uFuzzy = /* @__PURE__ */ __commonJS({ "node_modules/.pnpm/@leeoniya+
|
|
|
12823
12926
|
}
|
|
12824
12927
|
let len = idxs.length;
|
|
12825
12928
|
let field = Array(len).fill(0);
|
|
12826
|
-
let info$
|
|
12929
|
+
let info$2 = {
|
|
12827
12930
|
idx: Array(len),
|
|
12828
12931
|
start: field.slice(),
|
|
12829
12932
|
chars: field.slice(),
|
|
@@ -12958,17 +13061,17 @@ var require_uFuzzy = /* @__PURE__ */ __commonJS({ "node_modules/.pnpm/@leeoniya+
|
|
|
12958
13061
|
if (j < partsLen - 1) idxAcc += groupLen + m[k + 1].length;
|
|
12959
13062
|
}
|
|
12960
13063
|
if (!disc) {
|
|
12961
|
-
info$
|
|
12962
|
-
info$
|
|
12963
|
-
info$
|
|
12964
|
-
info$
|
|
12965
|
-
info$
|
|
12966
|
-
info$
|
|
12967
|
-
info$
|
|
12968
|
-
info$
|
|
12969
|
-
info$
|
|
12970
|
-
info$
|
|
12971
|
-
info$
|
|
13064
|
+
info$2.idx[ii] = idxs[i$1];
|
|
13065
|
+
info$2.interLft2[ii] = lft2;
|
|
13066
|
+
info$2.interLft1[ii] = lft1;
|
|
13067
|
+
info$2.interRgt2[ii] = rgt2;
|
|
13068
|
+
info$2.interRgt1[ii] = rgt1;
|
|
13069
|
+
info$2.chars[ii] = chars;
|
|
13070
|
+
info$2.terms[ii] = terms;
|
|
13071
|
+
info$2.cases[ii] = cases;
|
|
13072
|
+
info$2.interIns[ii] = inter;
|
|
13073
|
+
info$2.intraIns[ii] = intra;
|
|
13074
|
+
info$2.start[ii] = start;
|
|
12972
13075
|
let m$1 = mhstr.match(queryR);
|
|
12973
13076
|
let idxAcc$1 = m$1.index + m$1[1].length;
|
|
12974
13077
|
let refLen = refine.length;
|
|
@@ -12995,7 +13098,7 @@ var require_uFuzzy = /* @__PURE__ */ __commonJS({ "node_modules/.pnpm/@leeoniya+
|
|
|
12995
13098
|
}
|
|
12996
13099
|
}
|
|
12997
13100
|
idxAcc$1 = m$1.index + m$1[1].length;
|
|
12998
|
-
let ranges = info$
|
|
13101
|
+
let ranges = info$2.ranges[ii] = [];
|
|
12999
13102
|
let from = idxAcc$1;
|
|
13000
13103
|
let to = idxAcc$1;
|
|
13001
13104
|
for (let i$2 = 2; i$2 < m$1.length; i$2++) {
|
|
@@ -13011,8 +13114,8 @@ var require_uFuzzy = /* @__PURE__ */ __commonJS({ "node_modules/.pnpm/@leeoniya+
|
|
|
13011
13114
|
ii++;
|
|
13012
13115
|
}
|
|
13013
13116
|
}
|
|
13014
|
-
if (ii < idxs.length) for (let k in info$
|
|
13015
|
-
return info$
|
|
13117
|
+
if (ii < idxs.length) for (let k in info$2) info$2[k] = info$2[k].slice(0, ii);
|
|
13118
|
+
return info$2;
|
|
13016
13119
|
};
|
|
13017
13120
|
const refineMatch = (m, k, idxInNext, termLen) => {
|
|
13018
13121
|
let prepend = m[k] + m[k + 1].slice(0, idxInNext);
|
|
@@ -13093,7 +13196,7 @@ var require_uFuzzy = /* @__PURE__ */ __commonJS({ "node_modules/.pnpm/@leeoniya+
|
|
|
13093
13196
|
let idxs = matches[ni];
|
|
13094
13197
|
if (idxs == null || idxs.length == 0) continue;
|
|
13095
13198
|
let needle$1 = needles[ni];
|
|
13096
|
-
let _info = info(idxs, haystack, needle$1);
|
|
13199
|
+
let _info = info$1(idxs, haystack, needle$1);
|
|
13097
13200
|
let order = opts.sort(_info, haystack, needle$1, compare);
|
|
13098
13201
|
if (ni > 0) for (let i$1 = 0; i$1 < order.length; i$1++) order[i$1] += retOrder.length;
|
|
13099
13202
|
for (let k in _info) retInfo[k] = (retInfo[k] ?? []).concat(_info[k]);
|
|
@@ -13112,7 +13215,7 @@ var require_uFuzzy = /* @__PURE__ */ __commonJS({ "node_modules/.pnpm/@leeoniya+
|
|
|
13112
13215
|
},
|
|
13113
13216
|
split,
|
|
13114
13217
|
filter,
|
|
13115
|
-
info,
|
|
13218
|
+
info: info$1,
|
|
13116
13219
|
sort: opts.sort
|
|
13117
13220
|
};
|
|
13118
13221
|
}
|
|
@@ -13217,18 +13320,85 @@ function containsCaseInsensitive(haystack, needle) {
|
|
|
13217
13320
|
return haystack.toLowerCase().includes(needle.toLowerCase());
|
|
13218
13321
|
}
|
|
13219
13322
|
|
|
13323
|
+
//#endregion
|
|
13324
|
+
//#region src/utils/skill-id.ts
|
|
13325
|
+
function stripPluginPrefix(name, pluginName) {
|
|
13326
|
+
const prefix = `${pluginName}:`;
|
|
13327
|
+
return name.startsWith(prefix) ? name.slice(prefix.length) : name;
|
|
13328
|
+
}
|
|
13329
|
+
const defaultFormatOptions = {
|
|
13330
|
+
includeProvider: true,
|
|
13331
|
+
color: true
|
|
13332
|
+
};
|
|
13333
|
+
/**
|
|
13334
|
+
* Build a copy/paste friendly skill id that includes provider and plugin (when present).
|
|
13335
|
+
* Format: provider:@plugin:name or provider:name
|
|
13336
|
+
*/
|
|
13337
|
+
function formatSkillId(skill, opts) {
|
|
13338
|
+
const { includeProvider } = {
|
|
13339
|
+
...defaultFormatOptions,
|
|
13340
|
+
...opts
|
|
13341
|
+
};
|
|
13342
|
+
if (skill.pluginInfo) {
|
|
13343
|
+
const base = stripPluginPrefix(skill.name, skill.pluginInfo.pluginName);
|
|
13344
|
+
const id = `@${skill.pluginInfo.pluginName}:${base}`;
|
|
13345
|
+
return includeProvider ? `${skill.provider}:${id}` : id;
|
|
13346
|
+
}
|
|
13347
|
+
return includeProvider ? `${skill.provider}:${skill.name}` : skill.name;
|
|
13348
|
+
}
|
|
13349
|
+
/**
|
|
13350
|
+
* Return a set of aliases (lowercased) that should match user input, including plugin-qualified variants.
|
|
13351
|
+
*/
|
|
13352
|
+
function skillAliases(skill) {
|
|
13353
|
+
const aliases = /* @__PURE__ */ new Set();
|
|
13354
|
+
aliases.add(skill.name.toLowerCase());
|
|
13355
|
+
const short = skill.name.toLowerCase().split(":").pop() ?? skill.name.toLowerCase();
|
|
13356
|
+
aliases.add(short);
|
|
13357
|
+
if (skill.pluginInfo) {
|
|
13358
|
+
const plugin = skill.pluginInfo.pluginName.toLowerCase();
|
|
13359
|
+
const base = stripPluginPrefix(skill.name.toLowerCase(), plugin);
|
|
13360
|
+
aliases.add(`${plugin}:${base}`);
|
|
13361
|
+
aliases.add(`@${plugin}:${base}`);
|
|
13362
|
+
aliases.add(`${skill.provider}:${plugin}:${base}`);
|
|
13363
|
+
aliases.add(`${skill.provider}:@${plugin}:${base}`);
|
|
13364
|
+
}
|
|
13365
|
+
return Array.from(aliases);
|
|
13366
|
+
}
|
|
13367
|
+
/**
|
|
13368
|
+
* Render a human-friendly label with colors, highlighting provider/plugin/name components.
|
|
13369
|
+
* Default includes provider to stay copy/pasteable; set includeProvider=false when a provider badge already exists.
|
|
13370
|
+
*/
|
|
13371
|
+
function formatSkillLabel(skill, opts) {
|
|
13372
|
+
const { includeProvider, color, providerColor } = {
|
|
13373
|
+
...defaultFormatOptions,
|
|
13374
|
+
...opts
|
|
13375
|
+
};
|
|
13376
|
+
const useColor = color !== false;
|
|
13377
|
+
const providerPart = includeProvider ? `${skill.provider}:` : "";
|
|
13378
|
+
const pluginPart = skill.pluginInfo ? `@${skill.pluginInfo.pluginName}:` : "";
|
|
13379
|
+
const baseName = skill.pluginInfo ? stripPluginPrefix(skill.name, skill.pluginInfo.pluginName) : skill.name;
|
|
13380
|
+
if (!useColor) return `${providerPart}${pluginPart}${baseName}`;
|
|
13381
|
+
const defaultProviderColor = skill.provider === "claude" ? colors.green : skill.provider === "codex" ? colors.cyan : dim;
|
|
13382
|
+
const green$1 = (providerColor ?? defaultProviderColor)(providerPart.replace(/:$/, ""));
|
|
13383
|
+
const blue$1 = colors.blue(baseName);
|
|
13384
|
+
const pluginColored = pluginPart ? dim(pluginPart) : "";
|
|
13385
|
+
return `${includeProvider ? `${green$1}:` : ""}${pluginColored}${blue$1}`;
|
|
13386
|
+
}
|
|
13387
|
+
|
|
13220
13388
|
//#endregion
|
|
13221
13389
|
//#region src/core/registry.ts
|
|
13222
13390
|
/**
|
|
13223
13391
|
* Skill registry for managing discovered skills
|
|
13224
13392
|
*/
|
|
13225
13393
|
var SkillRegistry = class {
|
|
13226
|
-
skills =
|
|
13394
|
+
skills = [];
|
|
13227
13395
|
diagnostics = {
|
|
13228
13396
|
directoriesScanned: [],
|
|
13229
13397
|
pluginSources: [],
|
|
13230
13398
|
warnings: [],
|
|
13231
|
-
conflicts: []
|
|
13399
|
+
conflicts: [],
|
|
13400
|
+
byProvider: {},
|
|
13401
|
+
byLocation: {}
|
|
13232
13402
|
};
|
|
13233
13403
|
constructor(options = {}) {
|
|
13234
13404
|
this.options = options;
|
|
@@ -13238,56 +13408,75 @@ var SkillRegistry = class {
|
|
|
13238
13408
|
* Refresh the skill registry by rescanning directories
|
|
13239
13409
|
*/
|
|
13240
13410
|
refresh() {
|
|
13241
|
-
this.skills
|
|
13411
|
+
this.skills = [];
|
|
13242
13412
|
this.diagnostics = {
|
|
13243
13413
|
directoriesScanned: [],
|
|
13244
13414
|
pluginSources: [],
|
|
13245
13415
|
warnings: [],
|
|
13246
|
-
conflicts: []
|
|
13416
|
+
conflicts: [],
|
|
13417
|
+
byProvider: {},
|
|
13418
|
+
byLocation: {}
|
|
13247
13419
|
};
|
|
13248
13420
|
const discovered = discoverSkills(this.options);
|
|
13249
13421
|
this.diagnostics.directoriesScanned.push(...discovered.diagnostics.scannedDirectories);
|
|
13250
13422
|
this.diagnostics.warnings.push(...discovered.diagnostics.warnings);
|
|
13251
13423
|
this.diagnostics.conflicts.push(...discovered.diagnostics.conflicts);
|
|
13252
|
-
for (const skill of discovered.skills)
|
|
13424
|
+
for (const skill of discovered.skills) {
|
|
13425
|
+
this.skills.push(skill);
|
|
13426
|
+
this.diagnostics.byProvider[skill.provider] = (this.diagnostics.byProvider[skill.provider] ?? 0) + 1;
|
|
13427
|
+
this.diagnostics.byLocation[skill.location] = (this.diagnostics.byLocation[skill.location] ?? 0) + 1;
|
|
13428
|
+
}
|
|
13253
13429
|
if (!this.options.skipPlugins) {
|
|
13254
13430
|
const pluginOptions = {};
|
|
13255
13431
|
if (this.options.pluginsFile) pluginOptions.pluginsFile = this.options.pluginsFile;
|
|
13256
13432
|
if (this.options.pluginsRoot) pluginOptions.pluginsRoot = this.options.pluginsRoot;
|
|
13433
|
+
if (this.options.userDir) pluginOptions.userDir = this.options.userDir;
|
|
13257
13434
|
const pluginSkills = discoverPluginSkills(pluginOptions);
|
|
13258
13435
|
this.diagnostics.pluginSources.push(...pluginSkills.diagnostics.scannedPlugins);
|
|
13259
13436
|
this.diagnostics.warnings.push(...pluginSkills.diagnostics.warnings);
|
|
13260
|
-
for (const skill of pluginSkills.skills)
|
|
13261
|
-
|
|
13437
|
+
for (const skill of pluginSkills.skills) {
|
|
13438
|
+
if (this.skills.some((existing) => existing.name.toLowerCase() === skill.name.toLowerCase() && existing.location !== "plugin")) this.diagnostics.conflicts.push(`Duplicate skill ${skill.name} from plugin at ${skill.path}; keeping for filter-stage resolution.`);
|
|
13439
|
+
this.skills.push(skill);
|
|
13440
|
+
this.diagnostics.byProvider[skill.provider] = (this.diagnostics.byProvider[skill.provider] ?? 0) + 1;
|
|
13441
|
+
this.diagnostics.byLocation[skill.location] = (this.diagnostics.byLocation[skill.location] ?? 0) + 1;
|
|
13442
|
+
}
|
|
13262
13443
|
}
|
|
13263
13444
|
}
|
|
13264
13445
|
/**
|
|
13265
13446
|
* Get all skills
|
|
13266
13447
|
*/
|
|
13267
13448
|
getAll() {
|
|
13268
|
-
return
|
|
13449
|
+
return [...this.skills];
|
|
13269
13450
|
}
|
|
13270
13451
|
/**
|
|
13271
13452
|
* Find a skill by name (case-insensitive, supports full and short names)
|
|
13272
13453
|
*/
|
|
13273
13454
|
find(name) {
|
|
13274
13455
|
const normalizedName = name.toLowerCase();
|
|
13275
|
-
|
|
13276
|
-
|
|
13277
|
-
|
|
13278
|
-
|
|
13456
|
+
const [maybeProvider, rest] = normalizedName.includes(":") ? (() => {
|
|
13457
|
+
const parts = normalizedName.split(":");
|
|
13458
|
+
if (parts.length > 1 && [
|
|
13459
|
+
"claude",
|
|
13460
|
+
"codex",
|
|
13461
|
+
"file"
|
|
13462
|
+
].includes(parts[0])) return [parts.shift(), parts.join(":")];
|
|
13463
|
+
return [void 0, normalizedName];
|
|
13464
|
+
})() : [void 0, normalizedName];
|
|
13465
|
+
const targetProvider = maybeProvider;
|
|
13466
|
+
const targetName = rest;
|
|
13467
|
+
const candidates = this.skills.filter((skill) => {
|
|
13468
|
+
const skillName = skill.name.toLowerCase();
|
|
13469
|
+
const shortName = skillName.split(":").pop();
|
|
13470
|
+
const matchesName = skillName === targetName || shortName === targetName;
|
|
13471
|
+
const matchesProvider = targetProvider ? skill.provider === targetProvider : true;
|
|
13472
|
+
return matchesName && matchesProvider;
|
|
13279
13473
|
});
|
|
13280
|
-
if (
|
|
13281
|
-
|
|
13282
|
-
|
|
13283
|
-
|
|
13284
|
-
|
|
13285
|
-
|
|
13286
|
-
const tierMatches = shortMatches.filter((skill) => skill.location === tier);
|
|
13287
|
-
if (tierMatches.length === 1) return tierMatches[0];
|
|
13288
|
-
if (tierMatches.length > 1) throw new AmbiguousSkillNameError(name, tierMatches.map((s) => s.name));
|
|
13289
|
-
}
|
|
13290
|
-
throw new SkillNotFoundError(name, this.getSuggestions(name));
|
|
13474
|
+
if (candidates.length === 1) return candidates[0];
|
|
13475
|
+
if (candidates.length > 1) {
|
|
13476
|
+
const suggestions = candidates.map((s) => this.formatNameWithProvider(s));
|
|
13477
|
+
throw new AmbiguousSkillNameError(name, candidates.map((s) => s.name), suggestions);
|
|
13478
|
+
}
|
|
13479
|
+
throw new SkillNotFoundError(name, this.getSuggestions(name, targetProvider));
|
|
13291
13480
|
}
|
|
13292
13481
|
/**
|
|
13293
13482
|
* Check if a skill exists
|
|
@@ -13309,27 +13498,29 @@ var SkillRegistry = class {
|
|
|
13309
13498
|
/**
|
|
13310
13499
|
* Get suggestions for similar skill names (fuzzy matching)
|
|
13311
13500
|
*/
|
|
13312
|
-
getSuggestions(query, limit = 3) {
|
|
13313
|
-
const
|
|
13314
|
-
return rankStrings(
|
|
13501
|
+
getSuggestions(query, provider, limit = 3) {
|
|
13502
|
+
const pool = this.skills.filter((s) => provider ? s.provider === provider : true).map((s) => this.formatNameWithProvider(s));
|
|
13503
|
+
return rankStrings(pool, query).slice(0, limit).map((index) => pool[index]);
|
|
13504
|
+
}
|
|
13505
|
+
formatNameWithProvider(skill) {
|
|
13506
|
+
return formatSkillId(skill);
|
|
13315
13507
|
}
|
|
13316
13508
|
/**
|
|
13317
13509
|
* Get diagnostic information
|
|
13318
13510
|
*/
|
|
13319
13511
|
getDiagnostics() {
|
|
13320
|
-
const byLocation = {};
|
|
13321
|
-
for (const skill of this.skills.values()) byLocation[skill.location] = (byLocation[skill.location] ?? 0) + 1;
|
|
13322
13512
|
return {
|
|
13323
|
-
totalSkills: this.skills.
|
|
13324
|
-
byLocation,
|
|
13325
|
-
|
|
13326
|
-
|
|
13327
|
-
|
|
13328
|
-
|
|
13513
|
+
totalSkills: this.skills.length,
|
|
13514
|
+
byLocation: { ...this.diagnostics.byLocation },
|
|
13515
|
+
byProvider: { ...this.diagnostics.byProvider },
|
|
13516
|
+
directoriesScanned: [...this.diagnostics.directoriesScanned],
|
|
13517
|
+
pluginSources: [...this.diagnostics.pluginSources],
|
|
13518
|
+
warnings: [...this.diagnostics.warnings],
|
|
13519
|
+
conflicts: [...this.diagnostics.conflicts]
|
|
13329
13520
|
};
|
|
13330
13521
|
}
|
|
13331
13522
|
};
|
|
13332
13523
|
|
|
13333
13524
|
//#endregion
|
|
13334
|
-
export {
|
|
13335
|
-
//# sourceMappingURL=registry-
|
|
13525
|
+
export { arrayType as A, recordType as B, warn as C, InstalledPluginsSchema as D, validateSkillFile as E, intersectionType as F, CcskiError as G, unionType as H, literalType as I, ValidationError as J, ParseError as K, numberType as L, custom as M, discriminatedUnionType as N, PluginEntrySchema as O, enumType as P, objectType as R, tone as S, parseSkillFile as T, unknownType as U, stringType as V, AmbiguousSkillNameError as W, highlight$1 as _, containsCaseInsensitive as a, setColorEnabled as b, getDefaultSkillDirectories as c, colors as d, dim as f, heading as g, formatBytes as h, skillAliases as i, booleanType as j, SkillFrontmatterSchema as k, loadSkill as l, error as m, formatSkillId as n, rankStrings as o, duplicateBadge as p, SkillNotFoundError as q, formatSkillLabel as r, discoverSkills as s, SkillRegistry as t, scanSkillDirectory as u, info as v, wrap as w, success as x, renderList as y, optionalType as z };
|
|
13526
|
+
//# sourceMappingURL=registry-Do2Htns7.mjs.map
|