@skillkit/cli 1.10.0 → 1.12.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/dist/index.d.ts +43 -1
- package/dist/index.js +758 -19
- package/dist/index.js.map +1 -1
- package/package.json +9 -8
package/dist/index.js
CHANGED
|
@@ -5790,12 +5790,12 @@ ${learning.title}
|
|
|
5790
5790
|
}
|
|
5791
5791
|
const outputPath = this.output || `.skillkit/exports/${skillName}/SKILL.md`;
|
|
5792
5792
|
const { dirname: dirname7 } = await import("path");
|
|
5793
|
-
const { existsSync:
|
|
5793
|
+
const { existsSync: existsSync23, mkdirSync: mkdirSync11, writeFileSync: writeFileSync12 } = await import("fs");
|
|
5794
5794
|
const outputDir = dirname7(outputPath);
|
|
5795
|
-
if (!
|
|
5796
|
-
|
|
5795
|
+
if (!existsSync23(outputDir)) {
|
|
5796
|
+
mkdirSync11(outputDir, { recursive: true });
|
|
5797
5797
|
}
|
|
5798
|
-
|
|
5798
|
+
writeFileSync12(outputPath, skillContent, "utf-8");
|
|
5799
5799
|
console.log(chalk18.green(`\u2713 Exported learning as skill: ${skillName}`));
|
|
5800
5800
|
console.log(chalk18.gray(` Path: ${outputPath}`));
|
|
5801
5801
|
return 0;
|
|
@@ -5810,10 +5810,10 @@ ${learning.title}
|
|
|
5810
5810
|
console.log(chalk18.gray("Usage: skillkit memory import --input <path>"));
|
|
5811
5811
|
return 1;
|
|
5812
5812
|
}
|
|
5813
|
-
const { existsSync:
|
|
5814
|
-
const { resolve:
|
|
5815
|
-
const fullPath =
|
|
5816
|
-
if (!
|
|
5813
|
+
const { existsSync: existsSync23, readFileSync: readFileSync12 } = await import("fs");
|
|
5814
|
+
const { resolve: resolve23 } = await import("path");
|
|
5815
|
+
const fullPath = resolve23(inputPath);
|
|
5816
|
+
if (!existsSync23(fullPath)) {
|
|
5817
5817
|
console.error(chalk18.red(`File not found: ${fullPath}`));
|
|
5818
5818
|
return 1;
|
|
5819
5819
|
}
|
|
@@ -5823,7 +5823,7 @@ ${learning.title}
|
|
|
5823
5823
|
this.global ? void 0 : projectPath
|
|
5824
5824
|
);
|
|
5825
5825
|
try {
|
|
5826
|
-
const content =
|
|
5826
|
+
const content = readFileSync12(fullPath, "utf-8");
|
|
5827
5827
|
const { parse: parseYaml2 } = await import("yaml");
|
|
5828
5828
|
const data = parseYaml2(content);
|
|
5829
5829
|
if (!data.learnings || !Array.isArray(data.learnings)) {
|
|
@@ -6892,14 +6892,14 @@ var TeamCommand = class extends Command29 {
|
|
|
6892
6892
|
}
|
|
6893
6893
|
const projectPath = process.cwd();
|
|
6894
6894
|
const bundlePath = join12(projectPath, ".skillkit", "bundles", `${this.name}.json`);
|
|
6895
|
-
const { existsSync:
|
|
6896
|
-
if (!
|
|
6895
|
+
const { existsSync: existsSync23, readFileSync: readFileSync12, writeFileSync: writeFileSync12 } = await import("fs");
|
|
6896
|
+
if (!existsSync23(bundlePath)) {
|
|
6897
6897
|
this.context.stderr.write(chalk21.red(`Bundle "${this.name}" not found. Create it first with bundle-create.
|
|
6898
6898
|
`));
|
|
6899
6899
|
return 1;
|
|
6900
6900
|
}
|
|
6901
|
-
const content =
|
|
6902
|
-
|
|
6901
|
+
const content = readFileSync12(bundlePath, "utf-8");
|
|
6902
|
+
writeFileSync12(this.output, content, "utf-8");
|
|
6903
6903
|
this.context.stdout.write(chalk21.green(`\u2713 Bundle exported to: ${this.output}
|
|
6904
6904
|
`));
|
|
6905
6905
|
return 0;
|
|
@@ -6909,8 +6909,8 @@ var TeamCommand = class extends Command29 {
|
|
|
6909
6909
|
this.context.stderr.write(chalk21.red("--source <path> is required for bundle-import\n"));
|
|
6910
6910
|
return 1;
|
|
6911
6911
|
}
|
|
6912
|
-
const { existsSync:
|
|
6913
|
-
if (!
|
|
6912
|
+
const { existsSync: existsSync23 } = await import("fs");
|
|
6913
|
+
if (!existsSync23(this.source)) {
|
|
6914
6914
|
this.context.stderr.write(chalk21.red(`Bundle file not found: ${this.source}
|
|
6915
6915
|
`));
|
|
6916
6916
|
return 1;
|
|
@@ -7078,8 +7078,8 @@ var PluginCommand = class extends Command30 {
|
|
|
7078
7078
|
}
|
|
7079
7079
|
const projectPath = this.global ? join13(homedir2(), ".skillkit") : process.cwd();
|
|
7080
7080
|
const pluginsDir = this.global ? join13(projectPath, "plugins") : join13(projectPath, ".skillkit", "plugins");
|
|
7081
|
-
const
|
|
7082
|
-
if (
|
|
7081
|
+
const isLocalPath5 = this.source.startsWith("./") || this.source.startsWith("../") || this.source.startsWith("/") || this.source.startsWith("~") || this.source.includes("\\") || isAbsolute(this.source);
|
|
7082
|
+
if (isLocalPath5 && existsSync15(resolvedSource)) {
|
|
7083
7083
|
const targetDir = join13(pluginsDir, pluginName);
|
|
7084
7084
|
const resolvedTarget = resolve13(targetDir);
|
|
7085
7085
|
const resolvedPluginsDir = resolve13(pluginsDir);
|
|
@@ -10815,6 +10815,7 @@ var CheckCommand = class extends Command39 {
|
|
|
10815
10815
|
// src/commands/find.ts
|
|
10816
10816
|
init_onboarding();
|
|
10817
10817
|
import { Command as Command40, Option as Option39 } from "clipanion";
|
|
10818
|
+
import { FederatedSearch, GitHubSkillRegistry, RateLimitError } from "@skillkit/core";
|
|
10818
10819
|
|
|
10819
10820
|
// ../../marketplace/skills.json
|
|
10820
10821
|
var skills_default = {
|
|
@@ -136493,6 +136494,9 @@ var FindCommand = class extends Command40 {
|
|
|
136493
136494
|
quiet = Option39.Boolean("--quiet,-q", false, {
|
|
136494
136495
|
description: "Minimal output (just list skills)"
|
|
136495
136496
|
});
|
|
136497
|
+
federated = Option39.Boolean("--federated,-f", false, {
|
|
136498
|
+
description: "Search external registries (GitHub SKILL.md files)"
|
|
136499
|
+
});
|
|
136496
136500
|
async execute() {
|
|
136497
136501
|
const s = spinner2();
|
|
136498
136502
|
const limit = parseInt(this.limit, 10) || 10;
|
|
@@ -136542,12 +136546,42 @@ var FindCommand = class extends Command40 {
|
|
|
136542
136546
|
results = allSkills.slice(0, limit);
|
|
136543
136547
|
}
|
|
136544
136548
|
}
|
|
136549
|
+
if (this.federated && this.query) {
|
|
136550
|
+
s.start("Searching external registries...");
|
|
136551
|
+
const fedSearch = new FederatedSearch();
|
|
136552
|
+
fedSearch.addRegistry(new GitHubSkillRegistry());
|
|
136553
|
+
try {
|
|
136554
|
+
const fedResult = await fedSearch.search(this.query, { limit: parseInt(this.limit, 10) || 10 });
|
|
136555
|
+
s.stop(`Found ${fedResult.total} external skill(s) from ${fedResult.registries.join(", ") || "none"}`);
|
|
136556
|
+
if (fedResult.skills.length > 0) {
|
|
136557
|
+
console.log("");
|
|
136558
|
+
console.log(colors.bold("External Skills (SKILL.md):"));
|
|
136559
|
+
for (const skill of fedResult.skills) {
|
|
136560
|
+
const stars = typeof skill.stars === "number" ? colors.muted(` \u2605${skill.stars}`) : "";
|
|
136561
|
+
const desc = skill.description ? colors.muted(` - ${skill.description.slice(0, 50)}${skill.description.length > 50 ? "..." : ""}`) : "";
|
|
136562
|
+
console.log(` ${colors.cyan(symbols.bullet)} ${colors.primary(skill.name)}${stars}${desc}`);
|
|
136563
|
+
if (!this.quiet) {
|
|
136564
|
+
console.log(` ${colors.muted(skill.source)}`);
|
|
136565
|
+
}
|
|
136566
|
+
}
|
|
136567
|
+
console.log("");
|
|
136568
|
+
}
|
|
136569
|
+
} catch (err) {
|
|
136570
|
+
if (err instanceof RateLimitError) {
|
|
136571
|
+
s.stop(colors.warning("Rate limited by GitHub API"));
|
|
136572
|
+
console.log(colors.muted("Set GITHUB_TOKEN env var or wait before retrying."));
|
|
136573
|
+
} else {
|
|
136574
|
+
s.stop(colors.warning("Federated search failed"));
|
|
136575
|
+
}
|
|
136576
|
+
}
|
|
136577
|
+
}
|
|
136545
136578
|
if (results.length === 0) {
|
|
136546
136579
|
console.log(colors.muted("No skills found matching your search"));
|
|
136547
136580
|
console.log("");
|
|
136548
136581
|
console.log(colors.muted("Try:"));
|
|
136549
|
-
console.log(colors.muted(" skillkit find --top
|
|
136550
|
-
console.log(colors.muted(" skillkit
|
|
136582
|
+
console.log(colors.muted(" skillkit find --top # Show featured skills"));
|
|
136583
|
+
console.log(colors.muted(" skillkit find -f <query> # Search external registries"));
|
|
136584
|
+
console.log(colors.muted(" skillkit ui # Browse in TUI"));
|
|
136551
136585
|
return 0;
|
|
136552
136586
|
}
|
|
136553
136587
|
console.log("");
|
|
@@ -139409,6 +139443,706 @@ var TreeCommand = class extends Command49 {
|
|
|
139409
139443
|
}
|
|
139410
139444
|
};
|
|
139411
139445
|
|
|
139446
|
+
// src/commands/quick.ts
|
|
139447
|
+
init_helpers();
|
|
139448
|
+
init_onboarding();
|
|
139449
|
+
import { existsSync as existsSync21, mkdirSync as mkdirSync10, cpSync as cpSync4, rmSync as rmSync5, symlinkSync as symlinkSync2 } from "fs";
|
|
139450
|
+
import { join as join20, resolve as resolve21, normalize } from "path";
|
|
139451
|
+
import { execFile as execFile2 } from "child_process";
|
|
139452
|
+
import { promisify as promisify2 } from "util";
|
|
139453
|
+
import { Command as Command50 } from "clipanion";
|
|
139454
|
+
import {
|
|
139455
|
+
ContextManager as ContextManager3,
|
|
139456
|
+
RecommendationEngine as RecommendationEngine2,
|
|
139457
|
+
loadIndex as loadIndexFromCache4,
|
|
139458
|
+
isIndexStale as isIndexStale2,
|
|
139459
|
+
buildSkillIndex as buildSkillIndex2,
|
|
139460
|
+
saveIndex as saveIndex2,
|
|
139461
|
+
KNOWN_SKILL_REPOS as KNOWN_SKILL_REPOS2,
|
|
139462
|
+
isPathInside as isPathInside2,
|
|
139463
|
+
isLocalPath as isLocalPath4,
|
|
139464
|
+
detectProvider as detectProvider4
|
|
139465
|
+
} from "@skillkit/core";
|
|
139466
|
+
import { getAdapter as getAdapter6, detectAgent as detectAgent5, getAllAdapters as getAllAdapters6 } from "@skillkit/agents";
|
|
139467
|
+
var execFileAsync2 = promisify2(execFile2);
|
|
139468
|
+
function truncate6(str, maxLen) {
|
|
139469
|
+
if (str.length <= maxLen) return str;
|
|
139470
|
+
return str.slice(0, maxLen - 3) + "...";
|
|
139471
|
+
}
|
|
139472
|
+
var QuickCommand = class extends Command50 {
|
|
139473
|
+
static paths = [["quick"]];
|
|
139474
|
+
static usage = Command50.Usage({
|
|
139475
|
+
description: "Zero-friction skill setup: detect agents, analyze project, recommend and install",
|
|
139476
|
+
examples: [
|
|
139477
|
+
["Quick setup", "$0 quick"]
|
|
139478
|
+
]
|
|
139479
|
+
});
|
|
139480
|
+
async execute() {
|
|
139481
|
+
const s = spinner2();
|
|
139482
|
+
try {
|
|
139483
|
+
welcome();
|
|
139484
|
+
step(`${colors.bold("Quick Setup")} - zero-friction skill installation`);
|
|
139485
|
+
console.log("");
|
|
139486
|
+
s.start("Detecting installed AI agents...");
|
|
139487
|
+
const allAdapters = getAllAdapters6();
|
|
139488
|
+
const detectedAgents = [];
|
|
139489
|
+
for (const adapter of allAdapters) {
|
|
139490
|
+
try {
|
|
139491
|
+
const installDir = getInstallDir(false, adapter.type);
|
|
139492
|
+
const globalDir = getInstallDir(true, adapter.type);
|
|
139493
|
+
if (existsSync21(installDir) || existsSync21(globalDir) || existsSync21(adapter.configFile)) {
|
|
139494
|
+
detectedAgents.push(adapter.type);
|
|
139495
|
+
}
|
|
139496
|
+
} catch {
|
|
139497
|
+
}
|
|
139498
|
+
}
|
|
139499
|
+
if (detectedAgents.length === 0) {
|
|
139500
|
+
const fallback = await detectAgent5();
|
|
139501
|
+
detectedAgents.push(fallback);
|
|
139502
|
+
}
|
|
139503
|
+
s.stop(`Detected ${detectedAgents.length} agent${detectedAgents.length !== 1 ? "s" : ""}: ${detectedAgents.map(formatAgent).join(", ")}`);
|
|
139504
|
+
s.start("Analyzing project...");
|
|
139505
|
+
const targetPath = resolve21(process.cwd());
|
|
139506
|
+
const manager = new ContextManager3(targetPath);
|
|
139507
|
+
let context = manager.get();
|
|
139508
|
+
if (!context) {
|
|
139509
|
+
context = manager.init();
|
|
139510
|
+
}
|
|
139511
|
+
s.stop("Project analyzed");
|
|
139512
|
+
if (!context) {
|
|
139513
|
+
error("Failed to analyze project");
|
|
139514
|
+
return 1;
|
|
139515
|
+
}
|
|
139516
|
+
const profile = {
|
|
139517
|
+
name: context.project.name,
|
|
139518
|
+
type: context.project.type,
|
|
139519
|
+
stack: context.stack,
|
|
139520
|
+
patterns: context.patterns,
|
|
139521
|
+
installedSkills: context.skills?.installed || [],
|
|
139522
|
+
excludedSkills: context.skills?.excluded || []
|
|
139523
|
+
};
|
|
139524
|
+
const languages = profile.stack.languages.map((l) => `${l.name}${l.version ? ` ${l.version}` : ""}`);
|
|
139525
|
+
const frameworks = profile.stack.frameworks.map((f) => `${f.name}${f.version ? ` ${f.version}` : ""}`);
|
|
139526
|
+
showProjectSummary({
|
|
139527
|
+
name: profile.name,
|
|
139528
|
+
type: profile.type,
|
|
139529
|
+
languages,
|
|
139530
|
+
frameworks
|
|
139531
|
+
});
|
|
139532
|
+
let index = loadIndexFromCache4();
|
|
139533
|
+
if (!index || index.skills.length === 0) {
|
|
139534
|
+
s.start("Building skill index from known sources...");
|
|
139535
|
+
try {
|
|
139536
|
+
const result2 = await buildSkillIndex2(KNOWN_SKILL_REPOS2, (message) => {
|
|
139537
|
+
s.message(message);
|
|
139538
|
+
});
|
|
139539
|
+
index = result2.index;
|
|
139540
|
+
saveIndex2(index);
|
|
139541
|
+
s.stop(`Indexed ${index.skills.length} skills`);
|
|
139542
|
+
} catch {
|
|
139543
|
+
s.stop(colors.error("Failed to build index"));
|
|
139544
|
+
warn("Could not fetch skill index. Try running: skillkit recommend --update");
|
|
139545
|
+
return 1;
|
|
139546
|
+
}
|
|
139547
|
+
} else if (isIndexStale2(index)) {
|
|
139548
|
+
step(colors.muted('Skill index is stale. Run "skillkit recommend --update" to refresh.'));
|
|
139549
|
+
}
|
|
139550
|
+
const engine = new RecommendationEngine2();
|
|
139551
|
+
engine.loadIndex(index);
|
|
139552
|
+
const result = engine.recommend(profile, {
|
|
139553
|
+
limit: 5,
|
|
139554
|
+
minScore: 20,
|
|
139555
|
+
excludeInstalled: true,
|
|
139556
|
+
includeReasons: true
|
|
139557
|
+
});
|
|
139558
|
+
const recommendations = result.recommendations;
|
|
139559
|
+
if (recommendations.length === 0) {
|
|
139560
|
+
warn("No matching skills found for your project.");
|
|
139561
|
+
console.log(colors.muted("Try running: skillkit recommend --update"));
|
|
139562
|
+
return 0;
|
|
139563
|
+
}
|
|
139564
|
+
console.log("");
|
|
139565
|
+
console.log(colors.bold(`Top ${recommendations.length} Recommended Skills:`));
|
|
139566
|
+
console.log("");
|
|
139567
|
+
const options = [];
|
|
139568
|
+
for (let i = 0; i < recommendations.length; i++) {
|
|
139569
|
+
const rec = recommendations[i];
|
|
139570
|
+
let scoreColor;
|
|
139571
|
+
if (rec.score >= 70) {
|
|
139572
|
+
scoreColor = colors.success;
|
|
139573
|
+
} else if (rec.score >= 50) {
|
|
139574
|
+
scoreColor = colors.warning;
|
|
139575
|
+
} else {
|
|
139576
|
+
scoreColor = colors.muted;
|
|
139577
|
+
}
|
|
139578
|
+
const scoreBar = progressBar(rec.score, 100, 10);
|
|
139579
|
+
const qualityScore = rec.skill.quality ?? null;
|
|
139580
|
+
const qualityDisplay = typeof qualityScore === "number" && Number.isFinite(qualityScore) ? ` ${formatQualityBadge(qualityScore)}` : "";
|
|
139581
|
+
console.log(` ${colors.bold(`${i + 1}.`)} ${scoreColor(`${rec.score}%`)} ${colors.dim(scoreBar)} ${colors.bold(rec.skill.name)}${qualityDisplay}`);
|
|
139582
|
+
if (rec.skill.description) {
|
|
139583
|
+
console.log(` ${colors.muted(truncate6(rec.skill.description, 70))}`);
|
|
139584
|
+
}
|
|
139585
|
+
options.push({
|
|
139586
|
+
value: `${i}`,
|
|
139587
|
+
label: `${rec.skill.name} (${rec.score}% match)`,
|
|
139588
|
+
hint: rec.skill.source || void 0
|
|
139589
|
+
});
|
|
139590
|
+
}
|
|
139591
|
+
console.log("");
|
|
139592
|
+
const skipOption = { value: "skip", label: "Skip installation" };
|
|
139593
|
+
const selectResult = await select2({
|
|
139594
|
+
message: "Select a skill to install",
|
|
139595
|
+
options: [...options, skipOption]
|
|
139596
|
+
});
|
|
139597
|
+
if (isCancel2(selectResult) || selectResult === "skip") {
|
|
139598
|
+
cancel2("Quick setup complete (no installation)");
|
|
139599
|
+
return 0;
|
|
139600
|
+
}
|
|
139601
|
+
const selectedIndex = parseInt(selectResult, 10);
|
|
139602
|
+
const selectedSkill = recommendations[selectedIndex];
|
|
139603
|
+
if (!selectedSkill || !selectedSkill.skill.source) {
|
|
139604
|
+
error("Selected skill has no installable source");
|
|
139605
|
+
return 1;
|
|
139606
|
+
}
|
|
139607
|
+
const agentDisplay = detectedAgents.length <= 3 ? detectedAgents.map(formatAgent).join(", ") : `${detectedAgents.slice(0, 2).map(formatAgent).join(", ")} +${detectedAgents.length - 2} more`;
|
|
139608
|
+
const confirmResult = await confirm2({
|
|
139609
|
+
message: `Install ${colors.bold(selectedSkill.skill.name)} to ${agentDisplay}?`,
|
|
139610
|
+
initialValue: true
|
|
139611
|
+
});
|
|
139612
|
+
if (isCancel2(confirmResult) || !confirmResult) {
|
|
139613
|
+
cancel2("Installation cancelled");
|
|
139614
|
+
return 0;
|
|
139615
|
+
}
|
|
139616
|
+
saveLastAgents(detectedAgents);
|
|
139617
|
+
const providerAdapter = detectProvider4(selectedSkill.skill.source);
|
|
139618
|
+
if (!providerAdapter) {
|
|
139619
|
+
error(`Could not detect provider for: ${selectedSkill.skill.source}`);
|
|
139620
|
+
return 1;
|
|
139621
|
+
}
|
|
139622
|
+
s.start(`Fetching ${selectedSkill.skill.name}...`);
|
|
139623
|
+
const cloneResult = await providerAdapter.clone(selectedSkill.skill.source, "", { depth: 1 });
|
|
139624
|
+
if (!cloneResult.success || !cloneResult.path) {
|
|
139625
|
+
s.stop(colors.error(cloneResult.error || "Failed to fetch source"));
|
|
139626
|
+
return 1;
|
|
139627
|
+
}
|
|
139628
|
+
const discoveredSkills = cloneResult.discoveredSkills || [];
|
|
139629
|
+
const matchedSkill = discoveredSkills.find((ds) => ds.name === selectedSkill.skill.name) || discoveredSkills[0];
|
|
139630
|
+
if (!matchedSkill) {
|
|
139631
|
+
s.stop(colors.error("Skill not found in repository"));
|
|
139632
|
+
return 1;
|
|
139633
|
+
}
|
|
139634
|
+
s.stop(`Found ${selectedSkill.skill.name}`);
|
|
139635
|
+
let primaryPath = null;
|
|
139636
|
+
const installedAgents = [];
|
|
139637
|
+
for (const agentType of detectedAgents) {
|
|
139638
|
+
const adapter = getAdapter6(agentType);
|
|
139639
|
+
const installDir = getInstallDir(false, agentType);
|
|
139640
|
+
if (!existsSync21(installDir)) {
|
|
139641
|
+
mkdirSync10(installDir, { recursive: true });
|
|
139642
|
+
}
|
|
139643
|
+
const sanitizedName = matchedSkill.name.split(/[/\\]/).pop() || matchedSkill.name;
|
|
139644
|
+
const targetInstallPath = normalize(join20(installDir, sanitizedName));
|
|
139645
|
+
if (!isPathInside2(targetInstallPath, installDir)) {
|
|
139646
|
+
error(`Skipping ${matchedSkill.name} for ${adapter.name} (install path escapes target directory)`);
|
|
139647
|
+
continue;
|
|
139648
|
+
}
|
|
139649
|
+
const securityRoot = cloneResult.tempRoot || cloneResult.path;
|
|
139650
|
+
if (!isPathInside2(matchedSkill.path, securityRoot)) {
|
|
139651
|
+
error(`Skipping ${matchedSkill.name} for ${adapter.name} (path traversal detected)`);
|
|
139652
|
+
continue;
|
|
139653
|
+
}
|
|
139654
|
+
const useSymlink = detectedAgents.length > 1 && primaryPath !== null;
|
|
139655
|
+
s.start(`Installing to ${adapter.name}${useSymlink ? " (symlink)" : ""}...`);
|
|
139656
|
+
try {
|
|
139657
|
+
if (existsSync21(targetInstallPath)) {
|
|
139658
|
+
rmSync5(targetInstallPath, { recursive: true, force: true });
|
|
139659
|
+
}
|
|
139660
|
+
if (useSymlink && primaryPath) {
|
|
139661
|
+
symlinkSync2(primaryPath, targetInstallPath, "dir");
|
|
139662
|
+
} else {
|
|
139663
|
+
cpSync4(matchedSkill.path, targetInstallPath, { recursive: true, dereference: true });
|
|
139664
|
+
if (detectedAgents.length > 1 && primaryPath === null) {
|
|
139665
|
+
primaryPath = targetInstallPath;
|
|
139666
|
+
}
|
|
139667
|
+
const packageJsonPath = join20(targetInstallPath, "package.json");
|
|
139668
|
+
if (existsSync21(packageJsonPath)) {
|
|
139669
|
+
s.stop(`Installed to ${adapter.name}`);
|
|
139670
|
+
s.start("Installing npm dependencies...");
|
|
139671
|
+
try {
|
|
139672
|
+
await execFileAsync2("npm", ["install", "--production"], { cwd: targetInstallPath });
|
|
139673
|
+
s.stop("Dependencies installed");
|
|
139674
|
+
} catch {
|
|
139675
|
+
s.stop(colors.warning("Dependencies failed"));
|
|
139676
|
+
console.log(colors.muted("Run manually: npm install in " + targetInstallPath));
|
|
139677
|
+
}
|
|
139678
|
+
s.start("Finishing installation...");
|
|
139679
|
+
}
|
|
139680
|
+
}
|
|
139681
|
+
const metadata = {
|
|
139682
|
+
name: matchedSkill.name,
|
|
139683
|
+
description: selectedSkill.skill.description || "",
|
|
139684
|
+
source: selectedSkill.skill.source,
|
|
139685
|
+
sourceType: providerAdapter.type,
|
|
139686
|
+
subpath: matchedSkill.name,
|
|
139687
|
+
installedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
139688
|
+
enabled: true
|
|
139689
|
+
};
|
|
139690
|
+
saveSkillMetadata(targetInstallPath, metadata);
|
|
139691
|
+
installedAgents.push(agentType);
|
|
139692
|
+
s.stop(`Installed to ${adapter.name}${useSymlink ? " (symlink)" : ""}`);
|
|
139693
|
+
} catch (err) {
|
|
139694
|
+
s.stop(colors.error(`Failed to install to ${adapter.name}`));
|
|
139695
|
+
console.log(colors.muted(err instanceof Error ? err.message : String(err)));
|
|
139696
|
+
}
|
|
139697
|
+
}
|
|
139698
|
+
const cleanupPath = cloneResult.tempRoot || cloneResult.path;
|
|
139699
|
+
if (!isLocalPath4(selectedSkill.skill.source) && cleanupPath && existsSync21(cleanupPath)) {
|
|
139700
|
+
rmSync5(cleanupPath, { recursive: true, force: true });
|
|
139701
|
+
}
|
|
139702
|
+
if (installedAgents.length > 0) {
|
|
139703
|
+
console.log("");
|
|
139704
|
+
success(`Installed ${colors.bold(matchedSkill.name)} to ${installedAgents.length} agent${installedAgents.length !== 1 ? "s" : ""}`);
|
|
139705
|
+
for (const a of installedAgents) {
|
|
139706
|
+
console.log(colors.muted(` ${symbols.success} ${getAgentIcon(a)} ${formatAgent(a)}`));
|
|
139707
|
+
}
|
|
139708
|
+
console.log("");
|
|
139709
|
+
const badgeUrl = `https://img.shields.io/badge/SkillKit-${encodeURIComponent(matchedSkill.name)}-black?style=flat-square`;
|
|
139710
|
+
console.log(colors.dim("Add to your README:"));
|
|
139711
|
+
console.log(colors.muted(` [](https://agenstskills.com)`));
|
|
139712
|
+
outro2("Quick setup complete!");
|
|
139713
|
+
console.log("");
|
|
139714
|
+
console.log(colors.muted("Next steps:"));
|
|
139715
|
+
console.log(colors.muted(` ${symbols.arrowRight} Run ${colors.cyan("skillkit sync")} to update agent configs`));
|
|
139716
|
+
console.log(colors.muted(` ${symbols.arrowRight} Run ${colors.cyan("skillkit recommend")} for more suggestions`));
|
|
139717
|
+
console.log(colors.muted(` ${symbols.arrowRight} Run ${colors.cyan("skillkit list")} to see installed skills`));
|
|
139718
|
+
console.log("");
|
|
139719
|
+
} else {
|
|
139720
|
+
warn("No agents were installed");
|
|
139721
|
+
}
|
|
139722
|
+
return 0;
|
|
139723
|
+
} catch (err) {
|
|
139724
|
+
s.stop(colors.error("Quick setup failed"));
|
|
139725
|
+
console.log(colors.muted(err instanceof Error ? err.message : String(err)));
|
|
139726
|
+
return 1;
|
|
139727
|
+
}
|
|
139728
|
+
}
|
|
139729
|
+
};
|
|
139730
|
+
|
|
139731
|
+
// src/commands/skillmd.ts
|
|
139732
|
+
init_onboarding();
|
|
139733
|
+
import { existsSync as existsSync22, readFileSync as readFileSync11, writeFileSync as writeFileSync11, readdirSync as readdirSync4 } from "fs";
|
|
139734
|
+
import { join as join21, resolve as resolve22, basename as basename6, relative } from "path";
|
|
139735
|
+
import { Command as Command51, Option as Option49 } from "clipanion";
|
|
139736
|
+
function validateSkillMd(filePath) {
|
|
139737
|
+
const result = {
|
|
139738
|
+
path: filePath,
|
|
139739
|
+
exists: false,
|
|
139740
|
+
hasName: false,
|
|
139741
|
+
hasDescription: false,
|
|
139742
|
+
hasTriggers: false,
|
|
139743
|
+
hasCapabilities: false,
|
|
139744
|
+
triggerCount: 0,
|
|
139745
|
+
capabilityCount: 0,
|
|
139746
|
+
score: 0,
|
|
139747
|
+
issues: []
|
|
139748
|
+
};
|
|
139749
|
+
if (!existsSync22(filePath)) {
|
|
139750
|
+
result.issues.push("File does not exist");
|
|
139751
|
+
return result;
|
|
139752
|
+
}
|
|
139753
|
+
result.exists = true;
|
|
139754
|
+
const content = readFileSync11(filePath, "utf-8");
|
|
139755
|
+
if (!content.trim()) {
|
|
139756
|
+
result.issues.push("File is empty");
|
|
139757
|
+
return result;
|
|
139758
|
+
}
|
|
139759
|
+
const frontmatterMatch = content.match(/^---\r?\n([\s\S]*?)\r?\n---/);
|
|
139760
|
+
const bodyContent = frontmatterMatch ? content.slice(frontmatterMatch[0].length) : content;
|
|
139761
|
+
if (frontmatterMatch) {
|
|
139762
|
+
const frontmatter = frontmatterMatch[1];
|
|
139763
|
+
if (/^name:\s*.+$/m.test(frontmatter)) result.hasName = true;
|
|
139764
|
+
if (/^description:\s*.+$/m.test(frontmatter)) result.hasDescription = true;
|
|
139765
|
+
}
|
|
139766
|
+
if (!result.hasName) {
|
|
139767
|
+
if (/^#\s+.+$/m.test(bodyContent)) result.hasName = true;
|
|
139768
|
+
}
|
|
139769
|
+
if (!result.hasDescription) {
|
|
139770
|
+
if (/^##?\s*(description|about|overview)\b/im.test(bodyContent)) {
|
|
139771
|
+
result.hasDescription = true;
|
|
139772
|
+
} else {
|
|
139773
|
+
const lines = bodyContent.split(/\r?\n/).filter((l) => l.trim());
|
|
139774
|
+
const nonHeaderLines = lines.filter((l) => !l.startsWith("#"));
|
|
139775
|
+
if (nonHeaderLines.length >= 2) result.hasDescription = true;
|
|
139776
|
+
}
|
|
139777
|
+
}
|
|
139778
|
+
const triggerPatterns = [
|
|
139779
|
+
/triggers?\s*when/i,
|
|
139780
|
+
/when\s*to\s*use/i,
|
|
139781
|
+
/use\s*this\s*when/i,
|
|
139782
|
+
/\*\*triggers?\b/i,
|
|
139783
|
+
/^[-*]\s+.+(when|if|pattern|trigger)/im,
|
|
139784
|
+
/glob:/i
|
|
139785
|
+
];
|
|
139786
|
+
for (const pattern of triggerPatterns) {
|
|
139787
|
+
if (pattern.test(content)) {
|
|
139788
|
+
result.hasTriggers = true;
|
|
139789
|
+
break;
|
|
139790
|
+
}
|
|
139791
|
+
}
|
|
139792
|
+
if (result.hasTriggers) {
|
|
139793
|
+
const triggerSection = content.match(/triggers?\s*when[:\s]*\n((?:[-*]\s+.+\n?)+)/i);
|
|
139794
|
+
result.triggerCount = triggerSection ? (triggerSection[1].match(/^[-*]\s+/gm) || []).length : 1;
|
|
139795
|
+
}
|
|
139796
|
+
const capabilityPatterns = [
|
|
139797
|
+
/capabilities?[:\s]/i,
|
|
139798
|
+
/features?[:\s]/i,
|
|
139799
|
+
/what\s*(it|this)\s*(does|can)/i,
|
|
139800
|
+
/^##?\s*capabilities/im,
|
|
139801
|
+
/^##?\s*features/im
|
|
139802
|
+
];
|
|
139803
|
+
for (const pattern of capabilityPatterns) {
|
|
139804
|
+
if (pattern.test(content)) {
|
|
139805
|
+
result.hasCapabilities = true;
|
|
139806
|
+
break;
|
|
139807
|
+
}
|
|
139808
|
+
}
|
|
139809
|
+
if (result.hasCapabilities) {
|
|
139810
|
+
const capSection = content.match(/(?:capabilities?|features?)[:\s]*\n((?:[-*]\s+.+\n?)+)/i);
|
|
139811
|
+
result.capabilityCount = capSection ? (capSection[1].match(/^[-*]\s+/gm) || []).length : 1;
|
|
139812
|
+
}
|
|
139813
|
+
if (!result.hasName) result.issues.push("Missing name field");
|
|
139814
|
+
if (!result.hasDescription) result.issues.push("Missing description section");
|
|
139815
|
+
if (!result.hasTriggers) result.issues.push("No trigger patterns found");
|
|
139816
|
+
if (!result.hasCapabilities) result.issues.push("No capabilities list found");
|
|
139817
|
+
let score = 0;
|
|
139818
|
+
if (result.exists) score += 10;
|
|
139819
|
+
if (result.hasName) score += 20;
|
|
139820
|
+
if (result.hasDescription) score += 25;
|
|
139821
|
+
if (result.hasTriggers) score += 20;
|
|
139822
|
+
if (result.hasCapabilities) score += 15;
|
|
139823
|
+
if (result.triggerCount >= 3) score += 5;
|
|
139824
|
+
if (result.capabilityCount >= 3) score += 5;
|
|
139825
|
+
if (frontmatterMatch) {
|
|
139826
|
+
const fm = frontmatterMatch[1];
|
|
139827
|
+
if (/^version:/m.test(fm)) score += 3;
|
|
139828
|
+
if (/^license:/m.test(fm)) score += 2;
|
|
139829
|
+
if (/^tags:/m.test(fm)) score += 3;
|
|
139830
|
+
if (/^metadata:/m.test(fm)) score += 2;
|
|
139831
|
+
}
|
|
139832
|
+
result.score = Math.min(100, score);
|
|
139833
|
+
return result;
|
|
139834
|
+
}
|
|
139835
|
+
function printValidation(validation, verbose = false) {
|
|
139836
|
+
const scoreColor = validation.score >= 80 ? colors.success : validation.score >= 60 ? colors.warning : colors.error;
|
|
139837
|
+
console.log(` ${colors.muted("Score:")} ${scoreColor(`${validation.score}`)}/100`);
|
|
139838
|
+
console.log(` ${validation.hasName ? colors.success(symbols.success) : colors.error(symbols.error)} Name field`);
|
|
139839
|
+
console.log(` ${validation.hasDescription ? colors.success(symbols.success) : colors.error(symbols.error)} Description section`);
|
|
139840
|
+
console.log(` ${validation.hasTriggers ? colors.success(symbols.success) : colors.error(symbols.error)} Trigger patterns${validation.triggerCount > 0 ? ` (${validation.triggerCount})` : ""}`);
|
|
139841
|
+
console.log(` ${validation.hasCapabilities ? colors.success(symbols.success) : colors.error(symbols.error)} Capabilities list${validation.capabilityCount > 0 ? ` (${validation.capabilityCount})` : ""}`);
|
|
139842
|
+
if (verbose && validation.issues.length > 0) {
|
|
139843
|
+
console.log("");
|
|
139844
|
+
console.log(` ${colors.warning("Issues:")}`);
|
|
139845
|
+
for (const issue of validation.issues) {
|
|
139846
|
+
console.log(` ${colors.warning(symbols.warning)} ${issue}`);
|
|
139847
|
+
}
|
|
139848
|
+
}
|
|
139849
|
+
}
|
|
139850
|
+
var SkillMdValidateCommand = class extends Command51 {
|
|
139851
|
+
static paths = [["skillmd", "validate"], ["skill-md", "validate"]];
|
|
139852
|
+
static usage = Command51.Usage({
|
|
139853
|
+
description: "Validate a SKILL.md file against the standard",
|
|
139854
|
+
examples: [
|
|
139855
|
+
["Validate SKILL.md in current directory", "$0 skillmd validate"],
|
|
139856
|
+
["Validate specific file", "$0 skillmd validate ./path/to/SKILL.md"]
|
|
139857
|
+
]
|
|
139858
|
+
});
|
|
139859
|
+
targetPath = Option49.String({ required: false, name: "path" });
|
|
139860
|
+
verbose = Option49.Boolean("--verbose,-v", false, {
|
|
139861
|
+
description: "Show detailed validation results"
|
|
139862
|
+
});
|
|
139863
|
+
json = Option49.Boolean("--json", false, {
|
|
139864
|
+
description: "Output as JSON"
|
|
139865
|
+
});
|
|
139866
|
+
async execute() {
|
|
139867
|
+
const targetPath = this.targetPath || join21(process.cwd(), "SKILL.md");
|
|
139868
|
+
const resolvedPath = resolve22(targetPath);
|
|
139869
|
+
const filePath = resolvedPath.endsWith("SKILL.md") ? resolvedPath : join21(resolvedPath, "SKILL.md");
|
|
139870
|
+
if (!this.json) {
|
|
139871
|
+
header("SKILL.md Validation");
|
|
139872
|
+
step(`Validating: ${colors.cyan(filePath)}`);
|
|
139873
|
+
console.log("");
|
|
139874
|
+
}
|
|
139875
|
+
const validation = validateSkillMd(filePath);
|
|
139876
|
+
if (this.json) {
|
|
139877
|
+
console.log(JSON.stringify(validation, null, 2));
|
|
139878
|
+
return validation.score >= 60 ? 0 : 1;
|
|
139879
|
+
}
|
|
139880
|
+
console.log(colors.primary(basename6(filePath)));
|
|
139881
|
+
printValidation(validation, this.verbose);
|
|
139882
|
+
console.log("");
|
|
139883
|
+
if (validation.score >= 80) {
|
|
139884
|
+
success(`SKILL.md is compliant (score: ${validation.score}/100)`);
|
|
139885
|
+
} else if (validation.score >= 60) {
|
|
139886
|
+
warn(`SKILL.md needs improvement (score: ${validation.score}/100)`);
|
|
139887
|
+
} else {
|
|
139888
|
+
error(`SKILL.md does not meet minimum standard (score: ${validation.score}/100)`);
|
|
139889
|
+
}
|
|
139890
|
+
return validation.score >= 60 ? 0 : 1;
|
|
139891
|
+
}
|
|
139892
|
+
};
|
|
139893
|
+
var SkillMdInitCommand = class extends Command51 {
|
|
139894
|
+
static paths = [["skillmd", "init"], ["skill-md", "init"]];
|
|
139895
|
+
static usage = Command51.Usage({
|
|
139896
|
+
description: "Create a template SKILL.md in the current directory",
|
|
139897
|
+
examples: [
|
|
139898
|
+
["Create SKILL.md template", "$0 skillmd init"],
|
|
139899
|
+
["Create with custom name", "$0 skillmd init --name my-skill"]
|
|
139900
|
+
]
|
|
139901
|
+
});
|
|
139902
|
+
name = Option49.String("--name,-n", {
|
|
139903
|
+
description: "Skill name"
|
|
139904
|
+
});
|
|
139905
|
+
force = Option49.Boolean("--force,-f", false, {
|
|
139906
|
+
description: "Overwrite existing SKILL.md"
|
|
139907
|
+
});
|
|
139908
|
+
async execute() {
|
|
139909
|
+
const outputPath = join21(process.cwd(), "SKILL.md");
|
|
139910
|
+
if (existsSync22(outputPath) && !this.force) {
|
|
139911
|
+
warn("SKILL.md already exists");
|
|
139912
|
+
console.log(colors.muted("Use --force to overwrite"));
|
|
139913
|
+
return 1;
|
|
139914
|
+
}
|
|
139915
|
+
const skillName = this.name || basename6(process.cwd());
|
|
139916
|
+
const formattedName = skillName.split("-").map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
|
|
139917
|
+
const template = [
|
|
139918
|
+
"---",
|
|
139919
|
+
`name: ${skillName}`,
|
|
139920
|
+
"description: What this skill does and when to use it",
|
|
139921
|
+
'version: "1.0"',
|
|
139922
|
+
"license: MIT",
|
|
139923
|
+
"tags: [general]",
|
|
139924
|
+
"metadata:",
|
|
139925
|
+
" author: your-name",
|
|
139926
|
+
"---",
|
|
139927
|
+
"",
|
|
139928
|
+
`# ${formattedName}`,
|
|
139929
|
+
"",
|
|
139930
|
+
"Brief description of what this skill provides to AI coding agents.",
|
|
139931
|
+
"",
|
|
139932
|
+
"## Triggers when:",
|
|
139933
|
+
`- User asks about ${skillName} related tasks`,
|
|
139934
|
+
`- Project contains ${skillName} configuration files`,
|
|
139935
|
+
`- Code changes involve ${skillName} patterns`,
|
|
139936
|
+
"",
|
|
139937
|
+
"## Capabilities:",
|
|
139938
|
+
`- Provides best practices for ${skillName}`,
|
|
139939
|
+
"- Generates boilerplate code and configurations",
|
|
139940
|
+
"- Validates existing implementations",
|
|
139941
|
+
"- Suggests improvements and optimizations",
|
|
139942
|
+
"",
|
|
139943
|
+
"## Steps",
|
|
139944
|
+
"1. First step the AI agent should take",
|
|
139945
|
+
"2. Second step with specific instructions",
|
|
139946
|
+
"3. Third step with expected outcome",
|
|
139947
|
+
"",
|
|
139948
|
+
"## Examples",
|
|
139949
|
+
"",
|
|
139950
|
+
"```",
|
|
139951
|
+
"Example code or configuration here",
|
|
139952
|
+
"```",
|
|
139953
|
+
""
|
|
139954
|
+
].join("\n");
|
|
139955
|
+
writeFileSync11(outputPath, template);
|
|
139956
|
+
success(`Created SKILL.md for "${skillName}"`);
|
|
139957
|
+
console.log("");
|
|
139958
|
+
console.log(colors.muted("Next steps:"));
|
|
139959
|
+
console.log(` ${colors.cyan("1.")} Edit SKILL.md with your skill instructions`);
|
|
139960
|
+
console.log(` ${colors.cyan("2.")} Run ${colors.cyan("skillkit skillmd validate")} to check compliance`);
|
|
139961
|
+
console.log(` ${colors.cyan("3.")} Run ${colors.cyan("skillkit publish submit")} to share with the marketplace`);
|
|
139962
|
+
return 0;
|
|
139963
|
+
}
|
|
139964
|
+
};
|
|
139965
|
+
var SkillMdCheckCommand = class extends Command51 {
|
|
139966
|
+
static paths = [["skillmd", "check"], ["skill-md", "check"]];
|
|
139967
|
+
static usage = Command51.Usage({
|
|
139968
|
+
description: "Check all SKILL.md files in the project for compliance",
|
|
139969
|
+
examples: [
|
|
139970
|
+
["Check current directory", "$0 skillmd check"],
|
|
139971
|
+
["Check specific directory", "$0 skillmd check ./skills"]
|
|
139972
|
+
]
|
|
139973
|
+
});
|
|
139974
|
+
targetPath = Option49.String({ required: false, name: "path" });
|
|
139975
|
+
verbose = Option49.Boolean("--verbose,-v", false, {
|
|
139976
|
+
description: "Show detailed validation results"
|
|
139977
|
+
});
|
|
139978
|
+
async execute() {
|
|
139979
|
+
const targetPath = resolve22(this.targetPath || process.cwd());
|
|
139980
|
+
header("SKILL.md Compliance Check");
|
|
139981
|
+
const s = spinner2();
|
|
139982
|
+
s.start("Scanning for SKILL.md files...");
|
|
139983
|
+
const skillMdFiles = this.findSkillMdFiles(targetPath);
|
|
139984
|
+
s.stop(`Found ${skillMdFiles.length} SKILL.md file(s)`);
|
|
139985
|
+
if (skillMdFiles.length === 0) {
|
|
139986
|
+
warn("No SKILL.md files found");
|
|
139987
|
+
console.log(colors.muted(`Searched: ${targetPath}`));
|
|
139988
|
+
console.log("");
|
|
139989
|
+
console.log(colors.muted("Create one with:"));
|
|
139990
|
+
console.log(` ${colors.cyan("skillkit skillmd init")}`);
|
|
139991
|
+
return 0;
|
|
139992
|
+
}
|
|
139993
|
+
const validations = skillMdFiles.map((f) => validateSkillMd(f));
|
|
139994
|
+
validations.sort((a, b) => b.score - a.score);
|
|
139995
|
+
console.log("");
|
|
139996
|
+
for (const validation of validations) {
|
|
139997
|
+
const relativePath = relative(targetPath, validation.path);
|
|
139998
|
+
const scoreColor = validation.score >= 80 ? colors.success : validation.score >= 60 ? colors.warning : colors.error;
|
|
139999
|
+
console.log(`${scoreColor(symbols.bullet)} ${colors.primary(relativePath)} ${colors.muted(`(${validation.score}/100)`)}`);
|
|
140000
|
+
if (this.verbose) {
|
|
140001
|
+
printValidation(validation, true);
|
|
140002
|
+
console.log("");
|
|
140003
|
+
}
|
|
140004
|
+
}
|
|
140005
|
+
console.log("");
|
|
140006
|
+
const passing = validations.filter((v) => v.score >= 60).length;
|
|
140007
|
+
const failing = validations.filter((v) => v.score < 60).length;
|
|
140008
|
+
const avgScore = Math.round(validations.reduce((sum, v) => sum + v.score, 0) / validations.length);
|
|
140009
|
+
console.log(colors.muted("Summary:"));
|
|
140010
|
+
console.log(` ${colors.muted("Total:")} ${validations.length}`);
|
|
140011
|
+
console.log(` ${colors.success(symbols.success)} Passing (60+): ${passing}`);
|
|
140012
|
+
if (failing > 0) {
|
|
140013
|
+
console.log(` ${colors.error(symbols.error)} Failing: ${failing}`);
|
|
140014
|
+
}
|
|
140015
|
+
console.log(` ${colors.muted("Average score:")} ${avgScore}/100`);
|
|
140016
|
+
console.log("");
|
|
140017
|
+
if (failing > 0) {
|
|
140018
|
+
error(`${failing} SKILL.md file(s) below minimum standard`);
|
|
140019
|
+
return 1;
|
|
140020
|
+
}
|
|
140021
|
+
success("All SKILL.md files are compliant");
|
|
140022
|
+
return 0;
|
|
140023
|
+
}
|
|
140024
|
+
findSkillMdFiles(dir) {
|
|
140025
|
+
const results = [];
|
|
140026
|
+
const directFile = join21(dir, "SKILL.md");
|
|
140027
|
+
if (existsSync22(directFile)) results.push(directFile);
|
|
140028
|
+
const searchDirs = [
|
|
140029
|
+
join21(dir, "skills"),
|
|
140030
|
+
join21(dir, ".claude", "skills"),
|
|
140031
|
+
join21(dir, ".cursor", "skills"),
|
|
140032
|
+
join21(dir, ".codex", "skills"),
|
|
140033
|
+
join21(dir, ".github", "skills")
|
|
140034
|
+
];
|
|
140035
|
+
for (const searchDir of searchDirs) {
|
|
140036
|
+
if (!existsSync22(searchDir)) continue;
|
|
140037
|
+
this.scanDir(searchDir, results, 0);
|
|
140038
|
+
}
|
|
140039
|
+
try {
|
|
140040
|
+
const entries = readdirSync4(dir, { withFileTypes: true });
|
|
140041
|
+
for (const entry of entries) {
|
|
140042
|
+
if (!entry.isDirectory()) continue;
|
|
140043
|
+
if (entry.name.startsWith(".") || entry.name === "node_modules") continue;
|
|
140044
|
+
const entrySkillMd = join21(dir, entry.name, "SKILL.md");
|
|
140045
|
+
if (existsSync22(entrySkillMd) && !results.includes(entrySkillMd)) {
|
|
140046
|
+
results.push(entrySkillMd);
|
|
140047
|
+
}
|
|
140048
|
+
}
|
|
140049
|
+
} catch {
|
|
140050
|
+
}
|
|
140051
|
+
return results;
|
|
140052
|
+
}
|
|
140053
|
+
scanDir(dir, results, depth) {
|
|
140054
|
+
if (depth > 3) return;
|
|
140055
|
+
try {
|
|
140056
|
+
const entries = readdirSync4(dir, { withFileTypes: true });
|
|
140057
|
+
for (const entry of entries) {
|
|
140058
|
+
const entryPath = join21(dir, entry.name);
|
|
140059
|
+
if (entry.isFile() && entry.name === "SKILL.md") {
|
|
140060
|
+
if (!results.includes(entryPath)) results.push(entryPath);
|
|
140061
|
+
}
|
|
140062
|
+
if (entry.isDirectory() && !entry.name.startsWith(".") && entry.name !== "node_modules") {
|
|
140063
|
+
this.scanDir(entryPath, results, depth + 1);
|
|
140064
|
+
}
|
|
140065
|
+
}
|
|
140066
|
+
} catch {
|
|
140067
|
+
}
|
|
140068
|
+
}
|
|
140069
|
+
};
|
|
140070
|
+
|
|
140071
|
+
// src/commands/serve.ts
|
|
140072
|
+
init_onboarding();
|
|
140073
|
+
import { Command as Command52, Option as Option50 } from "clipanion";
|
|
140074
|
+
var ServeCommand = class extends Command52 {
|
|
140075
|
+
static paths = [["serve"], ["server"]];
|
|
140076
|
+
static usage = Command52.Usage({
|
|
140077
|
+
description: "Start the SkillKit REST API server for skill discovery",
|
|
140078
|
+
details: `
|
|
140079
|
+
Launches a local HTTP server that exposes the SkillKit skill catalog
|
|
140080
|
+
via a REST API. Useful for integrating with other tools, building
|
|
140081
|
+
custom UIs, or enabling agent-native skill discovery.
|
|
140082
|
+
`,
|
|
140083
|
+
examples: [
|
|
140084
|
+
["Start server on default port", "$0 serve"],
|
|
140085
|
+
["Start on custom port", "$0 serve --port 8080"],
|
|
140086
|
+
["Start with custom CORS", '$0 serve --cors "http://localhost:3000"']
|
|
140087
|
+
]
|
|
140088
|
+
});
|
|
140089
|
+
port = Option50.String("--port,-p", "3737", {
|
|
140090
|
+
description: "Port to listen on"
|
|
140091
|
+
});
|
|
140092
|
+
host = Option50.String("--host,-H", "0.0.0.0", {
|
|
140093
|
+
description: "Host to bind to"
|
|
140094
|
+
});
|
|
140095
|
+
corsOrigin = Option50.String("--cors", "*", {
|
|
140096
|
+
description: "CORS allowed origin"
|
|
140097
|
+
});
|
|
140098
|
+
cacheTtl = Option50.String("--cache-ttl", "86400000", {
|
|
140099
|
+
description: "Cache TTL in milliseconds"
|
|
140100
|
+
});
|
|
140101
|
+
async execute() {
|
|
140102
|
+
header("SkillKit API Server");
|
|
140103
|
+
const skills = (skills_default.skills || []).map((skill) => ({
|
|
140104
|
+
name: skill.name,
|
|
140105
|
+
description: skill.description,
|
|
140106
|
+
source: skill.source || "",
|
|
140107
|
+
repo: skill.repo,
|
|
140108
|
+
tags: skill.tags,
|
|
140109
|
+
category: skill.category
|
|
140110
|
+
}));
|
|
140111
|
+
step(`Loading ${skills.length} skills from marketplace`);
|
|
140112
|
+
const portNum = parseInt(this.port, 10) || 3737;
|
|
140113
|
+
const cacheTtlMs = parseInt(this.cacheTtl, 10) || 864e5;
|
|
140114
|
+
try {
|
|
140115
|
+
const { startServer } = await import("@skillkit/api");
|
|
140116
|
+
await startServer({
|
|
140117
|
+
port: portNum,
|
|
140118
|
+
host: this.host,
|
|
140119
|
+
corsOrigin: this.corsOrigin,
|
|
140120
|
+
cacheTtlMs,
|
|
140121
|
+
skills
|
|
140122
|
+
});
|
|
140123
|
+
step(`Server running at ${colors.cyan(`http://${this.host}:${portNum}`)}`);
|
|
140124
|
+
console.log("");
|
|
140125
|
+
console.log(colors.muted("Endpoints:"));
|
|
140126
|
+
console.log(colors.muted(` GET /health - Server health check`));
|
|
140127
|
+
console.log(colors.muted(` GET /search?q=... - Search skills`));
|
|
140128
|
+
console.log(colors.muted(` POST /search - Search with filters`));
|
|
140129
|
+
console.log(colors.muted(` GET /skills/:o/:r/:id - Get specific skill`));
|
|
140130
|
+
console.log(colors.muted(` GET /trending - Top skills`));
|
|
140131
|
+
console.log(colors.muted(` GET /categories - Skill categories`));
|
|
140132
|
+
console.log(colors.muted(` GET /cache/stats - Cache statistics`));
|
|
140133
|
+
console.log("");
|
|
140134
|
+
console.log(colors.muted("Press Ctrl+C to stop"));
|
|
140135
|
+
await new Promise(() => {
|
|
140136
|
+
});
|
|
140137
|
+
} catch (err) {
|
|
140138
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
140139
|
+
console.error(colors.error(`Failed to start server: ${message}`));
|
|
140140
|
+
return 1;
|
|
140141
|
+
}
|
|
140142
|
+
return 0;
|
|
140143
|
+
}
|
|
140144
|
+
};
|
|
140145
|
+
|
|
139412
140146
|
// src/index.ts
|
|
139413
140147
|
init_helpers();
|
|
139414
140148
|
export {
|
|
@@ -139478,11 +140212,13 @@ export {
|
|
|
139478
140212
|
ProfileRemoveCommand,
|
|
139479
140213
|
PublishCommand,
|
|
139480
140214
|
PublishSubmitCommand,
|
|
140215
|
+
QuickCommand,
|
|
139481
140216
|
ReadCommand,
|
|
139482
140217
|
RecommendCommand,
|
|
139483
140218
|
RemoveCommand,
|
|
139484
140219
|
ResumeCommand,
|
|
139485
140220
|
RunCommand,
|
|
140221
|
+
ServeCommand,
|
|
139486
140222
|
SessionCommand,
|
|
139487
140223
|
SessionCompleteCommand,
|
|
139488
140224
|
SessionInProgressCommand,
|
|
@@ -139492,6 +140228,9 @@ export {
|
|
|
139492
140228
|
SessionStartCommand,
|
|
139493
140229
|
SessionStatusCommand,
|
|
139494
140230
|
SettingsCommand,
|
|
140231
|
+
SkillMdCheckCommand,
|
|
140232
|
+
SkillMdInitCommand,
|
|
140233
|
+
SkillMdValidateCommand,
|
|
139495
140234
|
StatusCommand,
|
|
139496
140235
|
SyncCommand,
|
|
139497
140236
|
TeamCommand,
|