@skillkit/cli 1.8.1 → 1.10.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,
@@ -3369,7 +3391,10 @@ var RecommendCommand = class extends Command15 {
3369
3391
  ["Show detailed reasons", "$0 recommend --verbose"],
3370
3392
  ["Update skill index", "$0 recommend --update"],
3371
3393
  ["Search for skills by task", '$0 recommend --task "authentication"'],
3372
- ["Search for skills (alias)", '$0 recommend --search "testing"']
3394
+ ["Search for skills (alias)", '$0 recommend --search "testing"'],
3395
+ ["Hybrid search (vector + keyword)", '$0 recommend --search "auth" --hybrid'],
3396
+ ["Hybrid search with query expansion", '$0 recommend --search "auth" --hybrid --expand'],
3397
+ ["Build hybrid search index", "$0 recommend --build-index"]
3373
3398
  ]
3374
3399
  });
3375
3400
  // Limit number of results
@@ -3416,11 +3441,45 @@ var RecommendCommand = class extends Command15 {
3416
3441
  quiet = Option14.Boolean("--quiet,-q", false, {
3417
3442
  description: "Minimal output"
3418
3443
  });
3444
+ // Explain mode (reasoning-based recommendations)
3445
+ explain = Option14.Boolean("--explain,-e", false, {
3446
+ description: "Show detailed explanations for recommendations (uses reasoning engine)"
3447
+ });
3448
+ // Reasoning mode
3449
+ reasoning = Option14.Boolean("--reasoning,-r", false, {
3450
+ description: "Use LLM-based reasoning for recommendations"
3451
+ });
3452
+ // Show tree path
3453
+ showPath = Option14.Boolean("--show-path", false, {
3454
+ description: "Show category path for each recommendation"
3455
+ });
3456
+ // Hybrid search mode
3457
+ hybrid = Option14.Boolean("--hybrid,-H", false, {
3458
+ description: "Use hybrid search (vector + keyword)"
3459
+ });
3460
+ // Query expansion
3461
+ expand = Option14.Boolean("--expand,-x", false, {
3462
+ description: "Enable query expansion (requires --hybrid)"
3463
+ });
3464
+ // Reranking
3465
+ rerank = Option14.Boolean("--rerank", false, {
3466
+ description: "Enable LLM reranking (requires --hybrid)"
3467
+ });
3468
+ // Build index
3469
+ buildIndex = Option14.Boolean("--build-index", false, {
3470
+ description: "Build/rebuild the hybrid search embedding index"
3471
+ });
3419
3472
  async execute() {
3420
3473
  const targetPath = resolve4(this.projectPath || process.cwd());
3421
3474
  if (this.update) {
3422
3475
  return await this.updateIndex();
3423
3476
  }
3477
+ if (this.buildIndex) {
3478
+ return await this.buildHybridIndex();
3479
+ }
3480
+ if ((this.expand || this.rerank) && !this.hybrid) {
3481
+ warn("--expand and --rerank require --hybrid flag. These options will be ignored.");
3482
+ }
3424
3483
  if (!this.quiet && !this.json) {
3425
3484
  header("Skill Recommendations");
3426
3485
  }
@@ -3437,10 +3496,16 @@ var RecommendCommand = class extends Command15 {
3437
3496
  this.showProjectProfile(profile);
3438
3497
  return 0;
3439
3498
  }
3499
+ if (this.explain || this.reasoning || this.showPath) {
3500
+ return await this.handleReasoningRecommendations(profile, index);
3501
+ }
3440
3502
  const engine = new RecommendationEngine();
3441
3503
  engine.loadIndex(index);
3442
3504
  const searchQuery = this.search || this.task;
3443
3505
  if (searchQuery) {
3506
+ if (this.hybrid) {
3507
+ return await this.handleHybridSearch(engine, searchQuery);
3508
+ }
3444
3509
  return this.handleSearch(engine, searchQuery);
3445
3510
  }
3446
3511
  const result = engine.recommend(profile, {
@@ -3457,6 +3522,53 @@ var RecommendCommand = class extends Command15 {
3457
3522
  this.displayRecommendations(result.recommendations, profile, result.totalSkillsScanned);
3458
3523
  return 0;
3459
3524
  }
3525
+ async handleReasoningRecommendations(profile, index) {
3526
+ const s = !this.quiet && !this.json ? spinner2() : null;
3527
+ s?.start("Analyzing with reasoning engine...");
3528
+ try {
3529
+ const engine = new ReasoningRecommendationEngine();
3530
+ engine.loadIndex(index);
3531
+ await engine.initReasoning();
3532
+ const result = await engine.recommendWithReasoning(profile, {
3533
+ limit: this.limit ? parseInt(this.limit, 10) : 10,
3534
+ minScore: this.minScore ? parseInt(this.minScore, 10) : 30,
3535
+ categories: this.category,
3536
+ excludeInstalled: !this.includeInstalled,
3537
+ includeReasons: this.verbose,
3538
+ reasoning: this.reasoning,
3539
+ explainResults: this.explain,
3540
+ useTree: true
3541
+ });
3542
+ s?.stop("Analysis complete");
3543
+ if (this.json) {
3544
+ console.log(JSON.stringify(result, null, 2));
3545
+ return 0;
3546
+ }
3547
+ this.displayExplainedRecommendations(
3548
+ result.recommendations,
3549
+ profile,
3550
+ result.totalSkillsScanned,
3551
+ result.reasoningSummary
3552
+ );
3553
+ return 0;
3554
+ } catch (err) {
3555
+ s?.stop(colors.error("Reasoning analysis failed"));
3556
+ console.log(colors.muted(err instanceof Error ? err.message : String(err)));
3557
+ console.log(colors.muted("Falling back to standard recommendations..."));
3558
+ console.log("");
3559
+ const engine = new RecommendationEngine();
3560
+ engine.loadIndex(index);
3561
+ const result = engine.recommend(profile, {
3562
+ limit: this.limit ? parseInt(this.limit, 10) : 10,
3563
+ minScore: this.minScore ? parseInt(this.minScore, 10) : 30,
3564
+ categories: this.category,
3565
+ excludeInstalled: !this.includeInstalled,
3566
+ includeReasons: this.verbose
3567
+ });
3568
+ this.displayRecommendations(result.recommendations, profile, result.totalSkillsScanned);
3569
+ return 0;
3570
+ }
3571
+ }
3460
3572
  async getProjectProfile(projectPath) {
3461
3573
  const manager = new ContextManager2(projectPath);
3462
3574
  let context = manager.get();
@@ -3539,6 +3651,178 @@ var RecommendCommand = class extends Command15 {
3539
3651
  }
3540
3652
  console.log(colors.muted("Install with: skillkit install <source>"));
3541
3653
  }
3654
+ displayExplainedRecommendations(recommendations, profile, totalScanned, reasoningSummary) {
3655
+ this.showProjectProfile(profile);
3656
+ if (reasoningSummary && !this.quiet) {
3657
+ console.log(colors.dim("Reasoning: ") + colors.muted(reasoningSummary));
3658
+ console.log("");
3659
+ }
3660
+ if (recommendations.length === 0) {
3661
+ warn("No matching skills found.");
3662
+ console.log(colors.muted("Try lowering the minimum score with --min-score"));
3663
+ return;
3664
+ }
3665
+ console.log(colors.bold(`Explained Recommendations (${recommendations.length} of ${totalScanned} scanned):`));
3666
+ console.log("");
3667
+ for (const rec of recommendations) {
3668
+ let scoreColor;
3669
+ if (rec.score >= 70) {
3670
+ scoreColor = colors.success;
3671
+ } else if (rec.score >= 50) {
3672
+ scoreColor = colors.warning;
3673
+ } else {
3674
+ scoreColor = colors.muted;
3675
+ }
3676
+ const scoreBar = progressBar(rec.score, 100, 10);
3677
+ const qualityScore = rec.skill.quality ?? null;
3678
+ const qualityDisplay = qualityScore !== null && qualityScore !== void 0 ? ` ${formatQualityBadge(qualityScore)}` : "";
3679
+ console.log(` ${scoreColor(`${rec.score}%`)} ${colors.dim(scoreBar)} ${colors.bold(rec.skill.name)}${qualityDisplay}`);
3680
+ if (this.showPath && rec.treePath && rec.treePath.length > 0) {
3681
+ console.log(` ${colors.accent("Path:")} ${rec.treePath.join(" > ")}`);
3682
+ }
3683
+ if (rec.skill.description) {
3684
+ console.log(` ${colors.muted(truncate3(rec.skill.description, 70))}`);
3685
+ }
3686
+ if (rec.skill.source) {
3687
+ console.log(` ${colors.dim("Source:")} ${rec.skill.source}`);
3688
+ }
3689
+ if (this.explain && rec.explanation) {
3690
+ console.log(colors.dim(" Why this skill:"));
3691
+ if (rec.explanation.matchedBecause.length > 0) {
3692
+ console.log(` ${colors.success("\u251C\u2500")} Matched: ${rec.explanation.matchedBecause.join(", ")}`);
3693
+ }
3694
+ if (rec.explanation.relevantFor.length > 0) {
3695
+ console.log(` ${colors.accent("\u251C\u2500")} Relevant for: ${rec.explanation.relevantFor.join(", ")}`);
3696
+ }
3697
+ if (rec.explanation.confidence) {
3698
+ const confidenceColor = rec.explanation.confidence === "high" ? colors.success : rec.explanation.confidence === "medium" ? colors.warning : colors.muted;
3699
+ console.log(` ${colors.dim("\u2514\u2500")} Confidence: ${confidenceColor(rec.explanation.confidence)}`);
3700
+ }
3701
+ }
3702
+ if (this.verbose && rec.reasons.length > 0) {
3703
+ console.log(colors.dim(" Score breakdown:"));
3704
+ for (const reason of rec.reasons.filter((r) => r.weight > 0)) {
3705
+ console.log(` ${colors.muted(symbols.stepActive)} ${reason.description} (+${reason.weight})`);
3706
+ }
3707
+ if (qualityScore !== null && qualityScore !== void 0) {
3708
+ const grade = getQualityGradeFromScore(qualityScore);
3709
+ console.log(` ${colors.muted(symbols.stepActive)} Quality: ${qualityScore}/100 (${grade})`);
3710
+ }
3711
+ }
3712
+ if (rec.warnings.length > 0) {
3713
+ for (const warning of rec.warnings) {
3714
+ console.log(` ${colors.warning(symbols.warning)} ${warning}`);
3715
+ }
3716
+ }
3717
+ console.log("");
3718
+ }
3719
+ console.log(colors.muted("Install with: skillkit install <source>"));
3720
+ console.log(colors.muted("More details: skillkit recommend --explain --verbose"));
3721
+ }
3722
+ async handleHybridSearch(engine, query) {
3723
+ if (!this.quiet && !this.json) {
3724
+ header(`Hybrid Search: "${query}"`);
3725
+ }
3726
+ const s = !this.quiet && !this.json ? spinner2() : null;
3727
+ s?.start("Initializing hybrid search...");
3728
+ try {
3729
+ await engine.initHybridSearch();
3730
+ s?.message("Searching...");
3731
+ const results = await engine.hybridSearch({
3732
+ query,
3733
+ limit: this.limit ? parseInt(this.limit, 10) : 10,
3734
+ hybrid: true,
3735
+ enableExpansion: this.expand,
3736
+ enableReranking: this.rerank,
3737
+ filters: {
3738
+ minScore: this.minScore ? parseInt(this.minScore, 10) : void 0
3739
+ }
3740
+ });
3741
+ s?.stop(`Found ${results.length} results`);
3742
+ if (this.json) {
3743
+ console.log(JSON.stringify(results, null, 2));
3744
+ return 0;
3745
+ }
3746
+ if (results.length === 0) {
3747
+ warn(`No skills found matching "${query}"`);
3748
+ return 0;
3749
+ }
3750
+ console.log("");
3751
+ console.log(colors.bold(`Hybrid search results for "${query}" (${results.length} found):`));
3752
+ if (this.expand && results[0]?.expandedTerms?.length) {
3753
+ console.log(colors.muted(` Expanded: ${results[0].expandedTerms.join(", ")}`));
3754
+ }
3755
+ console.log("");
3756
+ for (const result of results) {
3757
+ let relevanceColor;
3758
+ if (result.relevance >= 70) {
3759
+ relevanceColor = colors.success;
3760
+ } else if (result.relevance >= 50) {
3761
+ relevanceColor = colors.warning;
3762
+ } else {
3763
+ relevanceColor = colors.muted;
3764
+ }
3765
+ const relevanceBar = progressBar(result.relevance, 100, 10);
3766
+ console.log(` ${relevanceColor(`${result.relevance}%`)} ${colors.dim(relevanceBar)} ${colors.bold(result.skill.name)}`);
3767
+ if (result.skill.description) {
3768
+ console.log(` ${colors.muted(truncate3(result.skill.description, 70))}`);
3769
+ }
3770
+ if (this.verbose) {
3771
+ const scores = [];
3772
+ if (typeof result.vectorSimilarity === "number") {
3773
+ scores.push(`vector: ${(result.vectorSimilarity * 100).toFixed(0)}%`);
3774
+ }
3775
+ if (typeof result.keywordScore === "number") {
3776
+ scores.push(`keyword: ${result.keywordScore.toFixed(0)}%`);
3777
+ }
3778
+ if (typeof result.rrfScore === "number") {
3779
+ scores.push(`rrf: ${result.rrfScore.toFixed(3)}`);
3780
+ }
3781
+ if (scores.length > 0) {
3782
+ console.log(` ${colors.dim("Scores:")} ${scores.join(" | ")}`);
3783
+ }
3784
+ }
3785
+ if (result.matchedTerms.length > 0) {
3786
+ console.log(` ${colors.dim("Matched:")} ${result.matchedTerms.join(", ")}`);
3787
+ }
3788
+ console.log("");
3789
+ }
3790
+ return 0;
3791
+ } catch (err) {
3792
+ s?.stop(colors.error("Hybrid search failed"));
3793
+ console.log(colors.muted(err instanceof Error ? err.message : String(err)));
3794
+ console.log(colors.muted("Falling back to standard search..."));
3795
+ return this.handleSearch(engine, query);
3796
+ }
3797
+ }
3798
+ async buildHybridIndex() {
3799
+ if (!this.quiet) {
3800
+ header("Build Hybrid Search Index");
3801
+ }
3802
+ const index = this.loadIndex();
3803
+ if (!index || index.skills.length === 0) {
3804
+ warn("No skill index found. Run --update first.");
3805
+ return 1;
3806
+ }
3807
+ const s = spinner2();
3808
+ s.start("Initializing...");
3809
+ try {
3810
+ const engine = new RecommendationEngine();
3811
+ engine.loadIndex(index);
3812
+ await engine.buildHybridIndex((progress) => {
3813
+ const percentage = Math.round(progress.current / progress.total * 100);
3814
+ s.message(`${progress.phase}: ${progress.message || ""} (${percentage}%)`);
3815
+ });
3816
+ s.stop(colors.success(`${symbols.success} Built hybrid index for ${index.skills.length} skills`));
3817
+ console.log(colors.muted(" Index stored in: ~/.skillkit/search.db"));
3818
+ console.log(colors.muted(" Use --hybrid flag for vector+keyword search\n"));
3819
+ return 0;
3820
+ } catch (err) {
3821
+ s.stop(colors.error("Failed to build hybrid index"));
3822
+ console.log(colors.muted(err instanceof Error ? err.message : String(err)));
3823
+ return 1;
3824
+ }
3825
+ }
3542
3826
  handleSearch(engine, query) {
3543
3827
  if (!this.quiet && !this.json) {
3544
3828
  header(`Search: "${query}"`);
@@ -5506,12 +5790,12 @@ ${learning.title}
5506
5790
  }
5507
5791
  const outputPath = this.output || `.skillkit/exports/${skillName}/SKILL.md`;
5508
5792
  const { dirname: dirname7 } = await import("path");
5509
- const { existsSync: existsSync21, mkdirSync: mkdirSync9, writeFileSync: writeFileSync10 } = await import("fs");
5793
+ const { existsSync: existsSync21, mkdirSync: mkdirSync10, writeFileSync: writeFileSync11 } = await import("fs");
5510
5794
  const outputDir = dirname7(outputPath);
5511
5795
  if (!existsSync21(outputDir)) {
5512
- mkdirSync9(outputDir, { recursive: true });
5796
+ mkdirSync10(outputDir, { recursive: true });
5513
5797
  }
5514
- writeFileSync10(outputPath, skillContent, "utf-8");
5798
+ writeFileSync11(outputPath, skillContent, "utf-8");
5515
5799
  console.log(chalk18.green(`\u2713 Exported learning as skill: ${skillName}`));
5516
5800
  console.log(chalk18.gray(` Path: ${outputPath}`));
5517
5801
  return 0;
@@ -5527,8 +5811,8 @@ ${learning.title}
5527
5811
  return 1;
5528
5812
  }
5529
5813
  const { existsSync: existsSync21, readFileSync: readFileSync11 } = await import("fs");
5530
- const { resolve: resolve20 } = await import("path");
5531
- const fullPath = resolve20(inputPath);
5814
+ const { resolve: resolve21 } = await import("path");
5815
+ const fullPath = resolve21(inputPath);
5532
5816
  if (!existsSync21(fullPath)) {
5533
5817
  console.error(chalk18.red(`File not found: ${fullPath}`));
5534
5818
  return 1;
@@ -5786,7 +6070,7 @@ ${learning.title}
5786
6070
  // src/commands/settings.ts
5787
6071
  import { Command as Command27, Option as Option26 } from "clipanion";
5788
6072
  import chalk19 from "chalk";
5789
- import { loadConfig as loadConfig3, saveConfig } from "@skillkit/core";
6073
+ import { loadConfig as loadConfig2, saveConfig } from "@skillkit/core";
5790
6074
  var VALID_AGENTS = [
5791
6075
  "claude-code",
5792
6076
  "cursor",
@@ -5846,7 +6130,7 @@ var SettingsCommand = class extends Command27 {
5846
6130
  description: "Reset all settings to defaults"
5847
6131
  });
5848
6132
  async execute() {
5849
- const config = loadConfig3(this.global);
6133
+ const config = loadConfig2(this.global);
5850
6134
  if (this.reset) {
5851
6135
  const defaultConfig = {
5852
6136
  version: 1,
@@ -6608,14 +6892,14 @@ var TeamCommand = class extends Command29 {
6608
6892
  }
6609
6893
  const projectPath = process.cwd();
6610
6894
  const bundlePath = join12(projectPath, ".skillkit", "bundles", `${this.name}.json`);
6611
- const { existsSync: existsSync21, readFileSync: readFileSync11, writeFileSync: writeFileSync10 } = await import("fs");
6895
+ const { existsSync: existsSync21, readFileSync: readFileSync11, writeFileSync: writeFileSync11 } = await import("fs");
6612
6896
  if (!existsSync21(bundlePath)) {
6613
6897
  this.context.stderr.write(chalk21.red(`Bundle "${this.name}" not found. Create it first with bundle-create.
6614
6898
  `));
6615
6899
  return 1;
6616
6900
  }
6617
6901
  const content = readFileSync11(bundlePath, "utf-8");
6618
- writeFileSync10(this.output, content, "utf-8");
6902
+ writeFileSync11(this.output, content, "utf-8");
6619
6903
  this.context.stdout.write(chalk21.green(`\u2713 Bundle exported to: ${this.output}
6620
6904
  `));
6621
6905
  return 0;
@@ -6806,8 +7090,8 @@ var PluginCommand = class extends Command30 {
6806
7090
  if (!existsSync15(pluginsDir)) {
6807
7091
  mkdirSync7(pluginsDir, { recursive: true });
6808
7092
  }
6809
- const { statSync: statSync3 } = await import("fs");
6810
- const sourceStat = statSync3(resolvedSource);
7093
+ const { statSync: statSync4 } = await import("fs");
7094
+ const sourceStat = statSync4(resolvedSource);
6811
7095
  if (sourceStat.isDirectory()) {
6812
7096
  cpSync3(resolvedSource, targetDir, { recursive: true });
6813
7097
  } else {
@@ -9148,27 +9432,245 @@ Recent Errors (${stats.recentErrors.length}):`));
9148
9432
  };
9149
9433
 
9150
9434
  // 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";
9435
+ import { existsSync as existsSync17, readFileSync as readFileSync9, mkdirSync as mkdirSync8, writeFileSync as writeFileSync8, readdirSync as readdirSync3, statSync as statSync3 } from "fs";
9436
+ import { join as join16, basename as basename4, dirname as dirname6, resolve as resolve18 } from "path";
9154
9437
  import chalk27 from "chalk";
9155
9438
  import { Command as Command37, Option as Option36 } from "clipanion";
9439
+ import { generateWellKnownIndex } from "@skillkit/core";
9440
+ function sanitizeSkillName(name) {
9441
+ if (!name || typeof name !== "string") return null;
9442
+ const base = basename4(name);
9443
+ if (base !== name || name.includes("..") || name.includes("/") || name.includes("\\")) {
9444
+ return null;
9445
+ }
9446
+ if (!/^[a-zA-Z0-9._-]+$/.test(name)) {
9447
+ return null;
9448
+ }
9449
+ return name;
9450
+ }
9156
9451
  var PublishCommand = class extends Command37 {
9157
9452
  static paths = [["publish"]];
9158
9453
  static usage = Command37.Usage({
9159
- description: "Publish your skill to the SkillKit marketplace",
9454
+ description: "Generate well-known skills structure for hosting",
9455
+ details: `
9456
+ This command generates the RFC 8615 well-known URI structure for hosting skills.
9457
+
9458
+ The output includes:
9459
+ - .well-known/skills/index.json - Skill manifest for auto-discovery
9460
+ - .well-known/skills/{skill-name}/SKILL.md - Individual skill files
9461
+
9462
+ Users can then install skills via: skillkit add https://your-domain.com
9463
+ `,
9464
+ examples: [
9465
+ ["Generate from current directory", "$0 publish"],
9466
+ ["Generate from specific path", "$0 publish ./my-skills"],
9467
+ ["Generate to custom output directory", "$0 publish --output ./public"],
9468
+ ["Preview without writing", "$0 publish --dry-run"]
9469
+ ]
9470
+ });
9471
+ skillPath = Option36.String({ required: false, name: "path" });
9472
+ output = Option36.String("--output,-o", {
9473
+ description: "Output directory for well-known structure (default: current directory)"
9474
+ });
9475
+ dryRun = Option36.Boolean("--dry-run,-n", false, {
9476
+ description: "Show what would be generated without writing files"
9477
+ });
9478
+ async execute() {
9479
+ const basePath = this.skillPath || process.cwd();
9480
+ const outputDir = this.output || basePath;
9481
+ console.log(chalk27.cyan("Generating well-known skills structure...\n"));
9482
+ const discoveredSkills = this.discoverSkills(basePath);
9483
+ if (discoveredSkills.length === 0) {
9484
+ console.error(chalk27.red("No skills found"));
9485
+ console.error(chalk27.dim("Skills must contain a SKILL.md file with frontmatter"));
9486
+ return 1;
9487
+ }
9488
+ console.log(chalk27.white(`Found ${discoveredSkills.length} skill(s):
9489
+ `));
9490
+ const wellKnownSkills = [];
9491
+ const validSkills = [];
9492
+ for (const skill of discoveredSkills) {
9493
+ const safeName = sanitizeSkillName(skill.name);
9494
+ if (!safeName) {
9495
+ console.log(chalk27.yellow(` ${chalk27.yellow("\u26A0")} Skipping "${skill.name}" (invalid name - must be alphanumeric with hyphens/underscores)`));
9496
+ continue;
9497
+ }
9498
+ const files = this.getSkillFiles(skill.path);
9499
+ console.log(chalk27.dim(` ${chalk27.green("\u25CF")} ${safeName}`));
9500
+ console.log(chalk27.dim(` Description: ${skill.description || "No description"}`));
9501
+ console.log(chalk27.dim(` Files: ${files.join(", ")}`));
9502
+ validSkills.push({ name: skill.name, safeName, description: skill.description, path: skill.path });
9503
+ wellKnownSkills.push({
9504
+ name: safeName,
9505
+ description: skill.description,
9506
+ files
9507
+ });
9508
+ }
9509
+ if (validSkills.length === 0) {
9510
+ console.error(chalk27.red("\nNo valid skills to publish"));
9511
+ return 1;
9512
+ }
9513
+ console.log("");
9514
+ if (this.dryRun) {
9515
+ console.log(chalk27.yellow("Dry run - not writing files\n"));
9516
+ console.log(chalk27.white("Would generate:"));
9517
+ console.log(chalk27.dim(` ${outputDir}/.well-known/skills/index.json`));
9518
+ for (const skill of wellKnownSkills) {
9519
+ for (const file of skill.files) {
9520
+ console.log(chalk27.dim(` ${outputDir}/.well-known/skills/${skill.name}/${file}`));
9521
+ }
9522
+ }
9523
+ console.log("");
9524
+ console.log(chalk27.white("index.json preview:"));
9525
+ console.log(JSON.stringify(generateWellKnownIndex(wellKnownSkills), null, 2));
9526
+ return 0;
9527
+ }
9528
+ const wellKnownDir = join16(outputDir, ".well-known", "skills");
9529
+ mkdirSync8(wellKnownDir, { recursive: true });
9530
+ for (const skill of validSkills) {
9531
+ const skillDir = join16(wellKnownDir, skill.safeName);
9532
+ const resolvedSkillDir = resolve18(skillDir);
9533
+ const resolvedWellKnownDir = resolve18(wellKnownDir);
9534
+ if (!resolvedSkillDir.startsWith(resolvedWellKnownDir)) {
9535
+ console.log(chalk27.yellow(` Skipping "${skill.name}" (path traversal detected)`));
9536
+ continue;
9537
+ }
9538
+ mkdirSync8(skillDir, { recursive: true });
9539
+ const files = this.getSkillFiles(skill.path);
9540
+ for (const file of files) {
9541
+ const safeFile = basename4(file);
9542
+ const sourcePath = join16(skill.path, file);
9543
+ const destPath = join16(skillDir, safeFile);
9544
+ const content = readFileSync9(sourcePath, "utf-8");
9545
+ writeFileSync8(destPath, content);
9546
+ }
9547
+ }
9548
+ const index = generateWellKnownIndex(wellKnownSkills);
9549
+ writeFileSync8(join16(wellKnownDir, "index.json"), JSON.stringify(index, null, 2));
9550
+ console.log(chalk27.green("Generated well-known structure:\n"));
9551
+ console.log(chalk27.dim(` ${wellKnownDir}/index.json`));
9552
+ for (const skill of wellKnownSkills) {
9553
+ console.log(chalk27.dim(` ${wellKnownDir}/${skill.name}/`));
9554
+ }
9555
+ console.log("");
9556
+ console.log(chalk27.cyan("Next steps:"));
9557
+ console.log(chalk27.dim(" 1. Deploy the .well-known directory to your web server"));
9558
+ console.log(chalk27.dim(" 2. Users can install via: skillkit add https://your-domain.com"));
9559
+ console.log(chalk27.dim(" 3. Skills auto-discovered from /.well-known/skills/index.json"));
9560
+ return 0;
9561
+ }
9562
+ discoverSkills(basePath) {
9563
+ const skills = [];
9564
+ const skillMdPath = join16(basePath, "SKILL.md");
9565
+ if (existsSync17(skillMdPath)) {
9566
+ const content = readFileSync9(skillMdPath, "utf-8");
9567
+ const frontmatter = this.parseFrontmatter(content);
9568
+ skills.push({
9569
+ name: frontmatter.name || basename4(basePath),
9570
+ description: frontmatter.description,
9571
+ path: basePath
9572
+ });
9573
+ return skills;
9574
+ }
9575
+ const searchDirs = [
9576
+ basePath,
9577
+ join16(basePath, "skills"),
9578
+ join16(basePath, ".claude", "skills")
9579
+ ];
9580
+ for (const searchDir of searchDirs) {
9581
+ if (!existsSync17(searchDir)) continue;
9582
+ const entries = readdirSync3(searchDir);
9583
+ for (const entry of entries) {
9584
+ const entryPath = join16(searchDir, entry);
9585
+ if (!statSync3(entryPath).isDirectory()) continue;
9586
+ const entrySkillMd = join16(entryPath, "SKILL.md");
9587
+ if (existsSync17(entrySkillMd)) {
9588
+ const content = readFileSync9(entrySkillMd, "utf-8");
9589
+ const frontmatter = this.parseFrontmatter(content);
9590
+ skills.push({
9591
+ name: frontmatter.name || entry,
9592
+ description: frontmatter.description,
9593
+ path: entryPath
9594
+ });
9595
+ }
9596
+ }
9597
+ }
9598
+ return skills;
9599
+ }
9600
+ getSkillFiles(skillPath) {
9601
+ const files = [];
9602
+ const entries = readdirSync3(skillPath);
9603
+ for (const entry of entries) {
9604
+ const entryPath = join16(skillPath, entry);
9605
+ if (statSync3(entryPath).isFile()) {
9606
+ if (entry.startsWith(".") || entry === ".skillkit-metadata.json") continue;
9607
+ files.push(entry);
9608
+ }
9609
+ }
9610
+ if (!files.includes("SKILL.md")) {
9611
+ files.unshift("SKILL.md");
9612
+ }
9613
+ return files;
9614
+ }
9615
+ parseFrontmatter(content) {
9616
+ const match = content.match(/^---\r?\n([\s\S]*?)\r?\n---/);
9617
+ if (!match) return {};
9618
+ const frontmatter = {};
9619
+ const lines = match[1].split(/\r?\n/);
9620
+ let inTagsList = false;
9621
+ for (const line of lines) {
9622
+ if (inTagsList) {
9623
+ const tagMatch = line.match(/^\s*-\s*(.+)$/);
9624
+ if (tagMatch) {
9625
+ frontmatter.tags ??= [];
9626
+ frontmatter.tags.push(tagMatch[1].trim().replace(/^["']|["']$/g, ""));
9627
+ continue;
9628
+ }
9629
+ if (line.trim() === "") continue;
9630
+ inTagsList = false;
9631
+ }
9632
+ const colonIdx = line.indexOf(":");
9633
+ if (colonIdx === -1) continue;
9634
+ const key = line.slice(0, colonIdx).trim();
9635
+ const value = line.slice(colonIdx + 1).trim();
9636
+ switch (key) {
9637
+ case "name":
9638
+ frontmatter.name = value.replace(/^["']|["']$/g, "");
9639
+ break;
9640
+ case "description":
9641
+ frontmatter.description = value.replace(/^["']|["']$/g, "");
9642
+ break;
9643
+ case "version":
9644
+ frontmatter.version = value.replace(/^["']|["']$/g, "");
9645
+ break;
9646
+ case "tags":
9647
+ if (value.startsWith("[")) {
9648
+ frontmatter.tags = value.slice(1, -1).split(",").map((t) => t.trim().replace(/^["']|["']$/g, "")).filter((t) => t.length > 0);
9649
+ } else if (value === "") {
9650
+ inTagsList = true;
9651
+ frontmatter.tags = [];
9652
+ }
9653
+ break;
9654
+ }
9655
+ }
9656
+ return frontmatter;
9657
+ }
9658
+ };
9659
+ var PublishSubmitCommand = class extends Command37 {
9660
+ static paths = [["publish", "submit"]];
9661
+ static usage = Command37.Usage({
9662
+ description: "Submit skill to SkillKit marketplace (requires review)",
9160
9663
  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"]
9664
+ ["Submit skill from current directory", "$0 publish submit"],
9665
+ ["Submit with custom name", "$0 publish submit --name my-skill"]
9164
9666
  ]
9165
9667
  });
9166
9668
  skillPath = Option36.String({ required: false, name: "path" });
9167
9669
  name = Option36.String("--name,-n", {
9168
- description: "Custom skill name (default: parsed from SKILL.md)"
9670
+ description: "Custom skill name"
9169
9671
  });
9170
9672
  dryRun = Option36.Boolean("--dry-run", false, {
9171
- description: "Show what would be published without actually publishing"
9673
+ description: "Show what would be submitted"
9172
9674
  });
9173
9675
  async execute() {
9174
9676
  const skillPath = this.skillPath || process.cwd();
@@ -9176,10 +9678,9 @@ var PublishCommand = class extends Command37 {
9176
9678
  if (!skillMdPath) {
9177
9679
  console.error(chalk27.red("No SKILL.md found"));
9178
9680
  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
9681
  return 1;
9181
9682
  }
9182
- console.log(chalk27.cyan("Publishing skill to SkillKit marketplace...\n"));
9683
+ console.log(chalk27.cyan("Submitting skill to SkillKit marketplace...\n"));
9183
9684
  const content = readFileSync9(skillMdPath, "utf-8");
9184
9685
  const frontmatter = this.parseFrontmatter(content);
9185
9686
  const skillName = this.name || frontmatter.name || basename4(dirname6(skillMdPath));
@@ -9198,9 +9699,9 @@ var PublishCommand = class extends Command37 {
9198
9699
  const skillEntry = {
9199
9700
  id: `${repoInfo.owner}/${repoInfo.repo}/${skillSlug}`,
9200
9701
  name: this.formatName(skillName),
9201
- description: frontmatter.description || `Best practices and patterns for ${this.formatName(skillName)}`,
9702
+ description: frontmatter.description || `Best practices for ${this.formatName(skillName)}`,
9202
9703
  source: `${repoInfo.owner}/${repoInfo.repo}`,
9203
- tags: frontmatter.tags || this.inferTags(skillName, frontmatter.description || "")
9704
+ tags: frontmatter.tags || ["general"]
9204
9705
  };
9205
9706
  console.log(chalk27.white("Skill details:"));
9206
9707
  console.log(chalk27.dim(` ID: ${skillEntry.id}`));
@@ -9210,8 +9711,7 @@ var PublishCommand = class extends Command37 {
9210
9711
  console.log(chalk27.dim(` Tags: ${skillEntry.tags.join(", ")}`));
9211
9712
  console.log();
9212
9713
  if (this.dryRun) {
9213
- console.log(chalk27.yellow("Dry run - not publishing"));
9214
- console.log(chalk27.dim("JSON entry that would be added:"));
9714
+ console.log(chalk27.yellow("Dry run - not submitting"));
9215
9715
  console.log(JSON.stringify(skillEntry, null, 2));
9216
9716
  return 0;
9217
9717
  }
@@ -9221,20 +9721,16 @@ var PublishCommand = class extends Command37 {
9221
9721
  const issueUrl = `https://github.com/rohitg00/skillkit/issues/new?title=${issueTitle}&body=${issueBodyEncoded}&labels=skill-submission,publish`;
9222
9722
  console.log(chalk27.green("Opening GitHub to submit your skill...\n"));
9223
9723
  try {
9724
+ const { execSync } = await import("child_process");
9224
9725
  const openCmd = process.platform === "darwin" ? `open "${issueUrl}"` : process.platform === "win32" ? `cmd /c start "" "${issueUrl}"` : `xdg-open "${issueUrl}"`;
9225
9726
  execSync(openCmd, { stdio: "ignore" });
9226
9727
  console.log(chalk27.green("GitHub issue page opened!"));
9227
- console.log(chalk27.dim("Review and submit the issue to publish your skill."));
9728
+ console.log(chalk27.dim("Review and submit the issue."));
9228
9729
  } catch {
9229
9730
  console.log(chalk27.yellow("Could not open browser automatically."));
9230
9731
  console.log(chalk27.dim("Please open this URL manually:\n"));
9231
9732
  console.log(chalk27.cyan(issueUrl));
9232
9733
  }
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
9734
  return 0;
9239
9735
  }
9240
9736
  findSkillMd(basePath) {
@@ -9247,8 +9743,7 @@ var PublishCommand = class extends Command37 {
9247
9743
  }
9248
9744
  const locations = [
9249
9745
  join16(basePath, "skills", "SKILL.md"),
9250
- join16(basePath, ".claude", "skills", "SKILL.md"),
9251
- join16(basePath, ".cursor", "skills", "SKILL.md")
9746
+ join16(basePath, ".claude", "skills", "SKILL.md")
9252
9747
  ];
9253
9748
  for (const loc of locations) {
9254
9749
  if (existsSync17(loc)) {
@@ -9262,18 +9757,7 @@ var PublishCommand = class extends Command37 {
9262
9757
  if (!match) return {};
9263
9758
  const frontmatter = {};
9264
9759
  const lines = match[1].split(/\r?\n/);
9265
- let inTagsList = false;
9266
9760
  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
9761
  const colonIdx = line.indexOf(":");
9278
9762
  if (colonIdx === -1) continue;
9279
9763
  const key = line.slice(0, colonIdx).trim();
@@ -9291,9 +9775,6 @@ var PublishCommand = class extends Command37 {
9291
9775
  case "tags":
9292
9776
  if (value.startsWith("[")) {
9293
9777
  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
9778
  }
9298
9779
  break;
9299
9780
  }
@@ -9305,6 +9786,7 @@ var PublishCommand = class extends Command37 {
9305
9786
  }
9306
9787
  getRepoInfo(dir) {
9307
9788
  try {
9789
+ const { execSync } = __require("child_process");
9308
9790
  const remote = execSync("git remote get-url origin", {
9309
9791
  cwd: dir,
9310
9792
  encoding: "utf-8",
@@ -9321,27 +9803,6 @@ var PublishCommand = class extends Command37 {
9321
9803
  formatName(name) {
9322
9804
  return name.split(/[-_]/).map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
9323
9805
  }
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
9806
  createIssueBody(skill) {
9346
9807
  return `## Publish Skill Request
9347
9808
 
@@ -9364,15 +9825,15 @@ ${JSON.stringify(skill, null, 2)}
9364
9825
  - [ ] Tags are appropriate
9365
9826
 
9366
9827
  ---
9367
- Submitted via \`skillkit publish\``;
9828
+ Submitted via \`skillkit publish submit\``;
9368
9829
  }
9369
9830
  };
9370
9831
 
9371
9832
  // src/commands/agent.ts
9372
9833
  import chalk28 from "chalk";
9373
9834
  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";
9835
+ import { existsSync as existsSync18, mkdirSync as mkdirSync9, writeFileSync as writeFileSync9 } from "fs";
9836
+ import { join as join17, basename as basename5 } from "path";
9376
9837
  import { homedir as homedir3 } from "os";
9377
9838
  import {
9378
9839
  findAllAgents,
@@ -9381,7 +9842,10 @@ import {
9381
9842
  discoverAgentsFromPath,
9382
9843
  validateAgent,
9383
9844
  translateAgent,
9384
- getAgentTargetDirectory
9845
+ getAgentTargetDirectory,
9846
+ discoverSkills as discoverSkills2,
9847
+ readSkillContent as readSkillContent2,
9848
+ generateSubagentFromSkill
9385
9849
  } from "@skillkit/core";
9386
9850
  import {
9387
9851
  getBundledAgents,
@@ -9402,17 +9866,19 @@ var AgentCommand = class extends Command38 {
9402
9866
  that can be invoked with @mentions or the --agent flag.
9403
9867
 
9404
9868
  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
9869
+ agent list - List all installed agents
9870
+ agent show - Show agent details
9871
+ agent create - Create a new agent
9872
+ agent from-skill - Convert a skill to a subagent
9873
+ agent translate - Translate agents between formats
9874
+ agent sync - Sync agents to target AI agent
9875
+ agent validate - Validate agent definitions
9411
9876
  `,
9412
9877
  examples: [
9413
9878
  ["List all agents", "$0 agent list"],
9414
9879
  ["Show agent details", "$0 agent show architect"],
9415
9880
  ["Create new agent", "$0 agent create security-reviewer"],
9881
+ ["Convert skill to subagent", "$0 agent from-skill code-simplifier"],
9416
9882
  ["Translate to Cursor format", "$0 agent translate --to cursor"],
9417
9883
  ["Sync agents", "$0 agent sync --agent claude-code"]
9418
9884
  ]
@@ -9422,6 +9888,7 @@ var AgentCommand = class extends Command38 {
9422
9888
  console.log(" agent list List all installed agents");
9423
9889
  console.log(" agent show <name> Show agent details");
9424
9890
  console.log(" agent create <name> Create a new agent");
9891
+ console.log(" agent from-skill <name> Convert a skill to a subagent");
9425
9892
  console.log(" agent translate Translate agents between formats");
9426
9893
  console.log(" agent sync Sync agents to target AI agent");
9427
9894
  console.log(" agent validate [path] Validate agent definitions");
@@ -9595,7 +10062,7 @@ var AgentCreateCommand = class extends Command38 {
9595
10062
  targetDir = join17(process.cwd(), ".claude", "agents");
9596
10063
  }
9597
10064
  if (!existsSync18(targetDir)) {
9598
- mkdirSync8(targetDir, { recursive: true });
10065
+ mkdirSync9(targetDir, { recursive: true });
9599
10066
  }
9600
10067
  const agentPath = join17(targetDir, `${this.name}.md`);
9601
10068
  if (existsSync18(agentPath)) {
@@ -9604,7 +10071,7 @@ var AgentCreateCommand = class extends Command38 {
9604
10071
  }
9605
10072
  const description = this.description || `${this.name} agent`;
9606
10073
  const content = generateAgentTemplate(this.name, description, this.model);
9607
- writeFileSync8(agentPath, content);
10074
+ writeFileSync9(agentPath, content);
9608
10075
  console.log(chalk28.green(`Created agent: ${agentPath}`));
9609
10076
  console.log();
9610
10077
  console.log(chalk28.dim("Edit the file to customize the agent system prompt."));
@@ -9713,9 +10180,9 @@ var AgentTranslateCommand = class extends Command38 {
9713
10180
  }
9714
10181
  } else {
9715
10182
  if (!existsSync18(outputDir)) {
9716
- mkdirSync8(outputDir, { recursive: true });
10183
+ mkdirSync9(outputDir, { recursive: true });
9717
10184
  }
9718
- writeFileSync8(outputPath, result.content);
10185
+ writeFileSync9(outputPath, result.content);
9719
10186
  console.log(chalk28.green(`\u2713 ${agent.name} \u2192 ${outputPath}`));
9720
10187
  }
9721
10188
  successCount++;
@@ -9759,13 +10226,13 @@ var AgentSyncCommand = class extends Command38 {
9759
10226
  const outputDir = getAgentTargetDirectory(process.cwd(), targetAgent);
9760
10227
  console.log(chalk28.blue(`\u2192 ${targetAgent} (${outputDir})`));
9761
10228
  if (!existsSync18(outputDir)) {
9762
- mkdirSync8(outputDir, { recursive: true });
10229
+ mkdirSync9(outputDir, { recursive: true });
9763
10230
  }
9764
10231
  for (const agent of agents) {
9765
10232
  const result = translateAgent(agent, targetAgent);
9766
10233
  if (result.success) {
9767
10234
  const outputPath = join17(outputDir, result.filename);
9768
- writeFileSync8(outputPath, result.content);
10235
+ writeFileSync9(outputPath, result.content);
9769
10236
  console.log(chalk28.green(` \u2713 ${agent.name}`));
9770
10237
  } else {
9771
10238
  console.log(chalk28.red(` \u2717 ${agent.name}`));
@@ -10039,9 +10506,148 @@ var AgentAvailableCommand = class extends Command38 {
10039
10506
  return 0;
10040
10507
  }
10041
10508
  };
10509
+ var AgentFromSkillCommand = class extends Command38 {
10510
+ static paths = [["agent", "from-skill"]];
10511
+ static usage = Command38.Usage({
10512
+ description: "Convert a skill into a Claude Code subagent",
10513
+ details: `
10514
+ Converts a SkillKit skill into a Claude Code native subagent format.
10515
+ The generated .md file can be used with @mentions in Claude Code.
10516
+
10517
+ By default, the subagent references the skill (skills: [skill-name]).
10518
+ Use --inline to embed the full skill content in the system prompt.
10519
+ `,
10520
+ examples: [
10521
+ ["Convert skill to subagent", "$0 agent from-skill code-simplifier"],
10522
+ ["Create global subagent", "$0 agent from-skill code-simplifier --global"],
10523
+ ["Embed skill content inline", "$0 agent from-skill code-simplifier --inline"],
10524
+ ["Set model for subagent", "$0 agent from-skill code-simplifier --model opus"],
10525
+ ["Preview without writing", "$0 agent from-skill code-simplifier --dry-run"]
10526
+ ]
10527
+ });
10528
+ skillName = Option37.String({ required: true });
10529
+ inline = Option37.Boolean("--inline,-i", false, {
10530
+ description: "Embed full skill content in system prompt"
10531
+ });
10532
+ model = Option37.String("--model,-m", {
10533
+ description: "Model to use (sonnet, opus, haiku, inherit)"
10534
+ });
10535
+ permission = Option37.String("--permission,-p", {
10536
+ description: "Permission mode (default, plan, auto-edit, full-auto, bypassPermissions)"
10537
+ });
10538
+ global = Option37.Boolean("--global,-g", false, {
10539
+ description: "Create in ~/.claude/agents/ instead of .claude/agents/"
10540
+ });
10541
+ output = Option37.String("--output,-o", {
10542
+ description: "Custom output filename (without .md)"
10543
+ });
10544
+ dryRun = Option37.Boolean("--dry-run,-n", false, {
10545
+ description: "Preview without writing files"
10546
+ });
10547
+ async execute() {
10548
+ const skills = discoverSkills2(process.cwd());
10549
+ const skill = skills.find((s) => s.name === this.skillName);
10550
+ if (!skill) {
10551
+ console.log(chalk28.red(`Skill not found: ${this.skillName}`));
10552
+ console.log(chalk28.dim("Available skills:"));
10553
+ for (const s of skills.slice(0, 10)) {
10554
+ console.log(chalk28.dim(` - ${s.name}`));
10555
+ }
10556
+ if (skills.length > 10) {
10557
+ console.log(chalk28.dim(` ... and ${skills.length - 10} more`));
10558
+ }
10559
+ return 1;
10560
+ }
10561
+ const skillContent = readSkillContent2(skill.path);
10562
+ if (!skillContent) {
10563
+ console.log(chalk28.red(`Could not read skill content: ${skill.path}`));
10564
+ return 1;
10565
+ }
10566
+ const options = {
10567
+ inline: this.inline
10568
+ };
10569
+ if (this.model) {
10570
+ const validModels = ["sonnet", "opus", "haiku", "inherit"];
10571
+ if (!validModels.includes(this.model)) {
10572
+ console.log(chalk28.red(`Invalid model: ${this.model}`));
10573
+ console.log(chalk28.dim(`Valid options: ${validModels.join(", ")}`));
10574
+ return 1;
10575
+ }
10576
+ options.model = this.model;
10577
+ }
10578
+ if (this.permission) {
10579
+ const validModes = ["default", "plan", "auto-edit", "full-auto", "bypassPermissions"];
10580
+ if (!validModes.includes(this.permission)) {
10581
+ console.log(chalk28.red(`Invalid permission mode: ${this.permission}`));
10582
+ console.log(chalk28.dim(`Valid options: ${validModes.join(", ")}`));
10583
+ return 1;
10584
+ }
10585
+ options.permissionMode = this.permission;
10586
+ }
10587
+ const content = generateSubagentFromSkill(skill, skillContent, options);
10588
+ const targetDir = this.global ? join17(homedir3(), ".claude", "agents") : join17(process.cwd(), ".claude", "agents");
10589
+ let filename;
10590
+ if (this.output) {
10591
+ const sanitized = sanitizeFilename(this.output);
10592
+ if (!sanitized) {
10593
+ console.log(chalk28.red(`Invalid output filename: ${this.output}`));
10594
+ console.log(chalk28.dim("Filename must contain only alphanumeric characters, hyphens, and underscores"));
10595
+ return 1;
10596
+ }
10597
+ filename = `${sanitized}.md`;
10598
+ } else {
10599
+ const sanitized = sanitizeFilename(skill.name);
10600
+ if (!sanitized) {
10601
+ console.log(chalk28.red(`Invalid skill name for filename: ${skill.name}`));
10602
+ console.log(chalk28.dim("Skill name must contain only alphanumeric characters, hyphens, and underscores"));
10603
+ return 1;
10604
+ }
10605
+ filename = `${sanitized}.md`;
10606
+ }
10607
+ const outputPath = join17(targetDir, filename);
10608
+ if (this.dryRun) {
10609
+ console.log(chalk28.cyan("Preview (dry run):\n"));
10610
+ console.log(chalk28.dim(`Would write to: ${outputPath}`));
10611
+ console.log(chalk28.dim("\u2500".repeat(50)));
10612
+ console.log(content);
10613
+ console.log(chalk28.dim("\u2500".repeat(50)));
10614
+ return 0;
10615
+ }
10616
+ if (!existsSync18(targetDir)) {
10617
+ mkdirSync9(targetDir, { recursive: true });
10618
+ }
10619
+ if (existsSync18(outputPath)) {
10620
+ console.log(chalk28.yellow(`Overwriting existing file: ${outputPath}`));
10621
+ }
10622
+ writeFileSync9(outputPath, content);
10623
+ console.log(chalk28.green(`Created subagent: ${outputPath}`));
10624
+ console.log();
10625
+ console.log(chalk28.dim(`Invoke with: @${skill.name}`));
10626
+ if (!this.inline) {
10627
+ console.log(chalk28.dim(`Skills referenced: ${skill.name}`));
10628
+ } else {
10629
+ console.log(chalk28.dim("Skill content embedded inline"));
10630
+ }
10631
+ return 0;
10632
+ }
10633
+ };
10042
10634
  function formatCategoryName(category) {
10043
10635
  return category.split("-").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
10044
10636
  }
10637
+ function sanitizeFilename(input) {
10638
+ const base = basename5(input);
10639
+ const stem = base.replace(/\.md$/i, "");
10640
+ if (!stem || stem.startsWith(".") || stem.startsWith("-")) {
10641
+ return null;
10642
+ }
10643
+ if (!/^[a-zA-Z0-9][a-zA-Z0-9_-]*$/.test(stem)) {
10644
+ return null;
10645
+ }
10646
+ if (stem.length > 64) {
10647
+ return null;
10648
+ }
10649
+ return stem;
10650
+ }
10045
10651
 
10046
10652
  // src/commands/check.ts
10047
10653
  init_helpers();
@@ -10129,9 +10735,9 @@ var CheckCommand = class extends Command39 {
10129
10735
  const sourceSkillMd = join18(localPath, "SKILL.md");
10130
10736
  const installedSkillMd = join18(skill.path, "SKILL.md");
10131
10737
  if (existsSync19(sourceSkillMd) && existsSync19(installedSkillMd)) {
10132
- const { statSync: statSync3 } = await import("fs");
10133
- const sourceTime = statSync3(sourceSkillMd).mtime;
10134
- const installedTime = statSync3(installedSkillMd).mtime;
10738
+ const { statSync: statSync4 } = await import("fs");
10739
+ const sourceTime = statSync4(sourceSkillMd).mtime;
10740
+ const installedTime = statSync4(installedSkillMd).mtime;
10135
10741
  if (sourceTime > installedTime) {
10136
10742
  results.push({ name: skill.name, hasUpdate: true });
10137
10743
  updatesAvailable++;
@@ -10214,8 +10820,8 @@ import { Command as Command40, Option as Option39 } from "clipanion";
10214
10820
  var skills_default = {
10215
10821
  $schema: "./schema.json",
10216
10822
  version: 1,
10217
- updatedAt: "2026-01-26",
10218
- totalSkills: 15064,
10823
+ updatedAt: "2026-02-02",
10824
+ totalSkills: 15065,
10219
10825
  curatedCollections: 31,
10220
10826
  skills: [
10221
10827
  {
@@ -43325,6 +43931,23 @@ var skills_default = {
43325
43931
  "k8s"
43326
43932
  ]
43327
43933
  },
43934
+ {
43935
+ id: "rohitg00/beautiful-mermaid/beautiful-mermaid",
43936
+ name: "Beautiful Mermaid",
43937
+ description: "Render Mermaid diagrams as beautiful SVGs or ASCII art. 5 diagram types, 15 themes, Shiki integration, zero DOM dependencies.",
43938
+ source: "rohitg00/beautiful-mermaid",
43939
+ tags: [
43940
+ "mermaid",
43941
+ "diagrams",
43942
+ "visualization",
43943
+ "flowchart",
43944
+ "sequence",
43945
+ "uml",
43946
+ "ascii",
43947
+ "svg",
43948
+ "themes"
43949
+ ]
43950
+ },
43328
43951
  {
43329
43952
  id: "itsmostafa/aws-agent-skills/cognito",
43330
43953
  name: "Cognito",
@@ -136210,7 +136833,7 @@ var ManifestGenerateCommand = class extends Command41 {
136210
136833
 
136211
136834
  // src/commands/primer.ts
136212
136835
  import { Command as Command42, Option as Option41 } from "clipanion";
136213
- import { resolve as resolve18 } from "path";
136836
+ import { resolve as resolve19 } from "path";
136214
136837
  import chalk29 from "chalk";
136215
136838
  import {
136216
136839
  AgentType as AgentTypeSchema,
@@ -136278,7 +136901,7 @@ var PrimerCommand = class extends Command42 {
136278
136901
  description: "Number of commits to analyze for learning (default: 100)"
136279
136902
  });
136280
136903
  async execute() {
136281
- const projectPath = resolve18(this.directory || process.cwd());
136904
+ const projectPath = resolve19(this.directory || process.cwd());
136282
136905
  if (this.analyzeOnly) {
136283
136906
  return this.runAnalysis(projectPath);
136284
136907
  }
@@ -136347,7 +136970,7 @@ var PrimerCommand = class extends Command42 {
136347
136970
  const result = generatePrimer(projectPath, {
136348
136971
  agents,
136349
136972
  allAgents: this.allAgents,
136350
- outputDir: this.output ? resolve18(this.output) : void 0,
136973
+ outputDir: this.output ? resolve19(this.output) : void 0,
136351
136974
  dryRun: this.dryRun,
136352
136975
  verbose: this.verbose,
136353
136976
  includeExamples: this.includeExamples
@@ -137558,7 +138181,7 @@ Sent Messages (${messages.length})
137558
138181
 
137559
138182
  // src/commands/learn.ts
137560
138183
  import { Command as Command45, Option as Option44 } from "clipanion";
137561
- import { resolve as resolve19 } from "path";
138184
+ import { resolve as resolve20 } from "path";
137562
138185
  import chalk32 from "chalk";
137563
138186
  import {
137564
138187
  analyzeGitHistory as analyzeGitHistory2,
@@ -137578,7 +138201,7 @@ import {
137578
138201
  getPatternStats,
137579
138202
  clusterPatterns
137580
138203
  } from "@skillkit/core";
137581
- import { writeFileSync as writeFileSync9, readFileSync as readFileSync10, existsSync as existsSync20 } from "fs";
138204
+ import { writeFileSync as writeFileSync10, readFileSync as readFileSync10, existsSync as existsSync20 } from "fs";
137582
138205
  var LearnCommand = class extends Command45 {
137583
138206
  static paths = [["learn"]];
137584
138207
  static usage = Command45.Usage({
@@ -137615,7 +138238,7 @@ var LearnCommand = class extends Command45 {
137615
138238
  description: "Project directory to analyze (default: current directory)"
137616
138239
  });
137617
138240
  async execute() {
137618
- const projectPath = resolve19(this.directory || process.cwd());
138241
+ const projectPath = resolve20(this.directory || process.cwd());
137619
138242
  if (this.show) {
137620
138243
  return this.showPatterns();
137621
138244
  }
@@ -137862,7 +138485,7 @@ var PatternExportCommand = class extends Command45 {
137862
138485
  content = exportPatternsAsJson(patterns);
137863
138486
  }
137864
138487
  if (this.output) {
137865
- writeFileSync9(this.output, content);
138488
+ writeFileSync10(this.output, content);
137866
138489
  console.log(chalk32.green(`\u2713 Exported ${patterns.length} patterns to ${this.output}`));
137867
138490
  } else {
137868
138491
  console.log(content);
@@ -138584,6 +139207,208 @@ function formatCategoryName2(category) {
138584
139207
  return category.split("-").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
138585
139208
  }
138586
139209
 
139210
+ // src/commands/tree.ts
139211
+ init_onboarding();
139212
+ import { Command as Command49, Option as Option48 } from "clipanion";
139213
+ import { join as join19 } from "path";
139214
+ import { homedir as homedir4 } from "os";
139215
+ import {
139216
+ loadIndex as loadIndexFromCache3,
139217
+ generateSkillTree,
139218
+ saveTree,
139219
+ loadTree
139220
+ } from "@skillkit/core";
139221
+ var TREE_PATH = join19(homedir4(), ".skillkit", "skill-tree.json");
139222
+ var TreeCommand = class extends Command49 {
139223
+ static paths = [["tree"]];
139224
+ static usage = Command49.Usage({
139225
+ description: "Browse skills in a hierarchical tree structure",
139226
+ details: `
139227
+ The tree command displays skills organized in a hierarchical taxonomy.
139228
+ Navigate through categories like Development, Testing, DevOps, AI/ML, etc.
139229
+
139230
+ Features:
139231
+ - Visual tree structure of all skills
139232
+ - Filter by category path (e.g., "Frontend > React")
139233
+ - Generate tree from skill index
139234
+ - Export to markdown format
139235
+ `,
139236
+ examples: [
139237
+ ["Show full tree", "$0 tree"],
139238
+ ["Show specific category", "$0 tree Frontend"],
139239
+ ["Show subcategory", '$0 tree "Frontend > React"'],
139240
+ ["Limit depth", "$0 tree --depth 2"],
139241
+ ["Generate/update tree", "$0 tree --generate"],
139242
+ ["Export to markdown", "$0 tree --markdown"],
139243
+ ["Show tree stats", "$0 tree --stats"]
139244
+ ]
139245
+ });
139246
+ treePath = Option48.String({ required: false });
139247
+ depth = Option48.String("--depth,-d", {
139248
+ description: "Maximum depth to display"
139249
+ });
139250
+ generate = Option48.Boolean("--generate,-g", false, {
139251
+ description: "Generate/update tree from skill index"
139252
+ });
139253
+ markdown = Option48.Boolean("--markdown,-m", false, {
139254
+ description: "Output in markdown format"
139255
+ });
139256
+ stats = Option48.Boolean("--stats,-s", false, {
139257
+ description: "Show tree statistics"
139258
+ });
139259
+ json = Option48.Boolean("--json,-j", false, {
139260
+ description: "Output in JSON format"
139261
+ });
139262
+ quiet = Option48.Boolean("--quiet,-q", false, {
139263
+ description: "Minimal output"
139264
+ });
139265
+ async execute() {
139266
+ if (this.generate) {
139267
+ return await this.generateTree();
139268
+ }
139269
+ const tree = this.loadOrGenerateTree();
139270
+ if (!tree) {
139271
+ warn('No skill tree found. Run "skillkit tree --generate" first.');
139272
+ return 1;
139273
+ }
139274
+ if (this.stats) {
139275
+ return this.showStats(tree);
139276
+ }
139277
+ if (this.json) {
139278
+ console.log(JSON.stringify(tree, null, 2));
139279
+ return 0;
139280
+ }
139281
+ if (this.markdown) {
139282
+ const { treeToMarkdown } = await import("@skillkit/core");
139283
+ console.log(treeToMarkdown(tree));
139284
+ return 0;
139285
+ }
139286
+ return this.displayTree(tree);
139287
+ }
139288
+ async generateTree() {
139289
+ if (!this.quiet) {
139290
+ header("Generate Skill Tree");
139291
+ }
139292
+ const index = loadIndexFromCache3();
139293
+ if (!index || index.skills.length === 0) {
139294
+ warn('No skill index found. Run "skillkit recommend --update" first.');
139295
+ return 1;
139296
+ }
139297
+ const s = spinner2();
139298
+ s.start("Generating skill tree...");
139299
+ try {
139300
+ const tree = generateSkillTree(index.skills);
139301
+ saveTree(tree, TREE_PATH);
139302
+ s.stop(`Generated tree with ${tree.totalCategories} categories`);
139303
+ console.log("");
139304
+ console.log(colors.success(`${symbols.success} Tree generated successfully`));
139305
+ console.log(colors.muted(` Total skills: ${tree.totalSkills}`));
139306
+ console.log(colors.muted(` Categories: ${tree.totalCategories}`));
139307
+ console.log(colors.muted(` Max depth: ${tree.maxDepth}`));
139308
+ console.log(colors.muted(` Saved to: ${TREE_PATH}`));
139309
+ console.log("");
139310
+ return 0;
139311
+ } catch (err) {
139312
+ s.stop(colors.error("Failed to generate tree"));
139313
+ console.log(colors.muted(err instanceof Error ? err.message : String(err)));
139314
+ return 1;
139315
+ }
139316
+ }
139317
+ loadOrGenerateTree() {
139318
+ let tree = loadTree(TREE_PATH);
139319
+ if (!tree) {
139320
+ const index = loadIndexFromCache3();
139321
+ if (index && index.skills.length > 0) {
139322
+ tree = generateSkillTree(index.skills);
139323
+ saveTree(tree, TREE_PATH);
139324
+ }
139325
+ }
139326
+ return tree;
139327
+ }
139328
+ showStats(tree) {
139329
+ if (!this.quiet) {
139330
+ header("Skill Tree Statistics");
139331
+ }
139332
+ console.log("");
139333
+ console.log(colors.bold("Overview:"));
139334
+ console.log(` Total Skills: ${colors.accent(String(tree.totalSkills))}`);
139335
+ console.log(` Categories: ${colors.accent(String(tree.totalCategories))}`);
139336
+ console.log(` Max Depth: ${colors.accent(String(tree.maxDepth))}`);
139337
+ console.log(` Generated: ${colors.muted(tree.generatedAt)}`);
139338
+ console.log("");
139339
+ console.log(colors.bold("Top-Level Categories:"));
139340
+ for (const child of tree.rootNode.children) {
139341
+ const percentage = tree.totalSkills > 0 ? (child.skillCount / tree.totalSkills * 100).toFixed(1) : "0.0";
139342
+ console.log(
139343
+ ` ${colors.accent(child.name.padEnd(15))} ${String(child.skillCount).padStart(6)} skills (${percentage}%)`
139344
+ );
139345
+ if (child.children.length > 0) {
139346
+ const subcats = child.children.sort((a, b) => b.skillCount - a.skillCount).slice(0, 3).map((c) => `${c.name} (${c.skillCount})`).join(", ");
139347
+ console.log(` ${colors.muted(subcats)}`);
139348
+ }
139349
+ }
139350
+ console.log("");
139351
+ return 0;
139352
+ }
139353
+ displayTree(tree) {
139354
+ if (!this.quiet) {
139355
+ header("Skill Tree");
139356
+ console.log(colors.muted(`${tree.totalSkills} skills in ${tree.totalCategories} categories`));
139357
+ console.log("");
139358
+ }
139359
+ let targetNode = tree.rootNode;
139360
+ if (this.treePath) {
139361
+ const segments = this.treePath.split(">").map((s) => s.trim());
139362
+ let current = tree.rootNode;
139363
+ for (const segment of segments) {
139364
+ const child = current.children.find(
139365
+ (c) => c.name.toLowerCase() === segment.toLowerCase()
139366
+ );
139367
+ if (!child) {
139368
+ warn(`Category not found: ${segment}`);
139369
+ console.log(colors.muted(`Available categories: ${current.children.map((c) => c.name).join(", ")}`));
139370
+ return 1;
139371
+ }
139372
+ current = child;
139373
+ }
139374
+ targetNode = current;
139375
+ }
139376
+ let maxDepth = this.depth ? parseInt(this.depth, 10) : 3;
139377
+ if (Number.isNaN(maxDepth) || maxDepth < 0) {
139378
+ warn("Invalid depth value. Using default depth of 3.");
139379
+ maxDepth = 3;
139380
+ }
139381
+ this.renderNode(targetNode, "", true, 0, maxDepth);
139382
+ console.log("");
139383
+ console.log(colors.muted('Navigate: skillkit tree "Category > Subcategory"'));
139384
+ console.log(colors.muted("Generate: skillkit tree --generate"));
139385
+ return 0;
139386
+ }
139387
+ renderNode(node, prefix, isLast, depth, maxDepth) {
139388
+ if (depth > maxDepth) return;
139389
+ const connector = depth === 0 ? "" : isLast ? "\u2514\u2500\u2500 " : "\u251C\u2500\u2500 ";
139390
+ const icon = node.children.length > 0 ? "\u{1F4C1} " : "\u{1F4C4} ";
139391
+ const skillInfo = node.skillCount > 0 ? colors.muted(` (${node.skillCount})`) : "";
139392
+ const nameColor = depth === 0 ? colors.bold : depth === 1 ? colors.accent : colors.dim;
139393
+ console.log(`${prefix}${connector}${icon}${nameColor(node.name)}${skillInfo}`);
139394
+ if (depth === maxDepth && node.skills.length > 0 && node.skills.length <= 5) {
139395
+ const childPrefix = prefix + (isLast ? " " : "\u2502 ");
139396
+ for (const skill of node.skills) {
139397
+ console.log(`${childPrefix} \u2022 ${colors.muted(skill)}`);
139398
+ }
139399
+ }
139400
+ const newPrefix = prefix + (depth === 0 ? "" : isLast ? " " : "\u2502 ");
139401
+ if (depth < maxDepth) {
139402
+ node.children.forEach((child, index) => {
139403
+ const childIsLast = index === node.children.length - 1;
139404
+ this.renderNode(child, newPrefix, childIsLast, depth + 1, maxDepth);
139405
+ });
139406
+ } else if (node.children.length > 0) {
139407
+ console.log(`${newPrefix} ${colors.muted(`... ${node.children.length} more subcategories`)}`);
139408
+ }
139409
+ }
139410
+ };
139411
+
138587
139412
  // src/index.ts
138588
139413
  init_helpers();
138589
139414
  export {
@@ -138591,6 +139416,7 @@ export {
138591
139416
  AgentAvailableCommand,
138592
139417
  AgentCommand,
138593
139418
  AgentCreateCommand,
139419
+ AgentFromSkillCommand,
138594
139420
  AgentInstallCommand,
138595
139421
  AgentListCommand,
138596
139422
  AgentShowCommand,
@@ -138651,6 +139477,7 @@ export {
138651
139477
  ProfileListCommand,
138652
139478
  ProfileRemoveCommand,
138653
139479
  PublishCommand,
139480
+ PublishSubmitCommand,
138654
139481
  ReadCommand,
138655
139482
  RecommendCommand,
138656
139483
  RemoveCommand,
@@ -138670,6 +139497,7 @@ export {
138670
139497
  TeamCommand,
138671
139498
  TestCommand,
138672
139499
  TranslateCommand,
139500
+ TreeCommand,
138673
139501
  UICommand,
138674
139502
  UpdateCommand,
138675
139503
  ValidateCommand,