@skillkit/cli 1.8.0 → 1.9.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.js CHANGED
@@ -1,5 +1,11 @@
1
1
  var __defProp = Object.defineProperty;
2
2
  var __getOwnPropNames = Object.getOwnPropertyNames;
3
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
4
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
5
+ }) : x)(function(x) {
6
+ if (typeof require !== "undefined") return require.apply(this, arguments);
7
+ throw Error('Dynamic require of "' + x + '" is not supported');
8
+ });
3
9
  var __esm = (fn, res) => function __init() {
4
10
  return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
5
11
  };
@@ -1215,7 +1221,7 @@ init_onboarding();
1215
1221
  import { existsSync as existsSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2, mkdirSync as mkdirSync2 } from "fs";
1216
1222
  import { dirname } from "path";
1217
1223
  import { Command as Command3, Option as Option3 } from "clipanion";
1218
- import { loadConfig as loadConfig2, findAllSkills as findAllSkills2 } from "@skillkit/core";
1224
+ import { findAllSkills as findAllSkills2 } from "@skillkit/core";
1219
1225
  import { getAdapter as getAdapter2, detectAgent as detectAgent2, getAllAdapters } from "@skillkit/agents";
1220
1226
  var SyncCommand = class extends Command3 {
1221
1227
  static paths = [["sync"], ["s"]];
@@ -1255,8 +1261,7 @@ var SyncCommand = class extends Command3 {
1255
1261
  agentType = this.agent;
1256
1262
  } else if (isInteractive) {
1257
1263
  s.start("Detecting agent...");
1258
- const config2 = loadConfig2();
1259
- const detected = config2.agent || await detectAgent2();
1264
+ const detected = await detectAgent2();
1260
1265
  s.stop(`Detected: ${formatAgent(detected)}`);
1261
1266
  const allAgents = getAllAdapters().map((a) => a.type);
1262
1267
  const agentResult = await select2({
@@ -1274,8 +1279,7 @@ var SyncCommand = class extends Command3 {
1274
1279
  }
1275
1280
  agentType = agentResult;
1276
1281
  } else {
1277
- const config2 = loadConfig2();
1278
- agentType = config2.agent || await detectAgent2();
1282
+ agentType = await detectAgent2();
1279
1283
  }
1280
1284
  const adapter = getAdapter2(agentType);
1281
1285
  const outputPath = this.output || getAgentConfigPath(agentType);
@@ -1650,10 +1654,13 @@ init_helpers();
1650
1654
  init_onboarding();
1651
1655
  import { existsSync as existsSync5, mkdirSync as mkdirSync3, cpSync, rmSync as rmSync2, symlinkSync } from "fs";
1652
1656
  import { join as join3 } from "path";
1657
+ import { execFile } from "child_process";
1658
+ import { promisify } from "util";
1653
1659
  import { Command as Command7, Option as Option7 } from "clipanion";
1654
1660
  import { detectProvider, isLocalPath, getProvider, evaluateSkillDirectory as evaluateSkillDirectory2 } from "@skillkit/core";
1655
1661
  import { isPathInside } from "@skillkit/core";
1656
1662
  import { getAdapter as getAdapter4, detectAgent as detectAgent4, getAllAdapters as getAllAdapters3 } from "@skillkit/agents";
1663
+ var execFileAsync = promisify(execFile);
1657
1664
  var InstallCommand = class extends Command7 {
1658
1665
  static paths = [["install"], ["i"], ["add"]];
1659
1666
  static usage = Command7.Usage({
@@ -1662,7 +1669,8 @@ var InstallCommand = class extends Command7 {
1662
1669
  ["Install from GitHub", "$0 install owner/repo"],
1663
1670
  ["Install from GitLab", "$0 install gitlab:owner/repo"],
1664
1671
  ["Install from Bitbucket", "$0 install bitbucket:owner/repo"],
1665
- ["Install specific skills (CI/CD)", "$0 install owner/repo --skills=pdf,xlsx"],
1672
+ ["Install specific skill", "$0 install owner/repo --skill=pdf"],
1673
+ ["Install multiple skills (CI/CD)", "$0 install owner/repo --skills=pdf,xlsx"],
1666
1674
  ["Install all skills non-interactively", "$0 install owner/repo --all"],
1667
1675
  ["Install from local path", "$0 install ./my-skills"],
1668
1676
  ["Install globally", "$0 install owner/repo --global"],
@@ -1671,7 +1679,7 @@ var InstallCommand = class extends Command7 {
1671
1679
  ]
1672
1680
  });
1673
1681
  source = Option7.String({ required: true });
1674
- skills = Option7.String("--skills,-s", {
1682
+ skills = Option7.String("--skills,--skill,-s", {
1675
1683
  description: "Comma-separated list of skills to install (non-interactive)"
1676
1684
  });
1677
1685
  all = Option7.Boolean("--all,-a", false, {
@@ -1740,7 +1748,7 @@ var InstallCommand = class extends Command7 {
1740
1748
  }
1741
1749
  console.log("");
1742
1750
  console.log(colors.muted(`Total: ${discoveredSkills.length} skill(s)`));
1743
- console.log(colors.muted("To install: skillkit install <source> --skills=skill1,skill2"));
1751
+ console.log(colors.muted("To install: skillkit install <source> --skill=name"));
1744
1752
  }
1745
1753
  const cleanupPath2 = result.tempRoot || result.path;
1746
1754
  if (!isLocalPath(this.source) && cleanupPath2 && existsSync5(cleanupPath2)) {
@@ -1880,6 +1888,19 @@ var InstallCommand = class extends Command7 {
1880
1888
  if (isSymlinkMode && primaryPath === null) {
1881
1889
  primaryPath = targetPath;
1882
1890
  }
1891
+ const packageJsonPath = join3(targetPath, "package.json");
1892
+ if (existsSync5(packageJsonPath)) {
1893
+ s.stop(`Installed ${skillName} to ${adapter.name}`);
1894
+ s.start(`Installing npm dependencies for ${skillName}...`);
1895
+ try {
1896
+ await execFileAsync("npm", ["install", "--production"], { cwd: targetPath });
1897
+ s.stop(`Installed dependencies for ${skillName}`);
1898
+ } catch (npmErr) {
1899
+ s.stop(colors.warning(`Dependencies failed for ${skillName}`));
1900
+ console.log(colors.muted("Run manually: npm install in " + targetPath));
1901
+ }
1902
+ s.start(`Finishing ${skillName} installation...`);
1903
+ }
1883
1904
  }
1884
1905
  const metadata = {
1885
1906
  name: skillName,
@@ -3338,6 +3359,7 @@ import { resolve as resolve4 } from "path";
3338
3359
  import {
3339
3360
  ContextManager as ContextManager2,
3340
3361
  RecommendationEngine,
3362
+ ReasoningRecommendationEngine,
3341
3363
  buildSkillIndex,
3342
3364
  saveIndex,
3343
3365
  loadIndex as loadIndexFromCache,
@@ -3416,6 +3438,18 @@ var RecommendCommand = class extends Command15 {
3416
3438
  quiet = Option14.Boolean("--quiet,-q", false, {
3417
3439
  description: "Minimal output"
3418
3440
  });
3441
+ // Explain mode (reasoning-based recommendations)
3442
+ explain = Option14.Boolean("--explain,-e", false, {
3443
+ description: "Show detailed explanations for recommendations (uses reasoning engine)"
3444
+ });
3445
+ // Reasoning mode
3446
+ reasoning = Option14.Boolean("--reasoning,-r", false, {
3447
+ description: "Use LLM-based reasoning for recommendations"
3448
+ });
3449
+ // Show tree path
3450
+ showPath = Option14.Boolean("--show-path", false, {
3451
+ description: "Show category path for each recommendation"
3452
+ });
3419
3453
  async execute() {
3420
3454
  const targetPath = resolve4(this.projectPath || process.cwd());
3421
3455
  if (this.update) {
@@ -3437,6 +3471,9 @@ var RecommendCommand = class extends Command15 {
3437
3471
  this.showProjectProfile(profile);
3438
3472
  return 0;
3439
3473
  }
3474
+ if (this.explain || this.reasoning || this.showPath) {
3475
+ return await this.handleReasoningRecommendations(profile, index);
3476
+ }
3440
3477
  const engine = new RecommendationEngine();
3441
3478
  engine.loadIndex(index);
3442
3479
  const searchQuery = this.search || this.task;
@@ -3457,6 +3494,53 @@ var RecommendCommand = class extends Command15 {
3457
3494
  this.displayRecommendations(result.recommendations, profile, result.totalSkillsScanned);
3458
3495
  return 0;
3459
3496
  }
3497
+ async handleReasoningRecommendations(profile, index) {
3498
+ const s = !this.quiet && !this.json ? spinner2() : null;
3499
+ s?.start("Analyzing with reasoning engine...");
3500
+ try {
3501
+ const engine = new ReasoningRecommendationEngine();
3502
+ engine.loadIndex(index);
3503
+ await engine.initReasoning();
3504
+ const result = await engine.recommendWithReasoning(profile, {
3505
+ limit: this.limit ? parseInt(this.limit, 10) : 10,
3506
+ minScore: this.minScore ? parseInt(this.minScore, 10) : 30,
3507
+ categories: this.category,
3508
+ excludeInstalled: !this.includeInstalled,
3509
+ includeReasons: this.verbose,
3510
+ reasoning: this.reasoning,
3511
+ explainResults: this.explain,
3512
+ useTree: true
3513
+ });
3514
+ s?.stop("Analysis complete");
3515
+ if (this.json) {
3516
+ console.log(JSON.stringify(result, null, 2));
3517
+ return 0;
3518
+ }
3519
+ this.displayExplainedRecommendations(
3520
+ result.recommendations,
3521
+ profile,
3522
+ result.totalSkillsScanned,
3523
+ result.reasoningSummary
3524
+ );
3525
+ return 0;
3526
+ } catch (err) {
3527
+ s?.stop(colors.error("Reasoning analysis failed"));
3528
+ console.log(colors.muted(err instanceof Error ? err.message : String(err)));
3529
+ console.log(colors.muted("Falling back to standard recommendations..."));
3530
+ console.log("");
3531
+ const engine = new RecommendationEngine();
3532
+ engine.loadIndex(index);
3533
+ const result = engine.recommend(profile, {
3534
+ limit: this.limit ? parseInt(this.limit, 10) : 10,
3535
+ minScore: this.minScore ? parseInt(this.minScore, 10) : 30,
3536
+ categories: this.category,
3537
+ excludeInstalled: !this.includeInstalled,
3538
+ includeReasons: this.verbose
3539
+ });
3540
+ this.displayRecommendations(result.recommendations, profile, result.totalSkillsScanned);
3541
+ return 0;
3542
+ }
3543
+ }
3460
3544
  async getProjectProfile(projectPath) {
3461
3545
  const manager = new ContextManager2(projectPath);
3462
3546
  let context = manager.get();
@@ -3539,6 +3623,74 @@ var RecommendCommand = class extends Command15 {
3539
3623
  }
3540
3624
  console.log(colors.muted("Install with: skillkit install <source>"));
3541
3625
  }
3626
+ displayExplainedRecommendations(recommendations, profile, totalScanned, reasoningSummary) {
3627
+ this.showProjectProfile(profile);
3628
+ if (reasoningSummary && !this.quiet) {
3629
+ console.log(colors.dim("Reasoning: ") + colors.muted(reasoningSummary));
3630
+ console.log("");
3631
+ }
3632
+ if (recommendations.length === 0) {
3633
+ warn("No matching skills found.");
3634
+ console.log(colors.muted("Try lowering the minimum score with --min-score"));
3635
+ return;
3636
+ }
3637
+ console.log(colors.bold(`Explained Recommendations (${recommendations.length} of ${totalScanned} scanned):`));
3638
+ console.log("");
3639
+ for (const rec of recommendations) {
3640
+ let scoreColor;
3641
+ if (rec.score >= 70) {
3642
+ scoreColor = colors.success;
3643
+ } else if (rec.score >= 50) {
3644
+ scoreColor = colors.warning;
3645
+ } else {
3646
+ scoreColor = colors.muted;
3647
+ }
3648
+ const scoreBar = progressBar(rec.score, 100, 10);
3649
+ const qualityScore = rec.skill.quality ?? null;
3650
+ const qualityDisplay = qualityScore !== null && qualityScore !== void 0 ? ` ${formatQualityBadge(qualityScore)}` : "";
3651
+ console.log(` ${scoreColor(`${rec.score}%`)} ${colors.dim(scoreBar)} ${colors.bold(rec.skill.name)}${qualityDisplay}`);
3652
+ if (this.showPath && rec.treePath && rec.treePath.length > 0) {
3653
+ console.log(` ${colors.accent("Path:")} ${rec.treePath.join(" > ")}`);
3654
+ }
3655
+ if (rec.skill.description) {
3656
+ console.log(` ${colors.muted(truncate3(rec.skill.description, 70))}`);
3657
+ }
3658
+ if (rec.skill.source) {
3659
+ console.log(` ${colors.dim("Source:")} ${rec.skill.source}`);
3660
+ }
3661
+ if (this.explain && rec.explanation) {
3662
+ console.log(colors.dim(" Why this skill:"));
3663
+ if (rec.explanation.matchedBecause.length > 0) {
3664
+ console.log(` ${colors.success("\u251C\u2500")} Matched: ${rec.explanation.matchedBecause.join(", ")}`);
3665
+ }
3666
+ if (rec.explanation.relevantFor.length > 0) {
3667
+ console.log(` ${colors.accent("\u251C\u2500")} Relevant for: ${rec.explanation.relevantFor.join(", ")}`);
3668
+ }
3669
+ if (rec.explanation.confidence) {
3670
+ const confidenceColor = rec.explanation.confidence === "high" ? colors.success : rec.explanation.confidence === "medium" ? colors.warning : colors.muted;
3671
+ console.log(` ${colors.dim("\u2514\u2500")} Confidence: ${confidenceColor(rec.explanation.confidence)}`);
3672
+ }
3673
+ }
3674
+ if (this.verbose && rec.reasons.length > 0) {
3675
+ console.log(colors.dim(" Score breakdown:"));
3676
+ for (const reason of rec.reasons.filter((r) => r.weight > 0)) {
3677
+ console.log(` ${colors.muted(symbols.stepActive)} ${reason.description} (+${reason.weight})`);
3678
+ }
3679
+ if (qualityScore !== null && qualityScore !== void 0) {
3680
+ const grade = getQualityGradeFromScore(qualityScore);
3681
+ console.log(` ${colors.muted(symbols.stepActive)} Quality: ${qualityScore}/100 (${grade})`);
3682
+ }
3683
+ }
3684
+ if (rec.warnings.length > 0) {
3685
+ for (const warning of rec.warnings) {
3686
+ console.log(` ${colors.warning(symbols.warning)} ${warning}`);
3687
+ }
3688
+ }
3689
+ console.log("");
3690
+ }
3691
+ console.log(colors.muted("Install with: skillkit install <source>"));
3692
+ console.log(colors.muted("More details: skillkit recommend --explain --verbose"));
3693
+ }
3542
3694
  handleSearch(engine, query) {
3543
3695
  if (!this.quiet && !this.json) {
3544
3696
  header(`Search: "${query}"`);
@@ -5506,12 +5658,12 @@ ${learning.title}
5506
5658
  }
5507
5659
  const outputPath = this.output || `.skillkit/exports/${skillName}/SKILL.md`;
5508
5660
  const { dirname: dirname7 } = await import("path");
5509
- const { existsSync: existsSync21, mkdirSync: mkdirSync9, writeFileSync: writeFileSync10 } = await import("fs");
5661
+ const { existsSync: existsSync21, mkdirSync: mkdirSync10, writeFileSync: writeFileSync11 } = await import("fs");
5510
5662
  const outputDir = dirname7(outputPath);
5511
5663
  if (!existsSync21(outputDir)) {
5512
- mkdirSync9(outputDir, { recursive: true });
5664
+ mkdirSync10(outputDir, { recursive: true });
5513
5665
  }
5514
- writeFileSync10(outputPath, skillContent, "utf-8");
5666
+ writeFileSync11(outputPath, skillContent, "utf-8");
5515
5667
  console.log(chalk18.green(`\u2713 Exported learning as skill: ${skillName}`));
5516
5668
  console.log(chalk18.gray(` Path: ${outputPath}`));
5517
5669
  return 0;
@@ -5527,8 +5679,8 @@ ${learning.title}
5527
5679
  return 1;
5528
5680
  }
5529
5681
  const { existsSync: existsSync21, readFileSync: readFileSync11 } = await import("fs");
5530
- const { resolve: resolve20 } = await import("path");
5531
- const fullPath = resolve20(inputPath);
5682
+ const { resolve: resolve21 } = await import("path");
5683
+ const fullPath = resolve21(inputPath);
5532
5684
  if (!existsSync21(fullPath)) {
5533
5685
  console.error(chalk18.red(`File not found: ${fullPath}`));
5534
5686
  return 1;
@@ -5786,7 +5938,7 @@ ${learning.title}
5786
5938
  // src/commands/settings.ts
5787
5939
  import { Command as Command27, Option as Option26 } from "clipanion";
5788
5940
  import chalk19 from "chalk";
5789
- import { loadConfig as loadConfig3, saveConfig } from "@skillkit/core";
5941
+ import { loadConfig as loadConfig2, saveConfig } from "@skillkit/core";
5790
5942
  var VALID_AGENTS = [
5791
5943
  "claude-code",
5792
5944
  "cursor",
@@ -5846,7 +5998,7 @@ var SettingsCommand = class extends Command27 {
5846
5998
  description: "Reset all settings to defaults"
5847
5999
  });
5848
6000
  async execute() {
5849
- const config = loadConfig3(this.global);
6001
+ const config = loadConfig2(this.global);
5850
6002
  if (this.reset) {
5851
6003
  const defaultConfig = {
5852
6004
  version: 1,
@@ -6608,14 +6760,14 @@ var TeamCommand = class extends Command29 {
6608
6760
  }
6609
6761
  const projectPath = process.cwd();
6610
6762
  const bundlePath = join12(projectPath, ".skillkit", "bundles", `${this.name}.json`);
6611
- const { existsSync: existsSync21, readFileSync: readFileSync11, writeFileSync: writeFileSync10 } = await import("fs");
6763
+ const { existsSync: existsSync21, readFileSync: readFileSync11, writeFileSync: writeFileSync11 } = await import("fs");
6612
6764
  if (!existsSync21(bundlePath)) {
6613
6765
  this.context.stderr.write(chalk21.red(`Bundle "${this.name}" not found. Create it first with bundle-create.
6614
6766
  `));
6615
6767
  return 1;
6616
6768
  }
6617
6769
  const content = readFileSync11(bundlePath, "utf-8");
6618
- writeFileSync10(this.output, content, "utf-8");
6770
+ writeFileSync11(this.output, content, "utf-8");
6619
6771
  this.context.stdout.write(chalk21.green(`\u2713 Bundle exported to: ${this.output}
6620
6772
  `));
6621
6773
  return 0;
@@ -6806,8 +6958,8 @@ var PluginCommand = class extends Command30 {
6806
6958
  if (!existsSync15(pluginsDir)) {
6807
6959
  mkdirSync7(pluginsDir, { recursive: true });
6808
6960
  }
6809
- const { statSync: statSync3 } = await import("fs");
6810
- const sourceStat = statSync3(resolvedSource);
6961
+ const { statSync: statSync4 } = await import("fs");
6962
+ const sourceStat = statSync4(resolvedSource);
6811
6963
  if (sourceStat.isDirectory()) {
6812
6964
  cpSync3(resolvedSource, targetDir, { recursive: true });
6813
6965
  } else {
@@ -9148,27 +9300,245 @@ Recent Errors (${stats.recentErrors.length}):`));
9148
9300
  };
9149
9301
 
9150
9302
  // src/commands/publish.ts
9151
- import { existsSync as existsSync17, readFileSync as readFileSync9 } from "fs";
9152
- import { join as join16, basename as basename4, dirname as dirname6 } from "path";
9153
- import { execSync } from "child_process";
9303
+ import { existsSync as existsSync17, readFileSync as readFileSync9, mkdirSync as mkdirSync8, writeFileSync as writeFileSync8, readdirSync as readdirSync3, statSync as statSync3 } from "fs";
9304
+ import { join as join16, basename as basename4, dirname as dirname6, resolve as resolve18 } from "path";
9154
9305
  import chalk27 from "chalk";
9155
9306
  import { Command as Command37, Option as Option36 } from "clipanion";
9307
+ import { generateWellKnownIndex } from "@skillkit/core";
9308
+ function sanitizeSkillName(name) {
9309
+ if (!name || typeof name !== "string") return null;
9310
+ const base = basename4(name);
9311
+ if (base !== name || name.includes("..") || name.includes("/") || name.includes("\\")) {
9312
+ return null;
9313
+ }
9314
+ if (!/^[a-zA-Z0-9._-]+$/.test(name)) {
9315
+ return null;
9316
+ }
9317
+ return name;
9318
+ }
9156
9319
  var PublishCommand = class extends Command37 {
9157
9320
  static paths = [["publish"]];
9158
9321
  static usage = Command37.Usage({
9159
- description: "Publish your skill to the SkillKit marketplace",
9322
+ description: "Generate well-known skills structure for hosting",
9323
+ details: `
9324
+ This command generates the RFC 8615 well-known URI structure for hosting skills.
9325
+
9326
+ The output includes:
9327
+ - .well-known/skills/index.json - Skill manifest for auto-discovery
9328
+ - .well-known/skills/{skill-name}/SKILL.md - Individual skill files
9329
+
9330
+ Users can then install skills via: skillkit add https://your-domain.com
9331
+ `,
9160
9332
  examples: [
9161
- ["Publish skill from current directory", "$0 publish"],
9162
- ["Publish skill from specific path", "$0 publish ./my-skill"],
9163
- ["Publish with custom name", "$0 publish --name my-awesome-skill"]
9333
+ ["Generate from current directory", "$0 publish"],
9334
+ ["Generate from specific path", "$0 publish ./my-skills"],
9335
+ ["Generate to custom output directory", "$0 publish --output ./public"],
9336
+ ["Preview without writing", "$0 publish --dry-run"]
9337
+ ]
9338
+ });
9339
+ skillPath = Option36.String({ required: false, name: "path" });
9340
+ output = Option36.String("--output,-o", {
9341
+ description: "Output directory for well-known structure (default: current directory)"
9342
+ });
9343
+ dryRun = Option36.Boolean("--dry-run,-n", false, {
9344
+ description: "Show what would be generated without writing files"
9345
+ });
9346
+ async execute() {
9347
+ const basePath = this.skillPath || process.cwd();
9348
+ const outputDir = this.output || basePath;
9349
+ console.log(chalk27.cyan("Generating well-known skills structure...\n"));
9350
+ const discoveredSkills = this.discoverSkills(basePath);
9351
+ if (discoveredSkills.length === 0) {
9352
+ console.error(chalk27.red("No skills found"));
9353
+ console.error(chalk27.dim("Skills must contain a SKILL.md file with frontmatter"));
9354
+ return 1;
9355
+ }
9356
+ console.log(chalk27.white(`Found ${discoveredSkills.length} skill(s):
9357
+ `));
9358
+ const wellKnownSkills = [];
9359
+ const validSkills = [];
9360
+ for (const skill of discoveredSkills) {
9361
+ const safeName = sanitizeSkillName(skill.name);
9362
+ if (!safeName) {
9363
+ console.log(chalk27.yellow(` ${chalk27.yellow("\u26A0")} Skipping "${skill.name}" (invalid name - must be alphanumeric with hyphens/underscores)`));
9364
+ continue;
9365
+ }
9366
+ const files = this.getSkillFiles(skill.path);
9367
+ console.log(chalk27.dim(` ${chalk27.green("\u25CF")} ${safeName}`));
9368
+ console.log(chalk27.dim(` Description: ${skill.description || "No description"}`));
9369
+ console.log(chalk27.dim(` Files: ${files.join(", ")}`));
9370
+ validSkills.push({ name: skill.name, safeName, description: skill.description, path: skill.path });
9371
+ wellKnownSkills.push({
9372
+ name: safeName,
9373
+ description: skill.description,
9374
+ files
9375
+ });
9376
+ }
9377
+ if (validSkills.length === 0) {
9378
+ console.error(chalk27.red("\nNo valid skills to publish"));
9379
+ return 1;
9380
+ }
9381
+ console.log("");
9382
+ if (this.dryRun) {
9383
+ console.log(chalk27.yellow("Dry run - not writing files\n"));
9384
+ console.log(chalk27.white("Would generate:"));
9385
+ console.log(chalk27.dim(` ${outputDir}/.well-known/skills/index.json`));
9386
+ for (const skill of wellKnownSkills) {
9387
+ for (const file of skill.files) {
9388
+ console.log(chalk27.dim(` ${outputDir}/.well-known/skills/${skill.name}/${file}`));
9389
+ }
9390
+ }
9391
+ console.log("");
9392
+ console.log(chalk27.white("index.json preview:"));
9393
+ console.log(JSON.stringify(generateWellKnownIndex(wellKnownSkills), null, 2));
9394
+ return 0;
9395
+ }
9396
+ const wellKnownDir = join16(outputDir, ".well-known", "skills");
9397
+ mkdirSync8(wellKnownDir, { recursive: true });
9398
+ for (const skill of validSkills) {
9399
+ const skillDir = join16(wellKnownDir, skill.safeName);
9400
+ const resolvedSkillDir = resolve18(skillDir);
9401
+ const resolvedWellKnownDir = resolve18(wellKnownDir);
9402
+ if (!resolvedSkillDir.startsWith(resolvedWellKnownDir)) {
9403
+ console.log(chalk27.yellow(` Skipping "${skill.name}" (path traversal detected)`));
9404
+ continue;
9405
+ }
9406
+ mkdirSync8(skillDir, { recursive: true });
9407
+ const files = this.getSkillFiles(skill.path);
9408
+ for (const file of files) {
9409
+ const safeFile = basename4(file);
9410
+ const sourcePath = join16(skill.path, file);
9411
+ const destPath = join16(skillDir, safeFile);
9412
+ const content = readFileSync9(sourcePath, "utf-8");
9413
+ writeFileSync8(destPath, content);
9414
+ }
9415
+ }
9416
+ const index = generateWellKnownIndex(wellKnownSkills);
9417
+ writeFileSync8(join16(wellKnownDir, "index.json"), JSON.stringify(index, null, 2));
9418
+ console.log(chalk27.green("Generated well-known structure:\n"));
9419
+ console.log(chalk27.dim(` ${wellKnownDir}/index.json`));
9420
+ for (const skill of wellKnownSkills) {
9421
+ console.log(chalk27.dim(` ${wellKnownDir}/${skill.name}/`));
9422
+ }
9423
+ console.log("");
9424
+ console.log(chalk27.cyan("Next steps:"));
9425
+ console.log(chalk27.dim(" 1. Deploy the .well-known directory to your web server"));
9426
+ console.log(chalk27.dim(" 2. Users can install via: skillkit add https://your-domain.com"));
9427
+ console.log(chalk27.dim(" 3. Skills auto-discovered from /.well-known/skills/index.json"));
9428
+ return 0;
9429
+ }
9430
+ discoverSkills(basePath) {
9431
+ const skills = [];
9432
+ const skillMdPath = join16(basePath, "SKILL.md");
9433
+ if (existsSync17(skillMdPath)) {
9434
+ const content = readFileSync9(skillMdPath, "utf-8");
9435
+ const frontmatter = this.parseFrontmatter(content);
9436
+ skills.push({
9437
+ name: frontmatter.name || basename4(basePath),
9438
+ description: frontmatter.description,
9439
+ path: basePath
9440
+ });
9441
+ return skills;
9442
+ }
9443
+ const searchDirs = [
9444
+ basePath,
9445
+ join16(basePath, "skills"),
9446
+ join16(basePath, ".claude", "skills")
9447
+ ];
9448
+ for (const searchDir of searchDirs) {
9449
+ if (!existsSync17(searchDir)) continue;
9450
+ const entries = readdirSync3(searchDir);
9451
+ for (const entry of entries) {
9452
+ const entryPath = join16(searchDir, entry);
9453
+ if (!statSync3(entryPath).isDirectory()) continue;
9454
+ const entrySkillMd = join16(entryPath, "SKILL.md");
9455
+ if (existsSync17(entrySkillMd)) {
9456
+ const content = readFileSync9(entrySkillMd, "utf-8");
9457
+ const frontmatter = this.parseFrontmatter(content);
9458
+ skills.push({
9459
+ name: frontmatter.name || entry,
9460
+ description: frontmatter.description,
9461
+ path: entryPath
9462
+ });
9463
+ }
9464
+ }
9465
+ }
9466
+ return skills;
9467
+ }
9468
+ getSkillFiles(skillPath) {
9469
+ const files = [];
9470
+ const entries = readdirSync3(skillPath);
9471
+ for (const entry of entries) {
9472
+ const entryPath = join16(skillPath, entry);
9473
+ if (statSync3(entryPath).isFile()) {
9474
+ if (entry.startsWith(".") || entry === ".skillkit-metadata.json") continue;
9475
+ files.push(entry);
9476
+ }
9477
+ }
9478
+ if (!files.includes("SKILL.md")) {
9479
+ files.unshift("SKILL.md");
9480
+ }
9481
+ return files;
9482
+ }
9483
+ parseFrontmatter(content) {
9484
+ const match = content.match(/^---\r?\n([\s\S]*?)\r?\n---/);
9485
+ if (!match) return {};
9486
+ const frontmatter = {};
9487
+ const lines = match[1].split(/\r?\n/);
9488
+ let inTagsList = false;
9489
+ for (const line of lines) {
9490
+ if (inTagsList) {
9491
+ const tagMatch = line.match(/^\s*-\s*(.+)$/);
9492
+ if (tagMatch) {
9493
+ frontmatter.tags ??= [];
9494
+ frontmatter.tags.push(tagMatch[1].trim().replace(/^["']|["']$/g, ""));
9495
+ continue;
9496
+ }
9497
+ if (line.trim() === "") continue;
9498
+ inTagsList = false;
9499
+ }
9500
+ const colonIdx = line.indexOf(":");
9501
+ if (colonIdx === -1) continue;
9502
+ const key = line.slice(0, colonIdx).trim();
9503
+ const value = line.slice(colonIdx + 1).trim();
9504
+ switch (key) {
9505
+ case "name":
9506
+ frontmatter.name = value.replace(/^["']|["']$/g, "");
9507
+ break;
9508
+ case "description":
9509
+ frontmatter.description = value.replace(/^["']|["']$/g, "");
9510
+ break;
9511
+ case "version":
9512
+ frontmatter.version = value.replace(/^["']|["']$/g, "");
9513
+ break;
9514
+ case "tags":
9515
+ if (value.startsWith("[")) {
9516
+ frontmatter.tags = value.slice(1, -1).split(",").map((t) => t.trim().replace(/^["']|["']$/g, "")).filter((t) => t.length > 0);
9517
+ } else if (value === "") {
9518
+ inTagsList = true;
9519
+ frontmatter.tags = [];
9520
+ }
9521
+ break;
9522
+ }
9523
+ }
9524
+ return frontmatter;
9525
+ }
9526
+ };
9527
+ var PublishSubmitCommand = class extends Command37 {
9528
+ static paths = [["publish", "submit"]];
9529
+ static usage = Command37.Usage({
9530
+ description: "Submit skill to SkillKit marketplace (requires review)",
9531
+ examples: [
9532
+ ["Submit skill from current directory", "$0 publish submit"],
9533
+ ["Submit with custom name", "$0 publish submit --name my-skill"]
9164
9534
  ]
9165
9535
  });
9166
9536
  skillPath = Option36.String({ required: false, name: "path" });
9167
9537
  name = Option36.String("--name,-n", {
9168
- description: "Custom skill name (default: parsed from SKILL.md)"
9538
+ description: "Custom skill name"
9169
9539
  });
9170
9540
  dryRun = Option36.Boolean("--dry-run", false, {
9171
- description: "Show what would be published without actually publishing"
9541
+ description: "Show what would be submitted"
9172
9542
  });
9173
9543
  async execute() {
9174
9544
  const skillPath = this.skillPath || process.cwd();
@@ -9176,10 +9546,9 @@ var PublishCommand = class extends Command37 {
9176
9546
  if (!skillMdPath) {
9177
9547
  console.error(chalk27.red("No SKILL.md found"));
9178
9548
  console.error(chalk27.dim("Run this command from a directory containing SKILL.md"));
9179
- console.error(chalk27.dim("Or specify the path: skillkit publish ./path/to/skill"));
9180
9549
  return 1;
9181
9550
  }
9182
- console.log(chalk27.cyan("Publishing skill to SkillKit marketplace...\n"));
9551
+ console.log(chalk27.cyan("Submitting skill to SkillKit marketplace...\n"));
9183
9552
  const content = readFileSync9(skillMdPath, "utf-8");
9184
9553
  const frontmatter = this.parseFrontmatter(content);
9185
9554
  const skillName = this.name || frontmatter.name || basename4(dirname6(skillMdPath));
@@ -9198,9 +9567,9 @@ var PublishCommand = class extends Command37 {
9198
9567
  const skillEntry = {
9199
9568
  id: `${repoInfo.owner}/${repoInfo.repo}/${skillSlug}`,
9200
9569
  name: this.formatName(skillName),
9201
- description: frontmatter.description || `Best practices and patterns for ${this.formatName(skillName)}`,
9570
+ description: frontmatter.description || `Best practices for ${this.formatName(skillName)}`,
9202
9571
  source: `${repoInfo.owner}/${repoInfo.repo}`,
9203
- tags: frontmatter.tags || this.inferTags(skillName, frontmatter.description || "")
9572
+ tags: frontmatter.tags || ["general"]
9204
9573
  };
9205
9574
  console.log(chalk27.white("Skill details:"));
9206
9575
  console.log(chalk27.dim(` ID: ${skillEntry.id}`));
@@ -9210,8 +9579,7 @@ var PublishCommand = class extends Command37 {
9210
9579
  console.log(chalk27.dim(` Tags: ${skillEntry.tags.join(", ")}`));
9211
9580
  console.log();
9212
9581
  if (this.dryRun) {
9213
- console.log(chalk27.yellow("Dry run - not publishing"));
9214
- console.log(chalk27.dim("JSON entry that would be added:"));
9582
+ console.log(chalk27.yellow("Dry run - not submitting"));
9215
9583
  console.log(JSON.stringify(skillEntry, null, 2));
9216
9584
  return 0;
9217
9585
  }
@@ -9221,20 +9589,16 @@ var PublishCommand = class extends Command37 {
9221
9589
  const issueUrl = `https://github.com/rohitg00/skillkit/issues/new?title=${issueTitle}&body=${issueBodyEncoded}&labels=skill-submission,publish`;
9222
9590
  console.log(chalk27.green("Opening GitHub to submit your skill...\n"));
9223
9591
  try {
9592
+ const { execSync } = await import("child_process");
9224
9593
  const openCmd = process.platform === "darwin" ? `open "${issueUrl}"` : process.platform === "win32" ? `cmd /c start "" "${issueUrl}"` : `xdg-open "${issueUrl}"`;
9225
9594
  execSync(openCmd, { stdio: "ignore" });
9226
9595
  console.log(chalk27.green("GitHub issue page opened!"));
9227
- console.log(chalk27.dim("Review and submit the issue to publish your skill."));
9596
+ console.log(chalk27.dim("Review and submit the issue."));
9228
9597
  } catch {
9229
9598
  console.log(chalk27.yellow("Could not open browser automatically."));
9230
9599
  console.log(chalk27.dim("Please open this URL manually:\n"));
9231
9600
  console.log(chalk27.cyan(issueUrl));
9232
9601
  }
9233
- console.log();
9234
- console.log(chalk27.cyan("Next steps:"));
9235
- console.log(chalk27.dim(" 1. Review the skill details in the GitHub issue"));
9236
- console.log(chalk27.dim(" 2. Submit the issue"));
9237
- console.log(chalk27.dim(" 3. A maintainer will review and add your skill"));
9238
9602
  return 0;
9239
9603
  }
9240
9604
  findSkillMd(basePath) {
@@ -9247,8 +9611,7 @@ var PublishCommand = class extends Command37 {
9247
9611
  }
9248
9612
  const locations = [
9249
9613
  join16(basePath, "skills", "SKILL.md"),
9250
- join16(basePath, ".claude", "skills", "SKILL.md"),
9251
- join16(basePath, ".cursor", "skills", "SKILL.md")
9614
+ join16(basePath, ".claude", "skills", "SKILL.md")
9252
9615
  ];
9253
9616
  for (const loc of locations) {
9254
9617
  if (existsSync17(loc)) {
@@ -9262,18 +9625,7 @@ var PublishCommand = class extends Command37 {
9262
9625
  if (!match) return {};
9263
9626
  const frontmatter = {};
9264
9627
  const lines = match[1].split(/\r?\n/);
9265
- let inTagsList = false;
9266
9628
  for (const line of lines) {
9267
- if (inTagsList) {
9268
- const tagMatch = line.match(/^\s*-\s*(.+)$/);
9269
- if (tagMatch) {
9270
- frontmatter.tags ??= [];
9271
- frontmatter.tags.push(tagMatch[1].trim().replace(/^["']|["']$/g, ""));
9272
- continue;
9273
- }
9274
- if (line.trim() === "") continue;
9275
- inTagsList = false;
9276
- }
9277
9629
  const colonIdx = line.indexOf(":");
9278
9630
  if (colonIdx === -1) continue;
9279
9631
  const key = line.slice(0, colonIdx).trim();
@@ -9291,9 +9643,6 @@ var PublishCommand = class extends Command37 {
9291
9643
  case "tags":
9292
9644
  if (value.startsWith("[")) {
9293
9645
  frontmatter.tags = value.slice(1, -1).split(",").map((t) => t.trim().replace(/^["']|["']$/g, "")).filter((t) => t.length > 0);
9294
- } else if (value === "") {
9295
- inTagsList = true;
9296
- frontmatter.tags = [];
9297
9646
  }
9298
9647
  break;
9299
9648
  }
@@ -9305,6 +9654,7 @@ var PublishCommand = class extends Command37 {
9305
9654
  }
9306
9655
  getRepoInfo(dir) {
9307
9656
  try {
9657
+ const { execSync } = __require("child_process");
9308
9658
  const remote = execSync("git remote get-url origin", {
9309
9659
  cwd: dir,
9310
9660
  encoding: "utf-8",
@@ -9321,27 +9671,6 @@ var PublishCommand = class extends Command37 {
9321
9671
  formatName(name) {
9322
9672
  return name.split(/[-_]/).map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
9323
9673
  }
9324
- inferTags(name, description) {
9325
- const tags = [];
9326
- const text3 = `${name} ${description}`.toLowerCase();
9327
- const tagMap = {
9328
- react: ["react", "jsx", "tsx"],
9329
- typescript: ["typescript", "ts"],
9330
- nextjs: ["next", "nextjs"],
9331
- testing: ["test", "jest", "vitest"],
9332
- mobile: ["mobile", "react-native", "expo"],
9333
- backend: ["backend", "api", "server"],
9334
- database: ["database", "postgres", "mysql", "supabase"],
9335
- frontend: ["frontend", "ui", "design"],
9336
- devops: ["devops", "ci", "cd", "docker"]
9337
- };
9338
- for (const [tag, keywords] of Object.entries(tagMap)) {
9339
- if (keywords.some((k) => text3.includes(k))) {
9340
- tags.push(tag);
9341
- }
9342
- }
9343
- return tags.length > 0 ? tags : ["general"];
9344
- }
9345
9674
  createIssueBody(skill) {
9346
9675
  return `## Publish Skill Request
9347
9676
 
@@ -9364,15 +9693,15 @@ ${JSON.stringify(skill, null, 2)}
9364
9693
  - [ ] Tags are appropriate
9365
9694
 
9366
9695
  ---
9367
- Submitted via \`skillkit publish\``;
9696
+ Submitted via \`skillkit publish submit\``;
9368
9697
  }
9369
9698
  };
9370
9699
 
9371
9700
  // src/commands/agent.ts
9372
9701
  import chalk28 from "chalk";
9373
9702
  import { Command as Command38, Option as Option37 } from "clipanion";
9374
- import { existsSync as existsSync18, mkdirSync as mkdirSync8, writeFileSync as writeFileSync8 } from "fs";
9375
- import { join as join17 } from "path";
9703
+ import { existsSync as existsSync18, mkdirSync as mkdirSync9, writeFileSync as writeFileSync9 } from "fs";
9704
+ import { join as join17, basename as basename5 } from "path";
9376
9705
  import { homedir as homedir3 } from "os";
9377
9706
  import {
9378
9707
  findAllAgents,
@@ -9381,7 +9710,10 @@ import {
9381
9710
  discoverAgentsFromPath,
9382
9711
  validateAgent,
9383
9712
  translateAgent,
9384
- getAgentTargetDirectory
9713
+ getAgentTargetDirectory,
9714
+ discoverSkills as discoverSkills2,
9715
+ readSkillContent as readSkillContent2,
9716
+ generateSubagentFromSkill
9385
9717
  } from "@skillkit/core";
9386
9718
  import {
9387
9719
  getBundledAgents,
@@ -9402,17 +9734,19 @@ var AgentCommand = class extends Command38 {
9402
9734
  that can be invoked with @mentions or the --agent flag.
9403
9735
 
9404
9736
  Sub-commands:
9405
- agent list - List all installed agents
9406
- agent show - Show agent details
9407
- agent create - Create a new agent
9408
- agent translate - Translate agents between formats
9409
- agent sync - Sync agents to target AI agent
9410
- agent validate - Validate agent definitions
9737
+ agent list - List all installed agents
9738
+ agent show - Show agent details
9739
+ agent create - Create a new agent
9740
+ agent from-skill - Convert a skill to a subagent
9741
+ agent translate - Translate agents between formats
9742
+ agent sync - Sync agents to target AI agent
9743
+ agent validate - Validate agent definitions
9411
9744
  `,
9412
9745
  examples: [
9413
9746
  ["List all agents", "$0 agent list"],
9414
9747
  ["Show agent details", "$0 agent show architect"],
9415
9748
  ["Create new agent", "$0 agent create security-reviewer"],
9749
+ ["Convert skill to subagent", "$0 agent from-skill code-simplifier"],
9416
9750
  ["Translate to Cursor format", "$0 agent translate --to cursor"],
9417
9751
  ["Sync agents", "$0 agent sync --agent claude-code"]
9418
9752
  ]
@@ -9422,6 +9756,7 @@ var AgentCommand = class extends Command38 {
9422
9756
  console.log(" agent list List all installed agents");
9423
9757
  console.log(" agent show <name> Show agent details");
9424
9758
  console.log(" agent create <name> Create a new agent");
9759
+ console.log(" agent from-skill <name> Convert a skill to a subagent");
9425
9760
  console.log(" agent translate Translate agents between formats");
9426
9761
  console.log(" agent sync Sync agents to target AI agent");
9427
9762
  console.log(" agent validate [path] Validate agent definitions");
@@ -9595,7 +9930,7 @@ var AgentCreateCommand = class extends Command38 {
9595
9930
  targetDir = join17(process.cwd(), ".claude", "agents");
9596
9931
  }
9597
9932
  if (!existsSync18(targetDir)) {
9598
- mkdirSync8(targetDir, { recursive: true });
9933
+ mkdirSync9(targetDir, { recursive: true });
9599
9934
  }
9600
9935
  const agentPath = join17(targetDir, `${this.name}.md`);
9601
9936
  if (existsSync18(agentPath)) {
@@ -9604,7 +9939,7 @@ var AgentCreateCommand = class extends Command38 {
9604
9939
  }
9605
9940
  const description = this.description || `${this.name} agent`;
9606
9941
  const content = generateAgentTemplate(this.name, description, this.model);
9607
- writeFileSync8(agentPath, content);
9942
+ writeFileSync9(agentPath, content);
9608
9943
  console.log(chalk28.green(`Created agent: ${agentPath}`));
9609
9944
  console.log();
9610
9945
  console.log(chalk28.dim("Edit the file to customize the agent system prompt."));
@@ -9713,9 +10048,9 @@ var AgentTranslateCommand = class extends Command38 {
9713
10048
  }
9714
10049
  } else {
9715
10050
  if (!existsSync18(outputDir)) {
9716
- mkdirSync8(outputDir, { recursive: true });
10051
+ mkdirSync9(outputDir, { recursive: true });
9717
10052
  }
9718
- writeFileSync8(outputPath, result.content);
10053
+ writeFileSync9(outputPath, result.content);
9719
10054
  console.log(chalk28.green(`\u2713 ${agent.name} \u2192 ${outputPath}`));
9720
10055
  }
9721
10056
  successCount++;
@@ -9759,13 +10094,13 @@ var AgentSyncCommand = class extends Command38 {
9759
10094
  const outputDir = getAgentTargetDirectory(process.cwd(), targetAgent);
9760
10095
  console.log(chalk28.blue(`\u2192 ${targetAgent} (${outputDir})`));
9761
10096
  if (!existsSync18(outputDir)) {
9762
- mkdirSync8(outputDir, { recursive: true });
10097
+ mkdirSync9(outputDir, { recursive: true });
9763
10098
  }
9764
10099
  for (const agent of agents) {
9765
10100
  const result = translateAgent(agent, targetAgent);
9766
10101
  if (result.success) {
9767
10102
  const outputPath = join17(outputDir, result.filename);
9768
- writeFileSync8(outputPath, result.content);
10103
+ writeFileSync9(outputPath, result.content);
9769
10104
  console.log(chalk28.green(` \u2713 ${agent.name}`));
9770
10105
  } else {
9771
10106
  console.log(chalk28.red(` \u2717 ${agent.name}`));
@@ -10039,9 +10374,148 @@ var AgentAvailableCommand = class extends Command38 {
10039
10374
  return 0;
10040
10375
  }
10041
10376
  };
10377
+ var AgentFromSkillCommand = class extends Command38 {
10378
+ static paths = [["agent", "from-skill"]];
10379
+ static usage = Command38.Usage({
10380
+ description: "Convert a skill into a Claude Code subagent",
10381
+ details: `
10382
+ Converts a SkillKit skill into a Claude Code native subagent format.
10383
+ The generated .md file can be used with @mentions in Claude Code.
10384
+
10385
+ By default, the subagent references the skill (skills: [skill-name]).
10386
+ Use --inline to embed the full skill content in the system prompt.
10387
+ `,
10388
+ examples: [
10389
+ ["Convert skill to subagent", "$0 agent from-skill code-simplifier"],
10390
+ ["Create global subagent", "$0 agent from-skill code-simplifier --global"],
10391
+ ["Embed skill content inline", "$0 agent from-skill code-simplifier --inline"],
10392
+ ["Set model for subagent", "$0 agent from-skill code-simplifier --model opus"],
10393
+ ["Preview without writing", "$0 agent from-skill code-simplifier --dry-run"]
10394
+ ]
10395
+ });
10396
+ skillName = Option37.String({ required: true });
10397
+ inline = Option37.Boolean("--inline,-i", false, {
10398
+ description: "Embed full skill content in system prompt"
10399
+ });
10400
+ model = Option37.String("--model,-m", {
10401
+ description: "Model to use (sonnet, opus, haiku, inherit)"
10402
+ });
10403
+ permission = Option37.String("--permission,-p", {
10404
+ description: "Permission mode (default, plan, auto-edit, full-auto, bypassPermissions)"
10405
+ });
10406
+ global = Option37.Boolean("--global,-g", false, {
10407
+ description: "Create in ~/.claude/agents/ instead of .claude/agents/"
10408
+ });
10409
+ output = Option37.String("--output,-o", {
10410
+ description: "Custom output filename (without .md)"
10411
+ });
10412
+ dryRun = Option37.Boolean("--dry-run,-n", false, {
10413
+ description: "Preview without writing files"
10414
+ });
10415
+ async execute() {
10416
+ const skills = discoverSkills2(process.cwd());
10417
+ const skill = skills.find((s) => s.name === this.skillName);
10418
+ if (!skill) {
10419
+ console.log(chalk28.red(`Skill not found: ${this.skillName}`));
10420
+ console.log(chalk28.dim("Available skills:"));
10421
+ for (const s of skills.slice(0, 10)) {
10422
+ console.log(chalk28.dim(` - ${s.name}`));
10423
+ }
10424
+ if (skills.length > 10) {
10425
+ console.log(chalk28.dim(` ... and ${skills.length - 10} more`));
10426
+ }
10427
+ return 1;
10428
+ }
10429
+ const skillContent = readSkillContent2(skill.path);
10430
+ if (!skillContent) {
10431
+ console.log(chalk28.red(`Could not read skill content: ${skill.path}`));
10432
+ return 1;
10433
+ }
10434
+ const options = {
10435
+ inline: this.inline
10436
+ };
10437
+ if (this.model) {
10438
+ const validModels = ["sonnet", "opus", "haiku", "inherit"];
10439
+ if (!validModels.includes(this.model)) {
10440
+ console.log(chalk28.red(`Invalid model: ${this.model}`));
10441
+ console.log(chalk28.dim(`Valid options: ${validModels.join(", ")}`));
10442
+ return 1;
10443
+ }
10444
+ options.model = this.model;
10445
+ }
10446
+ if (this.permission) {
10447
+ const validModes = ["default", "plan", "auto-edit", "full-auto", "bypassPermissions"];
10448
+ if (!validModes.includes(this.permission)) {
10449
+ console.log(chalk28.red(`Invalid permission mode: ${this.permission}`));
10450
+ console.log(chalk28.dim(`Valid options: ${validModes.join(", ")}`));
10451
+ return 1;
10452
+ }
10453
+ options.permissionMode = this.permission;
10454
+ }
10455
+ const content = generateSubagentFromSkill(skill, skillContent, options);
10456
+ const targetDir = this.global ? join17(homedir3(), ".claude", "agents") : join17(process.cwd(), ".claude", "agents");
10457
+ let filename;
10458
+ if (this.output) {
10459
+ const sanitized = sanitizeFilename(this.output);
10460
+ if (!sanitized) {
10461
+ console.log(chalk28.red(`Invalid output filename: ${this.output}`));
10462
+ console.log(chalk28.dim("Filename must contain only alphanumeric characters, hyphens, and underscores"));
10463
+ return 1;
10464
+ }
10465
+ filename = `${sanitized}.md`;
10466
+ } else {
10467
+ const sanitized = sanitizeFilename(skill.name);
10468
+ if (!sanitized) {
10469
+ console.log(chalk28.red(`Invalid skill name for filename: ${skill.name}`));
10470
+ console.log(chalk28.dim("Skill name must contain only alphanumeric characters, hyphens, and underscores"));
10471
+ return 1;
10472
+ }
10473
+ filename = `${sanitized}.md`;
10474
+ }
10475
+ const outputPath = join17(targetDir, filename);
10476
+ if (this.dryRun) {
10477
+ console.log(chalk28.cyan("Preview (dry run):\n"));
10478
+ console.log(chalk28.dim(`Would write to: ${outputPath}`));
10479
+ console.log(chalk28.dim("\u2500".repeat(50)));
10480
+ console.log(content);
10481
+ console.log(chalk28.dim("\u2500".repeat(50)));
10482
+ return 0;
10483
+ }
10484
+ if (!existsSync18(targetDir)) {
10485
+ mkdirSync9(targetDir, { recursive: true });
10486
+ }
10487
+ if (existsSync18(outputPath)) {
10488
+ console.log(chalk28.yellow(`Overwriting existing file: ${outputPath}`));
10489
+ }
10490
+ writeFileSync9(outputPath, content);
10491
+ console.log(chalk28.green(`Created subagent: ${outputPath}`));
10492
+ console.log();
10493
+ console.log(chalk28.dim(`Invoke with: @${skill.name}`));
10494
+ if (!this.inline) {
10495
+ console.log(chalk28.dim(`Skills referenced: ${skill.name}`));
10496
+ } else {
10497
+ console.log(chalk28.dim("Skill content embedded inline"));
10498
+ }
10499
+ return 0;
10500
+ }
10501
+ };
10042
10502
  function formatCategoryName(category) {
10043
10503
  return category.split("-").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
10044
10504
  }
10505
+ function sanitizeFilename(input) {
10506
+ const base = basename5(input);
10507
+ const stem = base.replace(/\.md$/i, "");
10508
+ if (!stem || stem.startsWith(".") || stem.startsWith("-")) {
10509
+ return null;
10510
+ }
10511
+ if (!/^[a-zA-Z0-9][a-zA-Z0-9_-]*$/.test(stem)) {
10512
+ return null;
10513
+ }
10514
+ if (stem.length > 64) {
10515
+ return null;
10516
+ }
10517
+ return stem;
10518
+ }
10045
10519
 
10046
10520
  // src/commands/check.ts
10047
10521
  init_helpers();
@@ -10129,9 +10603,9 @@ var CheckCommand = class extends Command39 {
10129
10603
  const sourceSkillMd = join18(localPath, "SKILL.md");
10130
10604
  const installedSkillMd = join18(skill.path, "SKILL.md");
10131
10605
  if (existsSync19(sourceSkillMd) && existsSync19(installedSkillMd)) {
10132
- const { statSync: statSync3 } = await import("fs");
10133
- const sourceTime = statSync3(sourceSkillMd).mtime;
10134
- const installedTime = statSync3(installedSkillMd).mtime;
10606
+ const { statSync: statSync4 } = await import("fs");
10607
+ const sourceTime = statSync4(sourceSkillMd).mtime;
10608
+ const installedTime = statSync4(installedSkillMd).mtime;
10135
10609
  if (sourceTime > installedTime) {
10136
10610
  results.push({ name: skill.name, hasUpdate: true });
10137
10611
  updatesAvailable++;
@@ -10215,7 +10689,7 @@ var skills_default = {
10215
10689
  $schema: "./schema.json",
10216
10690
  version: 1,
10217
10691
  updatedAt: "2026-01-26",
10218
- totalSkills: 15062,
10692
+ totalSkills: 15064,
10219
10693
  curatedCollections: 31,
10220
10694
  skills: [
10221
10695
  {
@@ -10567,6 +11041,19 @@ var skills_default = {
10567
11041
  "react"
10568
11042
  ]
10569
11043
  },
11044
+ {
11045
+ id: "rohitg00/skillkit/find-skills",
11046
+ name: "Find Skills",
11047
+ description: "Universal skill discovery across all AI agent marketplaces. Search 15K+ skills and install with one command.",
11048
+ source: "rohitg00/skillkit",
11049
+ tags: [
11050
+ "meta",
11051
+ "discovery",
11052
+ "marketplace",
11053
+ "skills",
11054
+ "find-skills"
11055
+ ]
11056
+ },
10570
11057
  {
10571
11058
  id: "anthropics/skills/frontend-design",
10572
11059
  name: "Frontend Design",
@@ -43298,6 +43785,20 @@ var skills_default = {
43298
43785
  source: "oldwinter/skills",
43299
43786
  tags: []
43300
43787
  },
43788
+ {
43789
+ id: "rohitg00/kubectl-mcp-server/kubernetes-mcp",
43790
+ name: "Kubernetes MCP Server",
43791
+ description: "MCP server for Kubernetes with 127+ tools, 8 resources, 8 prompts. Full cluster management via Claude/Cursor.",
43792
+ source: "rohitg00/kubectl-mcp-server",
43793
+ tags: [
43794
+ "kubernetes",
43795
+ "mcp",
43796
+ "kubernetes-mcp",
43797
+ "devops",
43798
+ "kubectl",
43799
+ "k8s"
43800
+ ]
43801
+ },
43301
43802
  {
43302
43803
  id: "itsmostafa/aws-agent-skills/cognito",
43303
43804
  name: "Cognito",
@@ -136183,7 +136684,7 @@ var ManifestGenerateCommand = class extends Command41 {
136183
136684
 
136184
136685
  // src/commands/primer.ts
136185
136686
  import { Command as Command42, Option as Option41 } from "clipanion";
136186
- import { resolve as resolve18 } from "path";
136687
+ import { resolve as resolve19 } from "path";
136187
136688
  import chalk29 from "chalk";
136188
136689
  import {
136189
136690
  AgentType as AgentTypeSchema,
@@ -136251,7 +136752,7 @@ var PrimerCommand = class extends Command42 {
136251
136752
  description: "Number of commits to analyze for learning (default: 100)"
136252
136753
  });
136253
136754
  async execute() {
136254
- const projectPath = resolve18(this.directory || process.cwd());
136755
+ const projectPath = resolve19(this.directory || process.cwd());
136255
136756
  if (this.analyzeOnly) {
136256
136757
  return this.runAnalysis(projectPath);
136257
136758
  }
@@ -136320,7 +136821,7 @@ var PrimerCommand = class extends Command42 {
136320
136821
  const result = generatePrimer(projectPath, {
136321
136822
  agents,
136322
136823
  allAgents: this.allAgents,
136323
- outputDir: this.output ? resolve18(this.output) : void 0,
136824
+ outputDir: this.output ? resolve19(this.output) : void 0,
136324
136825
  dryRun: this.dryRun,
136325
136826
  verbose: this.verbose,
136326
136827
  includeExamples: this.includeExamples
@@ -137531,7 +138032,7 @@ Sent Messages (${messages.length})
137531
138032
 
137532
138033
  // src/commands/learn.ts
137533
138034
  import { Command as Command45, Option as Option44 } from "clipanion";
137534
- import { resolve as resolve19 } from "path";
138035
+ import { resolve as resolve20 } from "path";
137535
138036
  import chalk32 from "chalk";
137536
138037
  import {
137537
138038
  analyzeGitHistory as analyzeGitHistory2,
@@ -137551,7 +138052,7 @@ import {
137551
138052
  getPatternStats,
137552
138053
  clusterPatterns
137553
138054
  } from "@skillkit/core";
137554
- import { writeFileSync as writeFileSync9, readFileSync as readFileSync10, existsSync as existsSync20 } from "fs";
138055
+ import { writeFileSync as writeFileSync10, readFileSync as readFileSync10, existsSync as existsSync20 } from "fs";
137555
138056
  var LearnCommand = class extends Command45 {
137556
138057
  static paths = [["learn"]];
137557
138058
  static usage = Command45.Usage({
@@ -137588,7 +138089,7 @@ var LearnCommand = class extends Command45 {
137588
138089
  description: "Project directory to analyze (default: current directory)"
137589
138090
  });
137590
138091
  async execute() {
137591
- const projectPath = resolve19(this.directory || process.cwd());
138092
+ const projectPath = resolve20(this.directory || process.cwd());
137592
138093
  if (this.show) {
137593
138094
  return this.showPatterns();
137594
138095
  }
@@ -137835,7 +138336,7 @@ var PatternExportCommand = class extends Command45 {
137835
138336
  content = exportPatternsAsJson(patterns);
137836
138337
  }
137837
138338
  if (this.output) {
137838
- writeFileSync9(this.output, content);
138339
+ writeFileSync10(this.output, content);
137839
138340
  console.log(chalk32.green(`\u2713 Exported ${patterns.length} patterns to ${this.output}`));
137840
138341
  } else {
137841
138342
  console.log(content);
@@ -138557,6 +139058,208 @@ function formatCategoryName2(category) {
138557
139058
  return category.split("-").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
138558
139059
  }
138559
139060
 
139061
+ // src/commands/tree.ts
139062
+ init_onboarding();
139063
+ import { Command as Command49, Option as Option48 } from "clipanion";
139064
+ import { join as join19 } from "path";
139065
+ import { homedir as homedir4 } from "os";
139066
+ import {
139067
+ loadIndex as loadIndexFromCache3,
139068
+ generateSkillTree,
139069
+ saveTree,
139070
+ loadTree
139071
+ } from "@skillkit/core";
139072
+ var TREE_PATH = join19(homedir4(), ".skillkit", "skill-tree.json");
139073
+ var TreeCommand = class extends Command49 {
139074
+ static paths = [["tree"]];
139075
+ static usage = Command49.Usage({
139076
+ description: "Browse skills in a hierarchical tree structure",
139077
+ details: `
139078
+ The tree command displays skills organized in a hierarchical taxonomy.
139079
+ Navigate through categories like Development, Testing, DevOps, AI/ML, etc.
139080
+
139081
+ Features:
139082
+ - Visual tree structure of all skills
139083
+ - Filter by category path (e.g., "Frontend > React")
139084
+ - Generate tree from skill index
139085
+ - Export to markdown format
139086
+ `,
139087
+ examples: [
139088
+ ["Show full tree", "$0 tree"],
139089
+ ["Show specific category", "$0 tree Frontend"],
139090
+ ["Show subcategory", '$0 tree "Frontend > React"'],
139091
+ ["Limit depth", "$0 tree --depth 2"],
139092
+ ["Generate/update tree", "$0 tree --generate"],
139093
+ ["Export to markdown", "$0 tree --markdown"],
139094
+ ["Show tree stats", "$0 tree --stats"]
139095
+ ]
139096
+ });
139097
+ treePath = Option48.String({ required: false });
139098
+ depth = Option48.String("--depth,-d", {
139099
+ description: "Maximum depth to display"
139100
+ });
139101
+ generate = Option48.Boolean("--generate,-g", false, {
139102
+ description: "Generate/update tree from skill index"
139103
+ });
139104
+ markdown = Option48.Boolean("--markdown,-m", false, {
139105
+ description: "Output in markdown format"
139106
+ });
139107
+ stats = Option48.Boolean("--stats,-s", false, {
139108
+ description: "Show tree statistics"
139109
+ });
139110
+ json = Option48.Boolean("--json,-j", false, {
139111
+ description: "Output in JSON format"
139112
+ });
139113
+ quiet = Option48.Boolean("--quiet,-q", false, {
139114
+ description: "Minimal output"
139115
+ });
139116
+ async execute() {
139117
+ if (this.generate) {
139118
+ return await this.generateTree();
139119
+ }
139120
+ const tree = this.loadOrGenerateTree();
139121
+ if (!tree) {
139122
+ warn('No skill tree found. Run "skillkit tree --generate" first.');
139123
+ return 1;
139124
+ }
139125
+ if (this.stats) {
139126
+ return this.showStats(tree);
139127
+ }
139128
+ if (this.json) {
139129
+ console.log(JSON.stringify(tree, null, 2));
139130
+ return 0;
139131
+ }
139132
+ if (this.markdown) {
139133
+ const { treeToMarkdown } = await import("@skillkit/core");
139134
+ console.log(treeToMarkdown(tree));
139135
+ return 0;
139136
+ }
139137
+ return this.displayTree(tree);
139138
+ }
139139
+ async generateTree() {
139140
+ if (!this.quiet) {
139141
+ header("Generate Skill Tree");
139142
+ }
139143
+ const index = loadIndexFromCache3();
139144
+ if (!index || index.skills.length === 0) {
139145
+ warn('No skill index found. Run "skillkit recommend --update" first.');
139146
+ return 1;
139147
+ }
139148
+ const s = spinner2();
139149
+ s.start("Generating skill tree...");
139150
+ try {
139151
+ const tree = generateSkillTree(index.skills);
139152
+ saveTree(tree, TREE_PATH);
139153
+ s.stop(`Generated tree with ${tree.totalCategories} categories`);
139154
+ console.log("");
139155
+ console.log(colors.success(`${symbols.success} Tree generated successfully`));
139156
+ console.log(colors.muted(` Total skills: ${tree.totalSkills}`));
139157
+ console.log(colors.muted(` Categories: ${tree.totalCategories}`));
139158
+ console.log(colors.muted(` Max depth: ${tree.maxDepth}`));
139159
+ console.log(colors.muted(` Saved to: ${TREE_PATH}`));
139160
+ console.log("");
139161
+ return 0;
139162
+ } catch (err) {
139163
+ s.stop(colors.error("Failed to generate tree"));
139164
+ console.log(colors.muted(err instanceof Error ? err.message : String(err)));
139165
+ return 1;
139166
+ }
139167
+ }
139168
+ loadOrGenerateTree() {
139169
+ let tree = loadTree(TREE_PATH);
139170
+ if (!tree) {
139171
+ const index = loadIndexFromCache3();
139172
+ if (index && index.skills.length > 0) {
139173
+ tree = generateSkillTree(index.skills);
139174
+ saveTree(tree, TREE_PATH);
139175
+ }
139176
+ }
139177
+ return tree;
139178
+ }
139179
+ showStats(tree) {
139180
+ if (!this.quiet) {
139181
+ header("Skill Tree Statistics");
139182
+ }
139183
+ console.log("");
139184
+ console.log(colors.bold("Overview:"));
139185
+ console.log(` Total Skills: ${colors.accent(String(tree.totalSkills))}`);
139186
+ console.log(` Categories: ${colors.accent(String(tree.totalCategories))}`);
139187
+ console.log(` Max Depth: ${colors.accent(String(tree.maxDepth))}`);
139188
+ console.log(` Generated: ${colors.muted(tree.generatedAt)}`);
139189
+ console.log("");
139190
+ console.log(colors.bold("Top-Level Categories:"));
139191
+ for (const child of tree.rootNode.children) {
139192
+ const percentage = tree.totalSkills > 0 ? (child.skillCount / tree.totalSkills * 100).toFixed(1) : "0.0";
139193
+ console.log(
139194
+ ` ${colors.accent(child.name.padEnd(15))} ${String(child.skillCount).padStart(6)} skills (${percentage}%)`
139195
+ );
139196
+ if (child.children.length > 0) {
139197
+ const subcats = child.children.sort((a, b) => b.skillCount - a.skillCount).slice(0, 3).map((c) => `${c.name} (${c.skillCount})`).join(", ");
139198
+ console.log(` ${colors.muted(subcats)}`);
139199
+ }
139200
+ }
139201
+ console.log("");
139202
+ return 0;
139203
+ }
139204
+ displayTree(tree) {
139205
+ if (!this.quiet) {
139206
+ header("Skill Tree");
139207
+ console.log(colors.muted(`${tree.totalSkills} skills in ${tree.totalCategories} categories`));
139208
+ console.log("");
139209
+ }
139210
+ let targetNode = tree.rootNode;
139211
+ if (this.treePath) {
139212
+ const segments = this.treePath.split(">").map((s) => s.trim());
139213
+ let current = tree.rootNode;
139214
+ for (const segment of segments) {
139215
+ const child = current.children.find(
139216
+ (c) => c.name.toLowerCase() === segment.toLowerCase()
139217
+ );
139218
+ if (!child) {
139219
+ warn(`Category not found: ${segment}`);
139220
+ console.log(colors.muted(`Available categories: ${current.children.map((c) => c.name).join(", ")}`));
139221
+ return 1;
139222
+ }
139223
+ current = child;
139224
+ }
139225
+ targetNode = current;
139226
+ }
139227
+ let maxDepth = this.depth ? parseInt(this.depth, 10) : 3;
139228
+ if (Number.isNaN(maxDepth) || maxDepth < 0) {
139229
+ warn("Invalid depth value. Using default depth of 3.");
139230
+ maxDepth = 3;
139231
+ }
139232
+ this.renderNode(targetNode, "", true, 0, maxDepth);
139233
+ console.log("");
139234
+ console.log(colors.muted('Navigate: skillkit tree "Category > Subcategory"'));
139235
+ console.log(colors.muted("Generate: skillkit tree --generate"));
139236
+ return 0;
139237
+ }
139238
+ renderNode(node, prefix, isLast, depth, maxDepth) {
139239
+ if (depth > maxDepth) return;
139240
+ const connector = depth === 0 ? "" : isLast ? "\u2514\u2500\u2500 " : "\u251C\u2500\u2500 ";
139241
+ const icon = node.children.length > 0 ? "\u{1F4C1} " : "\u{1F4C4} ";
139242
+ const skillInfo = node.skillCount > 0 ? colors.muted(` (${node.skillCount})`) : "";
139243
+ const nameColor = depth === 0 ? colors.bold : depth === 1 ? colors.accent : colors.dim;
139244
+ console.log(`${prefix}${connector}${icon}${nameColor(node.name)}${skillInfo}`);
139245
+ if (depth === maxDepth && node.skills.length > 0 && node.skills.length <= 5) {
139246
+ const childPrefix = prefix + (isLast ? " " : "\u2502 ");
139247
+ for (const skill of node.skills) {
139248
+ console.log(`${childPrefix} \u2022 ${colors.muted(skill)}`);
139249
+ }
139250
+ }
139251
+ const newPrefix = prefix + (depth === 0 ? "" : isLast ? " " : "\u2502 ");
139252
+ if (depth < maxDepth) {
139253
+ node.children.forEach((child, index) => {
139254
+ const childIsLast = index === node.children.length - 1;
139255
+ this.renderNode(child, newPrefix, childIsLast, depth + 1, maxDepth);
139256
+ });
139257
+ } else if (node.children.length > 0) {
139258
+ console.log(`${newPrefix} ${colors.muted(`... ${node.children.length} more subcategories`)}`);
139259
+ }
139260
+ }
139261
+ };
139262
+
138560
139263
  // src/index.ts
138561
139264
  init_helpers();
138562
139265
  export {
@@ -138564,6 +139267,7 @@ export {
138564
139267
  AgentAvailableCommand,
138565
139268
  AgentCommand,
138566
139269
  AgentCreateCommand,
139270
+ AgentFromSkillCommand,
138567
139271
  AgentInstallCommand,
138568
139272
  AgentListCommand,
138569
139273
  AgentShowCommand,
@@ -138624,6 +139328,7 @@ export {
138624
139328
  ProfileListCommand,
138625
139329
  ProfileRemoveCommand,
138626
139330
  PublishCommand,
139331
+ PublishSubmitCommand,
138627
139332
  ReadCommand,
138628
139333
  RecommendCommand,
138629
139334
  RemoveCommand,
@@ -138643,6 +139348,7 @@ export {
138643
139348
  TeamCommand,
138644
139349
  TestCommand,
138645
139350
  TranslateCommand,
139351
+ TreeCommand,
138646
139352
  UICommand,
138647
139353
  UpdateCommand,
138648
139354
  ValidateCommand,