skillkit 1.0.3 → 1.2.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/cli.js CHANGED
@@ -46,6 +46,16 @@ var init_types = __esm({
46
46
  "antigravity",
47
47
  "opencode",
48
48
  "gemini-cli",
49
+ "amp",
50
+ "clawdbot",
51
+ "droid",
52
+ "github-copilot",
53
+ "goose",
54
+ "kilo",
55
+ "kiro-cli",
56
+ "roo",
57
+ "trae",
58
+ "windsurf",
49
59
  "universal"
50
60
  ]);
51
61
  GitProvider = z.enum(["github", "gitlab", "bitbucket", "local"]);
@@ -97,7 +107,7 @@ var init_types = __esm({
97
107
  import { existsSync, readdirSync, readFileSync } from "fs";
98
108
  import { join, basename } from "path";
99
109
  import { parse as parseYaml } from "yaml";
100
- function discoverSkills(dir) {
110
+ function discoverSkillsInDir(dir) {
101
111
  const skills = [];
102
112
  if (!existsSync(dir)) {
103
113
  return skills;
@@ -116,6 +126,68 @@ function discoverSkills(dir) {
116
126
  }
117
127
  return skills;
118
128
  }
129
+ function discoverSkillsRecursive(dir, seen, maxDepth = 5, currentDepth = 0) {
130
+ const skills = [];
131
+ if (currentDepth >= maxDepth || !existsSync(dir)) {
132
+ return skills;
133
+ }
134
+ try {
135
+ const entries = readdirSync(dir, { withFileTypes: true });
136
+ for (const entry of entries) {
137
+ if (entry.name === "node_modules" || entry.name === ".git") {
138
+ continue;
139
+ }
140
+ if (!entry.isDirectory()) continue;
141
+ const entryPath = join(dir, entry.name);
142
+ const skillMdPath = join(entryPath, "SKILL.md");
143
+ if (existsSync(skillMdPath)) {
144
+ const skill = parseSkill(entryPath);
145
+ if (skill && !seen.has(skill.name)) {
146
+ seen.add(skill.name);
147
+ skills.push(skill);
148
+ }
149
+ } else {
150
+ const subSkills = discoverSkillsRecursive(entryPath, seen, maxDepth, currentDepth + 1);
151
+ skills.push(...subSkills);
152
+ }
153
+ }
154
+ } catch {
155
+ }
156
+ return skills;
157
+ }
158
+ function discoverSkills(rootDir) {
159
+ const skills = [];
160
+ const seen = /* @__PURE__ */ new Set();
161
+ const rootSkillMd = join(rootDir, "SKILL.md");
162
+ if (existsSync(rootSkillMd)) {
163
+ const skill = parseSkill(rootDir);
164
+ if (skill && !seen.has(skill.name)) {
165
+ seen.add(skill.name);
166
+ skills.push(skill);
167
+ }
168
+ }
169
+ for (const searchPath of SKILL_DISCOVERY_PATHS) {
170
+ const fullPath = join(rootDir, searchPath);
171
+ if (existsSync(fullPath)) {
172
+ for (const skill of discoverSkillsInDir(fullPath)) {
173
+ if (!seen.has(skill.name)) {
174
+ seen.add(skill.name);
175
+ skills.push(skill);
176
+ }
177
+ }
178
+ }
179
+ }
180
+ for (const skill of discoverSkillsInDir(rootDir)) {
181
+ if (!seen.has(skill.name)) {
182
+ seen.add(skill.name);
183
+ skills.push(skill);
184
+ }
185
+ }
186
+ if (skills.length === 0) {
187
+ skills.push(...discoverSkillsRecursive(rootDir, seen));
188
+ }
189
+ return skills;
190
+ }
119
191
  function parseSkill(skillPath, location = "project") {
120
192
  const skillMdPath = join(skillPath, "SKILL.md");
121
193
  if (!existsSync(skillMdPath)) {
@@ -261,10 +333,35 @@ function isPathInside(child, parent) {
261
333
  const relative = child.replace(parent, "");
262
334
  return !relative.startsWith("..") && !relative.includes("/..");
263
335
  }
336
+ var SKILL_DISCOVERY_PATHS;
264
337
  var init_skills = __esm({
265
338
  "src/core/skills.ts"() {
266
339
  "use strict";
267
340
  init_types();
341
+ SKILL_DISCOVERY_PATHS = [
342
+ "skills",
343
+ "skills/.curated",
344
+ "skills/.experimental",
345
+ "skills/.system",
346
+ ".agents/skills",
347
+ ".agent/skills",
348
+ ".claude/skills",
349
+ ".codex/skills",
350
+ ".cursor/skills",
351
+ ".factory/skills",
352
+ ".gemini/skills",
353
+ ".github/skills",
354
+ ".goose/skills",
355
+ ".kilocode/skills",
356
+ ".kiro/skills",
357
+ ".opencode/skills",
358
+ ".roo/skills",
359
+ ".trae/skills",
360
+ ".windsurf/skills",
361
+ ".clawdbot/skills",
362
+ ".antigravity/skills",
363
+ ".copilot/skills"
364
+ ];
268
365
  }
269
366
  });
270
367
 
@@ -591,7 +688,12 @@ var init_local = __esm({
591
688
  return {
592
689
  success: true,
593
690
  path: actualPath,
594
- skills: skills.map((s) => s.name)
691
+ skills: skills.map((s) => s.name),
692
+ discoveredSkills: skills.map((s) => ({
693
+ name: s.name,
694
+ dirName: basename5(s.path),
695
+ path: s.path
696
+ }))
595
697
  };
596
698
  } catch (error) {
597
699
  const message = error instanceof Error ? error.message : String(error);
@@ -659,29 +761,6 @@ var init_providers = __esm({
659
761
  }
660
762
  });
661
763
 
662
- // src/cli.ts
663
- import { Cli, Builtins } from "clipanion";
664
-
665
- // src/commands/install.ts
666
- init_providers();
667
- import { existsSync as existsSync14, mkdirSync as mkdirSync2, cpSync, rmSync as rmSync4 } from "fs";
668
- import { join as join14 } from "path";
669
- import chalk from "chalk";
670
- import ora from "ora";
671
- import { Command, Option } from "clipanion";
672
-
673
- // src/core/config.ts
674
- init_types();
675
- import { existsSync as existsSync13, readFileSync as readFileSync2, writeFileSync, mkdirSync } from "fs";
676
- import { join as join13, dirname } from "path";
677
- import { homedir as homedir7 } from "os";
678
- import { parse as parseYaml2, stringify as stringifyYaml } from "yaml";
679
-
680
- // src/agents/claude-code.ts
681
- import { existsSync as existsSync6 } from "fs";
682
- import { join as join6 } from "path";
683
- import { homedir as homedir2 } from "os";
684
-
685
764
  // src/agents/base.ts
686
765
  function createSkillXml(skill) {
687
766
  return `<skill>
@@ -693,20 +772,33 @@ function createSkillXml(skill) {
693
772
  function escapeXml(text) {
694
773
  return text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&apos;");
695
774
  }
775
+ var init_base2 = __esm({
776
+ "src/agents/base.ts"() {
777
+ "use strict";
778
+ }
779
+ });
696
780
 
697
781
  // src/agents/claude-code.ts
698
- var ClaudeCodeAdapter = class {
699
- type = "claude-code";
700
- name = "Claude Code";
701
- skillsDir = ".claude/skills";
702
- configFile = "AGENTS.md";
703
- generateConfig(skills) {
704
- const enabledSkills = skills.filter((s) => s.enabled);
705
- if (enabledSkills.length === 0) {
706
- return "";
707
- }
708
- const skillsXml = enabledSkills.map(createSkillXml).join("\n\n");
709
- return `<skills_system priority="1">
782
+ import { existsSync as existsSync6 } from "fs";
783
+ import { join as join6 } from "path";
784
+ import { homedir as homedir2 } from "os";
785
+ var ClaudeCodeAdapter;
786
+ var init_claude_code = __esm({
787
+ "src/agents/claude-code.ts"() {
788
+ "use strict";
789
+ init_base2();
790
+ ClaudeCodeAdapter = class {
791
+ type = "claude-code";
792
+ name = "Claude Code";
793
+ skillsDir = ".claude/skills";
794
+ configFile = "AGENTS.md";
795
+ generateConfig(skills) {
796
+ const enabledSkills = skills.filter((s) => s.enabled);
797
+ if (enabledSkills.length === 0) {
798
+ return "";
799
+ }
800
+ const skillsXml = enabledSkills.map(createSkillXml).join("\n\n");
801
+ return `<skills_system priority="1">
710
802
 
711
803
  ## Available Skills
712
804
 
@@ -733,43 +825,50 @@ ${skillsXml}
733
825
  <!-- SKILLS_TABLE_END -->
734
826
 
735
827
  </skills_system>`;
828
+ }
829
+ parseConfig(content) {
830
+ const skillNames = [];
831
+ const skillRegex = /<name>([^<]+)<\/name>/g;
832
+ let match;
833
+ while ((match = skillRegex.exec(content)) !== null) {
834
+ skillNames.push(match[1].trim());
835
+ }
836
+ return skillNames;
837
+ }
838
+ getInvokeCommand(skillName) {
839
+ return `skillkit read ${skillName}`;
840
+ }
841
+ async isDetected() {
842
+ const projectClaude = join6(process.cwd(), ".claude");
843
+ const globalClaude = join6(homedir2(), ".claude");
844
+ const claudeMd = join6(process.cwd(), "CLAUDE.md");
845
+ return existsSync6(projectClaude) || existsSync6(globalClaude) || existsSync6(claudeMd);
846
+ }
847
+ };
736
848
  }
737
- parseConfig(content) {
738
- const skillNames = [];
739
- const skillRegex = /<name>([^<]+)<\/name>/g;
740
- let match;
741
- while ((match = skillRegex.exec(content)) !== null) {
742
- skillNames.push(match[1].trim());
743
- }
744
- return skillNames;
745
- }
746
- getInvokeCommand(skillName) {
747
- return `skillkit read ${skillName}`;
748
- }
749
- async isDetected() {
750
- const projectClaude = join6(process.cwd(), ".claude");
751
- const globalClaude = join6(homedir2(), ".claude");
752
- const claudeMd = join6(process.cwd(), "CLAUDE.md");
753
- return existsSync6(projectClaude) || existsSync6(globalClaude) || existsSync6(claudeMd);
754
- }
755
- };
849
+ });
756
850
 
757
851
  // src/agents/cursor.ts
758
852
  import { existsSync as existsSync7 } from "fs";
759
853
  import { join as join7 } from "path";
760
- var CursorAdapter = class {
761
- type = "cursor";
762
- name = "Cursor";
763
- skillsDir = ".cursor/skills";
764
- configFile = ".cursorrules";
765
- generateConfig(skills) {
766
- const enabledSkills = skills.filter((s) => s.enabled);
767
- if (enabledSkills.length === 0) {
768
- return "";
769
- }
770
- const skillsList = enabledSkills.map((s) => `- **${s.name}**: ${s.description}`).join("\n");
771
- const skillsXml = enabledSkills.map(createSkillXml).join("\n\n");
772
- return `# Skills System
854
+ var CursorAdapter;
855
+ var init_cursor = __esm({
856
+ "src/agents/cursor.ts"() {
857
+ "use strict";
858
+ init_base2();
859
+ CursorAdapter = class {
860
+ type = "cursor";
861
+ name = "Cursor";
862
+ skillsDir = ".cursor/skills";
863
+ configFile = ".cursorrules";
864
+ generateConfig(skills) {
865
+ const enabledSkills = skills.filter((s) => s.enabled);
866
+ if (enabledSkills.length === 0) {
867
+ return "";
868
+ }
869
+ const skillsList = enabledSkills.map((s) => `- **${s.name}**: ${s.description}`).join("\n");
870
+ const skillsXml = enabledSkills.map(createSkillXml).join("\n\n");
871
+ return `# Skills System
773
872
 
774
873
  You have access to specialized skills that can help complete tasks. Use the skillkit CLI to load skill instructions when needed.
775
874
 
@@ -790,42 +889,48 @@ The skill will provide detailed instructions for completing the task.
790
889
  ${skillsXml}
791
890
  <!-- SKILLS_DATA_END -->
792
891
  `;
892
+ }
893
+ parseConfig(content) {
894
+ const skillNames = [];
895
+ const skillRegex = /<name>([^<]+)<\/name>/g;
896
+ let match;
897
+ while ((match = skillRegex.exec(content)) !== null) {
898
+ skillNames.push(match[1].trim());
899
+ }
900
+ return skillNames;
901
+ }
902
+ getInvokeCommand(skillName) {
903
+ return `skillkit read ${skillName}`;
904
+ }
905
+ async isDetected() {
906
+ const cursorRules = join7(process.cwd(), ".cursorrules");
907
+ const cursorDir = join7(process.cwd(), ".cursor");
908
+ return existsSync7(cursorRules) || existsSync7(cursorDir);
909
+ }
910
+ };
793
911
  }
794
- parseConfig(content) {
795
- const skillNames = [];
796
- const skillRegex = /<name>([^<]+)<\/name>/g;
797
- let match;
798
- while ((match = skillRegex.exec(content)) !== null) {
799
- skillNames.push(match[1].trim());
800
- }
801
- return skillNames;
802
- }
803
- getInvokeCommand(skillName) {
804
- return `skillkit read ${skillName}`;
805
- }
806
- async isDetected() {
807
- const cursorRules = join7(process.cwd(), ".cursorrules");
808
- const cursorDir = join7(process.cwd(), ".cursor");
809
- return existsSync7(cursorRules) || existsSync7(cursorDir);
810
- }
811
- };
912
+ });
812
913
 
813
914
  // src/agents/codex.ts
814
915
  import { existsSync as existsSync8 } from "fs";
815
916
  import { join as join8 } from "path";
816
917
  import { homedir as homedir3 } from "os";
817
- var CodexAdapter = class {
818
- type = "codex";
819
- name = "OpenAI Codex CLI";
820
- skillsDir = ".codex/skills";
821
- configFile = "AGENTS.md";
822
- generateConfig(skills) {
823
- const enabledSkills = skills.filter((s) => s.enabled);
824
- if (enabledSkills.length === 0) {
825
- return "";
826
- }
827
- const skillsList = enabledSkills.map((s) => `| ${s.name} | ${s.description} | \`skillkit read ${s.name}\` |`).join("\n");
828
- return `# Skills
918
+ var CodexAdapter;
919
+ var init_codex = __esm({
920
+ "src/agents/codex.ts"() {
921
+ "use strict";
922
+ CodexAdapter = class {
923
+ type = "codex";
924
+ name = "OpenAI Codex CLI";
925
+ skillsDir = ".codex/skills";
926
+ configFile = "AGENTS.md";
927
+ generateConfig(skills) {
928
+ const enabledSkills = skills.filter((s) => s.enabled);
929
+ if (enabledSkills.length === 0) {
930
+ return "";
931
+ }
932
+ const skillsList = enabledSkills.map((s) => `| ${s.name} | ${s.description} | \`skillkit read ${s.name}\` |`).join("\n");
933
+ return `# Skills
829
934
 
830
935
  You have access to specialized skills for completing complex tasks.
831
936
 
@@ -843,50 +948,56 @@ skillkit read <skill-name>
843
948
 
844
949
  Skills are loaded on-demand to keep context clean. Only load skills when relevant to the current task.
845
950
  `;
846
- }
847
- parseConfig(content) {
848
- const skillNames = [];
849
- const tableRegex = /^\|\s*([a-z0-9-]+)\s*\|/gm;
850
- let match;
851
- while ((match = tableRegex.exec(content)) !== null) {
852
- const name = match[1].trim();
853
- if (name && name !== "Skill" && name !== "-------") {
854
- skillNames.push(name);
855
951
  }
856
- }
857
- return skillNames;
858
- }
859
- getInvokeCommand(skillName) {
860
- return `skillkit read ${skillName}`;
861
- }
862
- async isDetected() {
863
- const codexDir = join8(process.cwd(), ".codex");
864
- const globalCodex = join8(homedir3(), ".codex");
865
- return existsSync8(codexDir) || existsSync8(globalCodex);
952
+ parseConfig(content) {
953
+ const skillNames = [];
954
+ const tableRegex = /^\|\s*([a-z0-9-]+)\s*\|/gm;
955
+ let match;
956
+ while ((match = tableRegex.exec(content)) !== null) {
957
+ const name = match[1].trim();
958
+ if (name && name !== "Skill" && name !== "-------") {
959
+ skillNames.push(name);
960
+ }
961
+ }
962
+ return skillNames;
963
+ }
964
+ getInvokeCommand(skillName) {
965
+ return `skillkit read ${skillName}`;
966
+ }
967
+ async isDetected() {
968
+ const codexDir = join8(process.cwd(), ".codex");
969
+ const globalCodex = join8(homedir3(), ".codex");
970
+ return existsSync8(codexDir) || existsSync8(globalCodex);
971
+ }
972
+ };
866
973
  }
867
- };
974
+ });
868
975
 
869
976
  // src/agents/gemini-cli.ts
870
977
  import { existsSync as existsSync9 } from "fs";
871
978
  import { join as join9 } from "path";
872
979
  import { homedir as homedir4 } from "os";
873
- var GeminiCliAdapter = class {
874
- type = "gemini-cli";
875
- name = "Gemini CLI";
876
- skillsDir = ".gemini/skills";
877
- configFile = "GEMINI.md";
878
- generateConfig(skills) {
879
- const enabledSkills = skills.filter((s) => s.enabled);
880
- if (enabledSkills.length === 0) {
881
- return "";
882
- }
883
- const skillsJson = enabledSkills.map((s) => ({
884
- name: s.name,
885
- description: s.description,
886
- invoke: `skillkit read ${s.name}`,
887
- location: s.location
888
- }));
889
- return `# Skills Configuration
980
+ var GeminiCliAdapter;
981
+ var init_gemini_cli = __esm({
982
+ "src/agents/gemini-cli.ts"() {
983
+ "use strict";
984
+ GeminiCliAdapter = class {
985
+ type = "gemini-cli";
986
+ name = "Gemini CLI";
987
+ skillsDir = ".gemini/skills";
988
+ configFile = "GEMINI.md";
989
+ generateConfig(skills) {
990
+ const enabledSkills = skills.filter((s) => s.enabled);
991
+ if (enabledSkills.length === 0) {
992
+ return "";
993
+ }
994
+ const skillsJson = enabledSkills.map((s) => ({
995
+ name: s.name,
996
+ description: s.description,
997
+ invoke: `skillkit read ${s.name}`,
998
+ location: s.location
999
+ }));
1000
+ return `# Skills Configuration
890
1001
 
891
1002
  You have access to specialized skills that extend your capabilities.
892
1003
 
@@ -909,57 +1020,64 @@ ${JSON.stringify(skillsJson, null, 2)}
909
1020
  2. Skills provide step-by-step instructions for complex tasks
910
1021
  3. Each skill is self-contained with its own resources
911
1022
  `;
912
- }
913
- parseConfig(content) {
914
- const skillNames = [];
915
- const jsonMatch = content.match(/```json\s*([\s\S]*?)```/);
916
- if (jsonMatch) {
917
- try {
918
- const skills = JSON.parse(jsonMatch[1]);
919
- if (Array.isArray(skills)) {
920
- skills.forEach((s) => {
921
- if (s.name) skillNames.push(s.name);
922
- });
1023
+ }
1024
+ parseConfig(content) {
1025
+ const skillNames = [];
1026
+ const jsonMatch = content.match(/```json\s*([\s\S]*?)```/);
1027
+ if (jsonMatch) {
1028
+ try {
1029
+ const skills = JSON.parse(jsonMatch[1]);
1030
+ if (Array.isArray(skills)) {
1031
+ skills.forEach((s) => {
1032
+ if (s.name) skillNames.push(s.name);
1033
+ });
1034
+ }
1035
+ } catch {
1036
+ }
1037
+ }
1038
+ if (skillNames.length === 0) {
1039
+ const headerRegex = /^### ([a-z0-9-]+)$/gm;
1040
+ let match;
1041
+ while ((match = headerRegex.exec(content)) !== null) {
1042
+ skillNames.push(match[1].trim());
1043
+ }
923
1044
  }
924
- } catch {
1045
+ return skillNames;
925
1046
  }
926
- }
927
- if (skillNames.length === 0) {
928
- const headerRegex = /^### ([a-z0-9-]+)$/gm;
929
- let match;
930
- while ((match = headerRegex.exec(content)) !== null) {
931
- skillNames.push(match[1].trim());
1047
+ getInvokeCommand(skillName) {
1048
+ return `skillkit read ${skillName}`;
932
1049
  }
933
- }
934
- return skillNames;
935
- }
936
- getInvokeCommand(skillName) {
937
- return `skillkit read ${skillName}`;
938
- }
939
- async isDetected() {
940
- const geminiMd = join9(process.cwd(), "GEMINI.md");
941
- const geminiDir = join9(process.cwd(), ".gemini");
942
- const globalGemini = join9(homedir4(), ".gemini");
943
- return existsSync9(geminiMd) || existsSync9(geminiDir) || existsSync9(globalGemini);
1050
+ async isDetected() {
1051
+ const geminiMd = join9(process.cwd(), "GEMINI.md");
1052
+ const geminiDir = join9(process.cwd(), ".gemini");
1053
+ const globalGemini = join9(homedir4(), ".gemini");
1054
+ return existsSync9(geminiMd) || existsSync9(geminiDir) || existsSync9(globalGemini);
1055
+ }
1056
+ };
944
1057
  }
945
- };
1058
+ });
946
1059
 
947
1060
  // src/agents/opencode.ts
948
1061
  import { existsSync as existsSync10 } from "fs";
949
1062
  import { join as join10 } from "path";
950
1063
  import { homedir as homedir5 } from "os";
951
- var OpenCodeAdapter = class {
952
- type = "opencode";
953
- name = "OpenCode";
954
- skillsDir = ".opencode/skills";
955
- configFile = "AGENTS.md";
956
- generateConfig(skills) {
957
- const enabledSkills = skills.filter((s) => s.enabled);
958
- if (enabledSkills.length === 0) {
959
- return "";
960
- }
961
- const skillsXml = enabledSkills.map(createSkillXml).join("\n\n");
962
- return `<!-- SKILLKIT_START -->
1064
+ var OpenCodeAdapter;
1065
+ var init_opencode = __esm({
1066
+ "src/agents/opencode.ts"() {
1067
+ "use strict";
1068
+ init_base2();
1069
+ OpenCodeAdapter = class {
1070
+ type = "opencode";
1071
+ name = "OpenCode";
1072
+ skillsDir = ".opencode/skills";
1073
+ configFile = "AGENTS.md";
1074
+ generateConfig(skills) {
1075
+ const enabledSkills = skills.filter((s) => s.enabled);
1076
+ if (enabledSkills.length === 0) {
1077
+ return "";
1078
+ }
1079
+ const skillsXml = enabledSkills.map(createSkillXml).join("\n\n");
1080
+ return `<!-- SKILLKIT_START -->
963
1081
  # Skills
964
1082
 
965
1083
  The following skills are available to help complete tasks:
@@ -979,44 +1097,50 @@ skillkit read <skill-name>
979
1097
  This loads the skill's instructions into context.
980
1098
 
981
1099
  <!-- SKILLKIT_END -->`;
1100
+ }
1101
+ parseConfig(content) {
1102
+ const skillNames = [];
1103
+ const skillRegex = /<name>([^<]+)<\/name>/g;
1104
+ let match;
1105
+ while ((match = skillRegex.exec(content)) !== null) {
1106
+ skillNames.push(match[1].trim());
1107
+ }
1108
+ return skillNames;
1109
+ }
1110
+ getInvokeCommand(skillName) {
1111
+ return `skillkit read ${skillName}`;
1112
+ }
1113
+ async isDetected() {
1114
+ const opencodeDir = join10(process.cwd(), ".opencode");
1115
+ const globalOpencode = join10(homedir5(), ".opencode");
1116
+ return existsSync10(opencodeDir) || existsSync10(globalOpencode);
1117
+ }
1118
+ };
982
1119
  }
983
- parseConfig(content) {
984
- const skillNames = [];
985
- const skillRegex = /<name>([^<]+)<\/name>/g;
986
- let match;
987
- while ((match = skillRegex.exec(content)) !== null) {
988
- skillNames.push(match[1].trim());
989
- }
990
- return skillNames;
991
- }
992
- getInvokeCommand(skillName) {
993
- return `skillkit read ${skillName}`;
994
- }
995
- async isDetected() {
996
- const opencodeDir = join10(process.cwd(), ".opencode");
997
- const globalOpencode = join10(homedir5(), ".opencode");
998
- return existsSync10(opencodeDir) || existsSync10(globalOpencode);
999
- }
1000
- };
1120
+ });
1001
1121
 
1002
1122
  // src/agents/antigravity.ts
1003
1123
  import { existsSync as existsSync11 } from "fs";
1004
1124
  import { join as join11 } from "path";
1005
1125
  import { homedir as homedir6 } from "os";
1006
- var AntigravityAdapter = class {
1007
- type = "antigravity";
1008
- name = "Antigravity";
1009
- skillsDir = ".antigravity/skills";
1010
- configFile = "AGENTS.md";
1011
- generateConfig(skills) {
1012
- const enabledSkills = skills.filter((s) => s.enabled);
1013
- if (enabledSkills.length === 0) {
1014
- return "";
1015
- }
1016
- const skillsYaml = enabledSkills.map((s) => ` - name: ${s.name}
1126
+ var AntigravityAdapter;
1127
+ var init_antigravity = __esm({
1128
+ "src/agents/antigravity.ts"() {
1129
+ "use strict";
1130
+ AntigravityAdapter = class {
1131
+ type = "antigravity";
1132
+ name = "Antigravity";
1133
+ skillsDir = ".antigravity/skills";
1134
+ configFile = "AGENTS.md";
1135
+ generateConfig(skills) {
1136
+ const enabledSkills = skills.filter((s) => s.enabled);
1137
+ if (enabledSkills.length === 0) {
1138
+ return "";
1139
+ }
1140
+ const skillsYaml = enabledSkills.map((s) => ` - name: ${s.name}
1017
1141
  description: "${s.description}"
1018
1142
  invoke: skillkit read ${s.name}`).join("\n");
1019
- return `# Antigravity Skills Configuration
1143
+ return `# Antigravity Skills Configuration
1020
1144
 
1021
1145
  <!-- skills:
1022
1146
  ${skillsYaml}
@@ -1024,65 +1148,782 @@ ${skillsYaml}
1024
1148
 
1025
1149
  ## Available Skills
1026
1150
 
1027
- ${enabledSkills.map((s) => `### ${s.name}
1151
+ ${enabledSkills.map((s) => `### ${s.name}
1152
+
1153
+ ${s.description}
1154
+
1155
+ **Usage:** \`skillkit read ${s.name}\`
1156
+ `).join("\n")}
1157
+
1158
+ ## How Skills Work
1159
+
1160
+ 1. Skills provide specialized knowledge for specific tasks
1161
+ 2. Load a skill when the current task matches its description
1162
+ 3. Skills are loaded on-demand to preserve context window
1163
+ `;
1164
+ }
1165
+ parseConfig(content) {
1166
+ const skillNames = [];
1167
+ const yamlMatch = content.match(/<!-- skills:\s*([\s\S]*?)-->/);
1168
+ if (yamlMatch) {
1169
+ const nameRegex = /name:\s*([a-z0-9-]+)/g;
1170
+ let match;
1171
+ while ((match = nameRegex.exec(yamlMatch[1])) !== null) {
1172
+ skillNames.push(match[1].trim());
1173
+ }
1174
+ }
1175
+ if (skillNames.length === 0) {
1176
+ const headerRegex = /^### ([a-z0-9-]+)$/gm;
1177
+ let match;
1178
+ while ((match = headerRegex.exec(content)) !== null) {
1179
+ skillNames.push(match[1].trim());
1180
+ }
1181
+ }
1182
+ return skillNames;
1183
+ }
1184
+ getInvokeCommand(skillName) {
1185
+ return `skillkit read ${skillName}`;
1186
+ }
1187
+ async isDetected() {
1188
+ const agDir = join11(process.cwd(), ".antigravity");
1189
+ const globalAg = join11(homedir6(), ".antigravity");
1190
+ return existsSync11(agDir) || existsSync11(globalAg);
1191
+ }
1192
+ };
1193
+ }
1194
+ });
1195
+
1196
+ // src/agents/amp.ts
1197
+ import { existsSync as existsSync12 } from "fs";
1198
+ import { join as join12 } from "path";
1199
+ import { homedir as homedir7 } from "os";
1200
+ var AmpAdapter;
1201
+ var init_amp = __esm({
1202
+ "src/agents/amp.ts"() {
1203
+ "use strict";
1204
+ init_base2();
1205
+ AmpAdapter = class {
1206
+ type = "amp";
1207
+ name = "Amp";
1208
+ skillsDir = ".agents/skills";
1209
+ configFile = "AGENTS.md";
1210
+ globalSkillsDir = join12(homedir7(), ".config", "agents", "skills");
1211
+ generateConfig(skills) {
1212
+ const enabledSkills = skills.filter((s) => s.enabled);
1213
+ if (enabledSkills.length === 0) {
1214
+ return "";
1215
+ }
1216
+ const skillsXml = enabledSkills.map(createSkillXml).join("\n\n");
1217
+ return `<skills_system priority="1">
1218
+
1219
+ ## Available Skills
1220
+
1221
+ <!-- SKILLS_TABLE_START -->
1222
+ <usage>
1223
+ When users ask you to perform tasks, check if any of the available skills below can help complete the task more effectively. Skills provide specialized capabilities and domain knowledge.
1224
+
1225
+ How to use skills:
1226
+ - Invoke: \`skillkit read <skill-name>\` or \`npx skillkit read <skill-name>\`
1227
+ - The skill content will load with detailed instructions on how to complete the task
1228
+ - Base directory provided in output for resolving bundled resources (references/, scripts/, assets/)
1229
+
1230
+ Usage notes:
1231
+ - Only use skills listed in <available_skills> below
1232
+ - Do not invoke a skill that is already loaded in your context
1233
+ - Each skill invocation is stateless
1234
+ </usage>
1235
+
1236
+ <available_skills>
1237
+
1238
+ ${skillsXml}
1239
+
1240
+ </available_skills>
1241
+ <!-- SKILLS_TABLE_END -->
1242
+
1243
+ </skills_system>`;
1244
+ }
1245
+ parseConfig(content) {
1246
+ const skillNames = [];
1247
+ const skillRegex = /<name>([^<]+)<\/name>/g;
1248
+ let match;
1249
+ while ((match = skillRegex.exec(content)) !== null) {
1250
+ skillNames.push(match[1].trim());
1251
+ }
1252
+ return skillNames;
1253
+ }
1254
+ getInvokeCommand(skillName) {
1255
+ return `skillkit read ${skillName}`;
1256
+ }
1257
+ async isDetected() {
1258
+ const projectAgents = join12(process.cwd(), ".agents");
1259
+ const globalAgents = join12(homedir7(), ".config", "agents");
1260
+ return existsSync12(projectAgents) || existsSync12(globalAgents);
1261
+ }
1262
+ };
1263
+ }
1264
+ });
1265
+
1266
+ // src/agents/clawdbot.ts
1267
+ import { existsSync as existsSync13 } from "fs";
1268
+ import { join as join13 } from "path";
1269
+ import { homedir as homedir8 } from "os";
1270
+ var ClawdbotAdapter;
1271
+ var init_clawdbot = __esm({
1272
+ "src/agents/clawdbot.ts"() {
1273
+ "use strict";
1274
+ init_base2();
1275
+ ClawdbotAdapter = class {
1276
+ type = "clawdbot";
1277
+ name = "Clawdbot";
1278
+ skillsDir = "skills";
1279
+ configFile = "AGENTS.md";
1280
+ globalSkillsDir = join13(homedir8(), ".clawdbot", "skills");
1281
+ generateConfig(skills) {
1282
+ const enabledSkills = skills.filter((s) => s.enabled);
1283
+ if (enabledSkills.length === 0) {
1284
+ return "";
1285
+ }
1286
+ const skillsXml = enabledSkills.map(createSkillXml).join("\n\n");
1287
+ return `<skills_system priority="1">
1288
+
1289
+ ## Available Skills
1290
+
1291
+ <!-- SKILLS_TABLE_START -->
1292
+ <usage>
1293
+ When users ask you to perform tasks, check if any of the available skills below can help complete the task more effectively. Skills provide specialized capabilities and domain knowledge.
1294
+
1295
+ How to use skills:
1296
+ - Invoke: \`skillkit read <skill-name>\` or \`npx skillkit read <skill-name>\`
1297
+ - The skill content will load with detailed instructions on how to complete the task
1298
+ - Base directory provided in output for resolving bundled resources (references/, scripts/, assets/)
1299
+
1300
+ Usage notes:
1301
+ - Only use skills listed in <available_skills> below
1302
+ - Do not invoke a skill that is already loaded in your context
1303
+ - Each skill invocation is stateless
1304
+ </usage>
1305
+
1306
+ <available_skills>
1307
+
1308
+ ${skillsXml}
1309
+
1310
+ </available_skills>
1311
+ <!-- SKILLS_TABLE_END -->
1312
+
1313
+ </skills_system>`;
1314
+ }
1315
+ parseConfig(content) {
1316
+ const skillNames = [];
1317
+ const skillRegex = /<name>([^<]+)<\/name>/g;
1318
+ let match;
1319
+ while ((match = skillRegex.exec(content)) !== null) {
1320
+ skillNames.push(match[1].trim());
1321
+ }
1322
+ return skillNames;
1323
+ }
1324
+ getInvokeCommand(skillName) {
1325
+ return `skillkit read ${skillName}`;
1326
+ }
1327
+ async isDetected() {
1328
+ const projectSkills = join13(process.cwd(), "skills");
1329
+ const globalClawdbot = join13(homedir8(), ".clawdbot");
1330
+ return existsSync13(globalClawdbot) || existsSync13(projectSkills) && existsSync13(join13(process.cwd(), ".clawdbot"));
1331
+ }
1332
+ };
1333
+ }
1334
+ });
1335
+
1336
+ // src/agents/droid.ts
1337
+ import { existsSync as existsSync14 } from "fs";
1338
+ import { join as join14 } from "path";
1339
+ import { homedir as homedir9 } from "os";
1340
+ var DroidAdapter;
1341
+ var init_droid = __esm({
1342
+ "src/agents/droid.ts"() {
1343
+ "use strict";
1344
+ init_base2();
1345
+ DroidAdapter = class {
1346
+ type = "droid";
1347
+ name = "Droid (Factory)";
1348
+ skillsDir = ".factory/skills";
1349
+ configFile = "AGENTS.md";
1350
+ globalSkillsDir = join14(homedir9(), ".factory", "skills");
1351
+ generateConfig(skills) {
1352
+ const enabledSkills = skills.filter((s) => s.enabled);
1353
+ if (enabledSkills.length === 0) {
1354
+ return "";
1355
+ }
1356
+ const skillsXml = enabledSkills.map(createSkillXml).join("\n\n");
1357
+ return `<skills_system priority="1">
1358
+
1359
+ ## Available Skills
1360
+
1361
+ <!-- SKILLS_TABLE_START -->
1362
+ <usage>
1363
+ When users ask you to perform tasks, check if any of the available skills below can help complete the task more effectively. Skills provide specialized capabilities and domain knowledge.
1364
+
1365
+ How to use skills:
1366
+ - Invoke: \`skillkit read <skill-name>\` or \`npx skillkit read <skill-name>\`
1367
+ - The skill content will load with detailed instructions on how to complete the task
1368
+ - Base directory provided in output for resolving bundled resources (references/, scripts/, assets/)
1369
+
1370
+ Usage notes:
1371
+ - Only use skills listed in <available_skills> below
1372
+ - Do not invoke a skill that is already loaded in your context
1373
+ - Each skill invocation is stateless
1374
+ </usage>
1375
+
1376
+ <available_skills>
1377
+
1378
+ ${skillsXml}
1379
+
1380
+ </available_skills>
1381
+ <!-- SKILLS_TABLE_END -->
1382
+
1383
+ </skills_system>`;
1384
+ }
1385
+ parseConfig(content) {
1386
+ const skillNames = [];
1387
+ const skillRegex = /<name>([^<]+)<\/name>/g;
1388
+ let match;
1389
+ while ((match = skillRegex.exec(content)) !== null) {
1390
+ skillNames.push(match[1].trim());
1391
+ }
1392
+ return skillNames;
1393
+ }
1394
+ getInvokeCommand(skillName) {
1395
+ return `skillkit read ${skillName}`;
1396
+ }
1397
+ async isDetected() {
1398
+ const projectFactory = join14(process.cwd(), ".factory");
1399
+ const globalFactory = join14(homedir9(), ".factory");
1400
+ return existsSync14(projectFactory) || existsSync14(globalFactory);
1401
+ }
1402
+ };
1403
+ }
1404
+ });
1405
+
1406
+ // src/agents/github-copilot.ts
1407
+ import { existsSync as existsSync15 } from "fs";
1408
+ import { join as join15 } from "path";
1409
+ import { homedir as homedir10 } from "os";
1410
+ var GitHubCopilotAdapter;
1411
+ var init_github_copilot = __esm({
1412
+ "src/agents/github-copilot.ts"() {
1413
+ "use strict";
1414
+ init_base2();
1415
+ GitHubCopilotAdapter = class {
1416
+ type = "github-copilot";
1417
+ name = "GitHub Copilot";
1418
+ skillsDir = ".github/skills";
1419
+ configFile = "AGENTS.md";
1420
+ globalSkillsDir = join15(homedir10(), ".copilot", "skills");
1421
+ generateConfig(skills) {
1422
+ const enabledSkills = skills.filter((s) => s.enabled);
1423
+ if (enabledSkills.length === 0) {
1424
+ return "";
1425
+ }
1426
+ const skillsXml = enabledSkills.map(createSkillXml).join("\n\n");
1427
+ return `<skills_system priority="1">
1428
+
1429
+ ## Available Skills
1430
+
1431
+ <!-- SKILLS_TABLE_START -->
1432
+ <usage>
1433
+ When users ask you to perform tasks, check if any of the available skills below can help complete the task more effectively. Skills provide specialized capabilities and domain knowledge.
1434
+
1435
+ How to use skills:
1436
+ - Invoke: \`skillkit read <skill-name>\` or \`npx skillkit read <skill-name>\`
1437
+ - The skill content will load with detailed instructions on how to complete the task
1438
+ - Base directory provided in output for resolving bundled resources (references/, scripts/, assets/)
1439
+
1440
+ Usage notes:
1441
+ - Only use skills listed in <available_skills> below
1442
+ - Do not invoke a skill that is already loaded in your context
1443
+ - Each skill invocation is stateless
1444
+ </usage>
1445
+
1446
+ <available_skills>
1447
+
1448
+ ${skillsXml}
1449
+
1450
+ </available_skills>
1451
+ <!-- SKILLS_TABLE_END -->
1452
+
1453
+ </skills_system>`;
1454
+ }
1455
+ parseConfig(content) {
1456
+ const skillNames = [];
1457
+ const skillRegex = /<name>([^<]+)<\/name>/g;
1458
+ let match;
1459
+ while ((match = skillRegex.exec(content)) !== null) {
1460
+ skillNames.push(match[1].trim());
1461
+ }
1462
+ return skillNames;
1463
+ }
1464
+ getInvokeCommand(skillName) {
1465
+ return `skillkit read ${skillName}`;
1466
+ }
1467
+ async isDetected() {
1468
+ const projectGithub = join15(process.cwd(), ".github", "skills");
1469
+ const globalCopilot = join15(homedir10(), ".copilot");
1470
+ return existsSync15(projectGithub) || existsSync15(globalCopilot);
1471
+ }
1472
+ };
1473
+ }
1474
+ });
1475
+
1476
+ // src/agents/goose.ts
1477
+ import { existsSync as existsSync16 } from "fs";
1478
+ import { join as join16 } from "path";
1479
+ import { homedir as homedir11 } from "os";
1480
+ var GooseAdapter;
1481
+ var init_goose = __esm({
1482
+ "src/agents/goose.ts"() {
1483
+ "use strict";
1484
+ init_base2();
1485
+ GooseAdapter = class {
1486
+ type = "goose";
1487
+ name = "Goose";
1488
+ skillsDir = ".goose/skills";
1489
+ configFile = "AGENTS.md";
1490
+ globalSkillsDir = join16(homedir11(), ".config", "goose", "skills");
1491
+ generateConfig(skills) {
1492
+ const enabledSkills = skills.filter((s) => s.enabled);
1493
+ if (enabledSkills.length === 0) {
1494
+ return "";
1495
+ }
1496
+ const skillsXml = enabledSkills.map(createSkillXml).join("\n\n");
1497
+ return `<skills_system priority="1">
1498
+
1499
+ ## Available Skills
1500
+
1501
+ <!-- SKILLS_TABLE_START -->
1502
+ <usage>
1503
+ When users ask you to perform tasks, check if any of the available skills below can help complete the task more effectively. Skills provide specialized capabilities and domain knowledge.
1504
+
1505
+ How to use skills:
1506
+ - Invoke: \`skillkit read <skill-name>\` or \`npx skillkit read <skill-name>\`
1507
+ - The skill content will load with detailed instructions on how to complete the task
1508
+ - Base directory provided in output for resolving bundled resources (references/, scripts/, assets/)
1509
+
1510
+ Usage notes:
1511
+ - Only use skills listed in <available_skills> below
1512
+ - Do not invoke a skill that is already loaded in your context
1513
+ - Each skill invocation is stateless
1514
+ </usage>
1515
+
1516
+ <available_skills>
1517
+
1518
+ ${skillsXml}
1519
+
1520
+ </available_skills>
1521
+ <!-- SKILLS_TABLE_END -->
1522
+
1523
+ </skills_system>`;
1524
+ }
1525
+ parseConfig(content) {
1526
+ const skillNames = [];
1527
+ const skillRegex = /<name>([^<]+)<\/name>/g;
1528
+ let match;
1529
+ while ((match = skillRegex.exec(content)) !== null) {
1530
+ skillNames.push(match[1].trim());
1531
+ }
1532
+ return skillNames;
1533
+ }
1534
+ getInvokeCommand(skillName) {
1535
+ return `skillkit read ${skillName}`;
1536
+ }
1537
+ async isDetected() {
1538
+ const projectGoose = join16(process.cwd(), ".goose");
1539
+ const globalGoose = join16(homedir11(), ".config", "goose");
1540
+ return existsSync16(projectGoose) || existsSync16(globalGoose);
1541
+ }
1542
+ };
1543
+ }
1544
+ });
1545
+
1546
+ // src/agents/kilo.ts
1547
+ import { existsSync as existsSync17 } from "fs";
1548
+ import { join as join17 } from "path";
1549
+ import { homedir as homedir12 } from "os";
1550
+ var KiloAdapter;
1551
+ var init_kilo = __esm({
1552
+ "src/agents/kilo.ts"() {
1553
+ "use strict";
1554
+ init_base2();
1555
+ KiloAdapter = class {
1556
+ type = "kilo";
1557
+ name = "Kilo Code";
1558
+ skillsDir = ".kilocode/skills";
1559
+ configFile = "AGENTS.md";
1560
+ globalSkillsDir = join17(homedir12(), ".kilocode", "skills");
1561
+ generateConfig(skills) {
1562
+ const enabledSkills = skills.filter((s) => s.enabled);
1563
+ if (enabledSkills.length === 0) {
1564
+ return "";
1565
+ }
1566
+ const skillsXml = enabledSkills.map(createSkillXml).join("\n\n");
1567
+ return `<skills_system priority="1">
1568
+
1569
+ ## Available Skills
1570
+
1571
+ <!-- SKILLS_TABLE_START -->
1572
+ <usage>
1573
+ When users ask you to perform tasks, check if any of the available skills below can help complete the task more effectively. Skills provide specialized capabilities and domain knowledge.
1574
+
1575
+ How to use skills:
1576
+ - Invoke: \`skillkit read <skill-name>\` or \`npx skillkit read <skill-name>\`
1577
+ - The skill content will load with detailed instructions on how to complete the task
1578
+ - Base directory provided in output for resolving bundled resources (references/, scripts/, assets/)
1579
+
1580
+ Usage notes:
1581
+ - Only use skills listed in <available_skills> below
1582
+ - Do not invoke a skill that is already loaded in your context
1583
+ - Each skill invocation is stateless
1584
+ </usage>
1585
+
1586
+ <available_skills>
1587
+
1588
+ ${skillsXml}
1589
+
1590
+ </available_skills>
1591
+ <!-- SKILLS_TABLE_END -->
1592
+
1593
+ </skills_system>`;
1594
+ }
1595
+ parseConfig(content) {
1596
+ const skillNames = [];
1597
+ const skillRegex = /<name>([^<]+)<\/name>/g;
1598
+ let match;
1599
+ while ((match = skillRegex.exec(content)) !== null) {
1600
+ skillNames.push(match[1].trim());
1601
+ }
1602
+ return skillNames;
1603
+ }
1604
+ getInvokeCommand(skillName) {
1605
+ return `skillkit read ${skillName}`;
1606
+ }
1607
+ async isDetected() {
1608
+ const projectKilo = join17(process.cwd(), ".kilocode");
1609
+ const globalKilo = join17(homedir12(), ".kilocode");
1610
+ return existsSync17(projectKilo) || existsSync17(globalKilo);
1611
+ }
1612
+ };
1613
+ }
1614
+ });
1615
+
1616
+ // src/agents/kiro-cli.ts
1617
+ import { existsSync as existsSync18 } from "fs";
1618
+ import { join as join18 } from "path";
1619
+ import { homedir as homedir13 } from "os";
1620
+ var KiroCliAdapter;
1621
+ var init_kiro_cli = __esm({
1622
+ "src/agents/kiro-cli.ts"() {
1623
+ "use strict";
1624
+ init_base2();
1625
+ KiroCliAdapter = class {
1626
+ type = "kiro-cli";
1627
+ name = "Kiro CLI";
1628
+ skillsDir = ".kiro/skills";
1629
+ configFile = "AGENTS.md";
1630
+ globalSkillsDir = join18(homedir13(), ".kiro", "skills");
1631
+ generateConfig(skills) {
1632
+ const enabledSkills = skills.filter((s) => s.enabled);
1633
+ if (enabledSkills.length === 0) {
1634
+ return "";
1635
+ }
1636
+ const skillsXml = enabledSkills.map(createSkillXml).join("\n\n");
1637
+ return `<skills_system priority="1">
1638
+
1639
+ ## Available Skills
1640
+
1641
+ <!-- SKILLS_TABLE_START -->
1642
+ <usage>
1643
+ When users ask you to perform tasks, check if any of the available skills below can help complete the task more effectively. Skills provide specialized capabilities and domain knowledge.
1644
+
1645
+ How to use skills:
1646
+ - Invoke: \`skillkit read <skill-name>\` or \`npx skillkit read <skill-name>\`
1647
+ - The skill content will load with detailed instructions on how to complete the task
1648
+ - Base directory provided in output for resolving bundled resources (references/, scripts/, assets/)
1649
+
1650
+ Usage notes:
1651
+ - Only use skills listed in <available_skills> below
1652
+ - Do not invoke a skill that is already loaded in your context
1653
+ - Each skill invocation is stateless
1654
+ </usage>
1655
+
1656
+ <available_skills>
1657
+
1658
+ ${skillsXml}
1659
+
1660
+ </available_skills>
1661
+ <!-- SKILLS_TABLE_END -->
1662
+
1663
+ </skills_system>
1664
+
1665
+ **Note for Kiro CLI users:** After installing skills, you need to manually add them to your custom agent's \`resources\` in \`.kiro/agents/<agent>.json\`:
1666
+
1667
+ \`\`\`json
1668
+ {
1669
+ "resources": [
1670
+ "skill://.kiro/skills/**/SKILL.md"
1671
+ ]
1672
+ }
1673
+ \`\`\``;
1674
+ }
1675
+ parseConfig(content) {
1676
+ const skillNames = [];
1677
+ const skillRegex = /<name>([^<]+)<\/name>/g;
1678
+ let match;
1679
+ while ((match = skillRegex.exec(content)) !== null) {
1680
+ skillNames.push(match[1].trim());
1681
+ }
1682
+ return skillNames;
1683
+ }
1684
+ getInvokeCommand(skillName) {
1685
+ return `skillkit read ${skillName}`;
1686
+ }
1687
+ async isDetected() {
1688
+ const projectKiro = join18(process.cwd(), ".kiro");
1689
+ const globalKiro = join18(homedir13(), ".kiro");
1690
+ return existsSync18(projectKiro) || existsSync18(globalKiro);
1691
+ }
1692
+ };
1693
+ }
1694
+ });
1695
+
1696
+ // src/agents/roo.ts
1697
+ import { existsSync as existsSync19 } from "fs";
1698
+ import { join as join19 } from "path";
1699
+ import { homedir as homedir14 } from "os";
1700
+ var RooAdapter;
1701
+ var init_roo = __esm({
1702
+ "src/agents/roo.ts"() {
1703
+ "use strict";
1704
+ init_base2();
1705
+ RooAdapter = class {
1706
+ type = "roo";
1707
+ name = "Roo Code";
1708
+ skillsDir = ".roo/skills";
1709
+ configFile = "AGENTS.md";
1710
+ globalSkillsDir = join19(homedir14(), ".roo", "skills");
1711
+ generateConfig(skills) {
1712
+ const enabledSkills = skills.filter((s) => s.enabled);
1713
+ if (enabledSkills.length === 0) {
1714
+ return "";
1715
+ }
1716
+ const skillsXml = enabledSkills.map(createSkillXml).join("\n\n");
1717
+ return `<skills_system priority="1">
1718
+
1719
+ ## Available Skills
1720
+
1721
+ <!-- SKILLS_TABLE_START -->
1722
+ <usage>
1723
+ When users ask you to perform tasks, check if any of the available skills below can help complete the task more effectively. Skills provide specialized capabilities and domain knowledge.
1724
+
1725
+ How to use skills:
1726
+ - Invoke: \`skillkit read <skill-name>\` or \`npx skillkit read <skill-name>\`
1727
+ - The skill content will load with detailed instructions on how to complete the task
1728
+ - Base directory provided in output for resolving bundled resources (references/, scripts/, assets/)
1729
+
1730
+ Usage notes:
1731
+ - Only use skills listed in <available_skills> below
1732
+ - Do not invoke a skill that is already loaded in your context
1733
+ - Each skill invocation is stateless
1734
+ </usage>
1735
+
1736
+ <available_skills>
1737
+
1738
+ ${skillsXml}
1739
+
1740
+ </available_skills>
1741
+ <!-- SKILLS_TABLE_END -->
1742
+
1743
+ </skills_system>`;
1744
+ }
1745
+ parseConfig(content) {
1746
+ const skillNames = [];
1747
+ const skillRegex = /<name>([^<]+)<\/name>/g;
1748
+ let match;
1749
+ while ((match = skillRegex.exec(content)) !== null) {
1750
+ skillNames.push(match[1].trim());
1751
+ }
1752
+ return skillNames;
1753
+ }
1754
+ getInvokeCommand(skillName) {
1755
+ return `skillkit read ${skillName}`;
1756
+ }
1757
+ async isDetected() {
1758
+ const projectRoo = join19(process.cwd(), ".roo");
1759
+ const globalRoo = join19(homedir14(), ".roo");
1760
+ return existsSync19(projectRoo) || existsSync19(globalRoo);
1761
+ }
1762
+ };
1763
+ }
1764
+ });
1765
+
1766
+ // src/agents/trae.ts
1767
+ import { existsSync as existsSync20 } from "fs";
1768
+ import { join as join20 } from "path";
1769
+ import { homedir as homedir15 } from "os";
1770
+ var TraeAdapter;
1771
+ var init_trae = __esm({
1772
+ "src/agents/trae.ts"() {
1773
+ "use strict";
1774
+ init_base2();
1775
+ TraeAdapter = class {
1776
+ type = "trae";
1777
+ name = "Trae";
1778
+ skillsDir = ".trae/skills";
1779
+ configFile = "AGENTS.md";
1780
+ globalSkillsDir = join20(homedir15(), ".trae", "skills");
1781
+ generateConfig(skills) {
1782
+ const enabledSkills = skills.filter((s) => s.enabled);
1783
+ if (enabledSkills.length === 0) {
1784
+ return "";
1785
+ }
1786
+ const skillsXml = enabledSkills.map(createSkillXml).join("\n\n");
1787
+ return `<skills_system priority="1">
1788
+
1789
+ ## Available Skills
1790
+
1791
+ <!-- SKILLS_TABLE_START -->
1792
+ <usage>
1793
+ When users ask you to perform tasks, check if any of the available skills below can help complete the task more effectively. Skills provide specialized capabilities and domain knowledge.
1794
+
1795
+ How to use skills:
1796
+ - Invoke: \`skillkit read <skill-name>\` or \`npx skillkit read <skill-name>\`
1797
+ - The skill content will load with detailed instructions on how to complete the task
1798
+ - Base directory provided in output for resolving bundled resources (references/, scripts/, assets/)
1799
+
1800
+ Usage notes:
1801
+ - Only use skills listed in <available_skills> below
1802
+ - Do not invoke a skill that is already loaded in your context
1803
+ - Each skill invocation is stateless
1804
+ </usage>
1805
+
1806
+ <available_skills>
1807
+
1808
+ ${skillsXml}
1809
+
1810
+ </available_skills>
1811
+ <!-- SKILLS_TABLE_END -->
1812
+
1813
+ </skills_system>`;
1814
+ }
1815
+ parseConfig(content) {
1816
+ const skillNames = [];
1817
+ const skillRegex = /<name>([^<]+)<\/name>/g;
1818
+ let match;
1819
+ while ((match = skillRegex.exec(content)) !== null) {
1820
+ skillNames.push(match[1].trim());
1821
+ }
1822
+ return skillNames;
1823
+ }
1824
+ getInvokeCommand(skillName) {
1825
+ return `skillkit read ${skillName}`;
1826
+ }
1827
+ async isDetected() {
1828
+ const projectTrae = join20(process.cwd(), ".trae");
1829
+ const globalTrae = join20(homedir15(), ".trae");
1830
+ return existsSync20(projectTrae) || existsSync20(globalTrae);
1831
+ }
1832
+ };
1833
+ }
1834
+ });
1835
+
1836
+ // src/agents/windsurf.ts
1837
+ import { existsSync as existsSync21 } from "fs";
1838
+ import { join as join21 } from "path";
1839
+ import { homedir as homedir16 } from "os";
1840
+ var WindsurfAdapter;
1841
+ var init_windsurf = __esm({
1842
+ "src/agents/windsurf.ts"() {
1843
+ "use strict";
1844
+ init_base2();
1845
+ WindsurfAdapter = class {
1846
+ type = "windsurf";
1847
+ name = "Windsurf";
1848
+ skillsDir = ".windsurf/skills";
1849
+ configFile = "AGENTS.md";
1850
+ globalSkillsDir = join21(homedir16(), ".codeium", "windsurf", "skills");
1851
+ generateConfig(skills) {
1852
+ const enabledSkills = skills.filter((s) => s.enabled);
1853
+ if (enabledSkills.length === 0) {
1854
+ return "";
1855
+ }
1856
+ const skillsXml = enabledSkills.map(createSkillXml).join("\n\n");
1857
+ return `<skills_system priority="1">
1858
+
1859
+ ## Available Skills
1860
+
1861
+ <!-- SKILLS_TABLE_START -->
1862
+ <usage>
1863
+ When users ask you to perform tasks, check if any of the available skills below can help complete the task more effectively. Skills provide specialized capabilities and domain knowledge.
1864
+
1865
+ How to use skills:
1866
+ - Invoke: \`skillkit read <skill-name>\` or \`npx skillkit read <skill-name>\`
1867
+ - The skill content will load with detailed instructions on how to complete the task
1868
+ - Base directory provided in output for resolving bundled resources (references/, scripts/, assets/)
1869
+
1870
+ Usage notes:
1871
+ - Only use skills listed in <available_skills> below
1872
+ - Do not invoke a skill that is already loaded in your context
1873
+ - Each skill invocation is stateless
1874
+ </usage>
1028
1875
 
1029
- ${s.description}
1876
+ <available_skills>
1030
1877
 
1031
- **Usage:** \`skillkit read ${s.name}\`
1032
- `).join("\n")}
1878
+ ${skillsXml}
1033
1879
 
1034
- ## How Skills Work
1880
+ </available_skills>
1881
+ <!-- SKILLS_TABLE_END -->
1035
1882
 
1036
- 1. Skills provide specialized knowledge for specific tasks
1037
- 2. Load a skill when the current task matches its description
1038
- 3. Skills are loaded on-demand to preserve context window
1039
- `;
1040
- }
1041
- parseConfig(content) {
1042
- const skillNames = [];
1043
- const yamlMatch = content.match(/<!-- skills:\s*([\s\S]*?)-->/);
1044
- if (yamlMatch) {
1045
- const nameRegex = /name:\s*([a-z0-9-]+)/g;
1046
- let match;
1047
- while ((match = nameRegex.exec(yamlMatch[1])) !== null) {
1048
- skillNames.push(match[1].trim());
1883
+ </skills_system>`;
1049
1884
  }
1050
- }
1051
- if (skillNames.length === 0) {
1052
- const headerRegex = /^### ([a-z0-9-]+)$/gm;
1053
- let match;
1054
- while ((match = headerRegex.exec(content)) !== null) {
1055
- skillNames.push(match[1].trim());
1885
+ parseConfig(content) {
1886
+ const skillNames = [];
1887
+ const skillRegex = /<name>([^<]+)<\/name>/g;
1888
+ let match;
1889
+ while ((match = skillRegex.exec(content)) !== null) {
1890
+ skillNames.push(match[1].trim());
1891
+ }
1892
+ return skillNames;
1056
1893
  }
1057
- }
1058
- return skillNames;
1059
- }
1060
- getInvokeCommand(skillName) {
1061
- return `skillkit read ${skillName}`;
1062
- }
1063
- async isDetected() {
1064
- const agDir = join11(process.cwd(), ".antigravity");
1065
- const globalAg = join11(homedir6(), ".antigravity");
1066
- return existsSync11(agDir) || existsSync11(globalAg);
1894
+ getInvokeCommand(skillName) {
1895
+ return `skillkit read ${skillName}`;
1896
+ }
1897
+ async isDetected() {
1898
+ const projectWindsurf = join21(process.cwd(), ".windsurf");
1899
+ const globalWindsurf = join21(homedir16(), ".codeium", "windsurf");
1900
+ return existsSync21(projectWindsurf) || existsSync21(globalWindsurf);
1901
+ }
1902
+ };
1067
1903
  }
1068
- };
1904
+ });
1069
1905
 
1070
1906
  // src/agents/universal.ts
1071
- import { existsSync as existsSync12 } from "fs";
1072
- import { join as join12 } from "path";
1073
- var UniversalAdapter = class {
1074
- type = "universal";
1075
- name = "Universal (Any Agent)";
1076
- skillsDir = ".agent/skills";
1077
- configFile = "AGENTS.md";
1078
- generateConfig(skills) {
1079
- const enabledSkills = skills.filter((s) => s.enabled);
1080
- if (enabledSkills.length === 0) {
1081
- return "";
1082
- }
1083
- const skillsXml = enabledSkills.map(createSkillXml).join("\n\n");
1084
- const skillsList = enabledSkills.map((s) => `- **${s.name}**: ${s.description}`).join("\n");
1085
- return `# Skills System
1907
+ import { existsSync as existsSync22 } from "fs";
1908
+ import { join as join22 } from "path";
1909
+ var UniversalAdapter;
1910
+ var init_universal = __esm({
1911
+ "src/agents/universal.ts"() {
1912
+ "use strict";
1913
+ init_base2();
1914
+ UniversalAdapter = class {
1915
+ type = "universal";
1916
+ name = "Universal (Any Agent)";
1917
+ skillsDir = ".agent/skills";
1918
+ configFile = "AGENTS.md";
1919
+ generateConfig(skills) {
1920
+ const enabledSkills = skills.filter((s) => s.enabled);
1921
+ if (enabledSkills.length === 0) {
1922
+ return "";
1923
+ }
1924
+ const skillsXml = enabledSkills.map(createSkillXml).join("\n\n");
1925
+ const skillsList = enabledSkills.map((s) => `- **${s.name}**: ${s.description}`).join("\n");
1926
+ return `# Skills System
1086
1927
 
1087
1928
  <!-- SKILLKIT_SKILLS_START -->
1088
1929
 
@@ -1124,42 +1965,35 @@ ${skillsXml}
1124
1965
 
1125
1966
  <!-- SKILLKIT_SKILLS_END -->
1126
1967
  `;
1127
- }
1128
- parseConfig(content) {
1129
- const skillNames = [];
1130
- const skillRegex = /<name>([^<]+)<\/name>/g;
1131
- let match;
1132
- while ((match = skillRegex.exec(content)) !== null) {
1133
- skillNames.push(match[1].trim());
1134
- }
1135
- if (skillNames.length === 0) {
1136
- const listRegex = /^- \*\*([a-z0-9-]+)\*\*:/gm;
1137
- while ((match = listRegex.exec(content)) !== null) {
1138
- skillNames.push(match[1].trim());
1139
1968
  }
1140
- }
1141
- return skillNames;
1142
- }
1143
- getInvokeCommand(skillName) {
1144
- return `skillkit read ${skillName}`;
1145
- }
1146
- async isDetected() {
1147
- const agentDir = join12(process.cwd(), ".agent");
1148
- const agentsMd = join12(process.cwd(), "AGENTS.md");
1149
- return existsSync12(agentDir) || existsSync12(agentsMd);
1969
+ parseConfig(content) {
1970
+ const skillNames = [];
1971
+ const skillRegex = /<name>([^<]+)<\/name>/g;
1972
+ let match;
1973
+ while ((match = skillRegex.exec(content)) !== null) {
1974
+ skillNames.push(match[1].trim());
1975
+ }
1976
+ if (skillNames.length === 0) {
1977
+ const listRegex = /^- \*\*([a-z0-9-]+)\*\*:/gm;
1978
+ while ((match = listRegex.exec(content)) !== null) {
1979
+ skillNames.push(match[1].trim());
1980
+ }
1981
+ }
1982
+ return skillNames;
1983
+ }
1984
+ getInvokeCommand(skillName) {
1985
+ return `skillkit read ${skillName}`;
1986
+ }
1987
+ async isDetected() {
1988
+ const agentDir = join22(process.cwd(), ".agent");
1989
+ const agentsMd = join22(process.cwd(), "AGENTS.md");
1990
+ return existsSync22(agentDir) || existsSync22(agentsMd);
1991
+ }
1992
+ };
1150
1993
  }
1151
- };
1994
+ });
1152
1995
 
1153
1996
  // src/agents/index.ts
1154
- var adapters = {
1155
- "claude-code": new ClaudeCodeAdapter(),
1156
- cursor: new CursorAdapter(),
1157
- codex: new CodexAdapter(),
1158
- "gemini-cli": new GeminiCliAdapter(),
1159
- opencode: new OpenCodeAdapter(),
1160
- antigravity: new AntigravityAdapter(),
1161
- universal: new UniversalAdapter()
1162
- };
1163
1997
  function getAdapter(type) {
1164
1998
  return adapters[type];
1165
1999
  }
@@ -1174,6 +2008,16 @@ async function detectAgent() {
1174
2008
  "gemini-cli",
1175
2009
  "opencode",
1176
2010
  "antigravity",
2011
+ "amp",
2012
+ "clawdbot",
2013
+ "droid",
2014
+ "github-copilot",
2015
+ "goose",
2016
+ "kilo",
2017
+ "kiro-cli",
2018
+ "roo",
2019
+ "trae",
2020
+ "windsurf",
1177
2021
  "universal"
1178
2022
  ];
1179
2023
  for (const type of checkOrder) {
@@ -1184,20 +2028,82 @@ async function detectAgent() {
1184
2028
  }
1185
2029
  return "universal";
1186
2030
  }
2031
+ var adapters;
2032
+ var init_agents = __esm({
2033
+ "src/agents/index.ts"() {
2034
+ "use strict";
2035
+ init_claude_code();
2036
+ init_cursor();
2037
+ init_codex();
2038
+ init_gemini_cli();
2039
+ init_opencode();
2040
+ init_antigravity();
2041
+ init_amp();
2042
+ init_clawdbot();
2043
+ init_droid();
2044
+ init_github_copilot();
2045
+ init_goose();
2046
+ init_kilo();
2047
+ init_kiro_cli();
2048
+ init_roo();
2049
+ init_trae();
2050
+ init_windsurf();
2051
+ init_universal();
2052
+ init_base2();
2053
+ init_claude_code();
2054
+ init_cursor();
2055
+ init_codex();
2056
+ init_gemini_cli();
2057
+ init_opencode();
2058
+ init_antigravity();
2059
+ init_amp();
2060
+ init_clawdbot();
2061
+ init_droid();
2062
+ init_github_copilot();
2063
+ init_goose();
2064
+ init_kilo();
2065
+ init_kiro_cli();
2066
+ init_roo();
2067
+ init_trae();
2068
+ init_windsurf();
2069
+ init_universal();
2070
+ adapters = {
2071
+ "claude-code": new ClaudeCodeAdapter(),
2072
+ cursor: new CursorAdapter(),
2073
+ codex: new CodexAdapter(),
2074
+ "gemini-cli": new GeminiCliAdapter(),
2075
+ opencode: new OpenCodeAdapter(),
2076
+ antigravity: new AntigravityAdapter(),
2077
+ amp: new AmpAdapter(),
2078
+ clawdbot: new ClawdbotAdapter(),
2079
+ droid: new DroidAdapter(),
2080
+ "github-copilot": new GitHubCopilotAdapter(),
2081
+ goose: new GooseAdapter(),
2082
+ kilo: new KiloAdapter(),
2083
+ "kiro-cli": new KiroCliAdapter(),
2084
+ roo: new RooAdapter(),
2085
+ trae: new TraeAdapter(),
2086
+ windsurf: new WindsurfAdapter(),
2087
+ universal: new UniversalAdapter()
2088
+ };
2089
+ }
2090
+ });
1187
2091
 
1188
2092
  // src/core/config.ts
1189
- var CONFIG_FILE = "skillkit.yaml";
1190
- var METADATA_FILE = ".skillkit.json";
2093
+ import { existsSync as existsSync23, readFileSync as readFileSync2, writeFileSync, mkdirSync } from "fs";
2094
+ import { join as join23, dirname } from "path";
2095
+ import { homedir as homedir17 } from "os";
2096
+ import { parse as parseYaml2, stringify as stringifyYaml } from "yaml";
1191
2097
  function getProjectConfigPath() {
1192
- return join13(process.cwd(), CONFIG_FILE);
2098
+ return join23(process.cwd(), CONFIG_FILE);
1193
2099
  }
1194
2100
  function getGlobalConfigPath() {
1195
- return join13(homedir7(), ".config", "skillkit", CONFIG_FILE);
2101
+ return join23(homedir17(), ".config", "skillkit", CONFIG_FILE);
1196
2102
  }
1197
2103
  function loadConfig() {
1198
2104
  const projectPath = getProjectConfigPath();
1199
2105
  const globalPath = getGlobalConfigPath();
1200
- if (existsSync13(projectPath)) {
2106
+ if (existsSync23(projectPath)) {
1201
2107
  try {
1202
2108
  const content = readFileSync2(projectPath, "utf-8");
1203
2109
  const data = parseYaml2(content);
@@ -1208,7 +2114,7 @@ function loadConfig() {
1208
2114
  } catch {
1209
2115
  }
1210
2116
  }
1211
- if (existsSync13(globalPath)) {
2117
+ if (existsSync23(globalPath)) {
1212
2118
  try {
1213
2119
  const content = readFileSync2(globalPath, "utf-8");
1214
2120
  const data = parseYaml2(content);
@@ -1228,7 +2134,7 @@ function loadConfig() {
1228
2134
  function saveConfig(config, global = false) {
1229
2135
  const configPath = global ? getGlobalConfigPath() : getProjectConfigPath();
1230
2136
  const dir = dirname(configPath);
1231
- if (!existsSync13(dir)) {
2137
+ if (!existsSync23(dir)) {
1232
2138
  mkdirSync(dir, { recursive: true });
1233
2139
  }
1234
2140
  const content = stringifyYaml(config);
@@ -1238,32 +2144,32 @@ function getSearchDirs(agentType) {
1238
2144
  const type = agentType || loadConfig().agent;
1239
2145
  const adapter = getAdapter(type);
1240
2146
  const dirs = [];
1241
- dirs.push(join13(process.cwd(), adapter.skillsDir));
1242
- dirs.push(join13(process.cwd(), ".agent", "skills"));
1243
- dirs.push(join13(homedir7(), adapter.skillsDir));
1244
- dirs.push(join13(homedir7(), ".agent", "skills"));
2147
+ dirs.push(join23(process.cwd(), adapter.skillsDir));
2148
+ dirs.push(join23(process.cwd(), ".agent", "skills"));
2149
+ dirs.push(join23(homedir17(), adapter.skillsDir));
2150
+ dirs.push(join23(homedir17(), ".agent", "skills"));
1245
2151
  return dirs;
1246
2152
  }
1247
2153
  function getInstallDir(global = false, agentType) {
1248
2154
  const type = agentType || loadConfig().agent;
1249
2155
  const adapter = getAdapter(type);
1250
2156
  if (global) {
1251
- return join13(homedir7(), adapter.skillsDir);
2157
+ return join23(homedir17(), adapter.skillsDir);
1252
2158
  }
1253
- return join13(process.cwd(), adapter.skillsDir);
2159
+ return join23(process.cwd(), adapter.skillsDir);
1254
2160
  }
1255
2161
  function getAgentConfigPath(agentType) {
1256
2162
  const type = agentType || loadConfig().agent;
1257
2163
  const adapter = getAdapter(type);
1258
- return join13(process.cwd(), adapter.configFile);
2164
+ return join23(process.cwd(), adapter.configFile);
1259
2165
  }
1260
2166
  function saveSkillMetadata(skillPath, metadata) {
1261
- const metadataPath = join13(skillPath, METADATA_FILE);
2167
+ const metadataPath = join23(skillPath, METADATA_FILE);
1262
2168
  writeFileSync(metadataPath, JSON.stringify(metadata, null, 2), "utf-8");
1263
2169
  }
1264
2170
  function loadSkillMetadata(skillPath) {
1265
- const metadataPath = join13(skillPath, METADATA_FILE);
1266
- if (!existsSync13(metadataPath)) {
2171
+ const metadataPath = join23(skillPath, METADATA_FILE);
2172
+ if (!existsSync23(metadataPath)) {
1267
2173
  return null;
1268
2174
  }
1269
2175
  try {
@@ -1286,8 +2192,8 @@ function setSkillEnabled(skillPath, enabled) {
1286
2192
  async function initProject(agentType) {
1287
2193
  const type = agentType || await detectAgent();
1288
2194
  const adapter = getAdapter(type);
1289
- const skillsDir = join13(process.cwd(), adapter.skillsDir);
1290
- if (!existsSync13(skillsDir)) {
2195
+ const skillsDir = join23(process.cwd(), adapter.skillsDir);
2196
+ if (!existsSync23(skillsDir)) {
1291
2197
  mkdirSync(skillsDir, { recursive: true });
1292
2198
  }
1293
2199
  const config = {
@@ -1296,16 +2202,825 @@ async function initProject(agentType) {
1296
2202
  autoSync: true
1297
2203
  };
1298
2204
  saveConfig(config);
1299
- const agentConfigPath = join13(process.cwd(), adapter.configFile);
1300
- if (!existsSync13(agentConfigPath)) {
2205
+ const agentConfigPath = join23(process.cwd(), adapter.configFile);
2206
+ if (!existsSync23(agentConfigPath)) {
1301
2207
  writeFileSync(agentConfigPath, `# ${adapter.name} Configuration
1302
2208
 
1303
2209
  `, "utf-8");
1304
2210
  }
1305
2211
  }
2212
+ var CONFIG_FILE, METADATA_FILE;
2213
+ var init_config = __esm({
2214
+ "src/core/config.ts"() {
2215
+ "use strict";
2216
+ init_types();
2217
+ init_agents();
2218
+ CONFIG_FILE = "skillkit.yaml";
2219
+ METADATA_FILE = ".skillkit.json";
2220
+ }
2221
+ });
2222
+
2223
+ // src/tui/theme.ts
2224
+ import chalk11 from "chalk";
2225
+ var colors, symbols, logo;
2226
+ var init_theme = __esm({
2227
+ "src/tui/theme.ts"() {
2228
+ "use strict";
2229
+ colors = {
2230
+ primary: "white",
2231
+ secondary: "white",
2232
+ secondaryDim: "gray",
2233
+ success: "white",
2234
+ danger: "white",
2235
+ warning: "white",
2236
+ background: "bgBlack",
2237
+ borderDim: "gray"
2238
+ };
2239
+ symbols = {
2240
+ pointer: chalk11.white("\u276F"),
2241
+ bullet: "\u25CF",
2242
+ checkboxOn: chalk11.white("\u2714"),
2243
+ checkboxOff: chalk11.dim("\u2716"),
2244
+ check: chalk11.white("\u2713"),
2245
+ star: "\u2605",
2246
+ spinner: ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"]
2247
+ };
2248
+ logo = `
2249
+ \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2557 \u2588\u2588\u2557\u2588\u2588\u2557\u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2557\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557
2250
+ \u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2551 \u2588\u2588\u2554\u255D\u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2554\u255D\u2588\u2588\u2551\u255A\u2550\u2550\u2588\u2588\u2554\u2550\u2550\u255D
2251
+ \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2554\u255D \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2588\u2588\u2588\u2554\u255D \u2588\u2588\u2551 \u2588\u2588\u2551
2252
+ \u255A\u2550\u2550\u2550\u2550\u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2588\u2588\u2557 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2554\u2550\u2588\u2588\u2557 \u2588\u2588\u2551 \u2588\u2588\u2551
2253
+ \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2557\u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2551 \u2588\u2588\u2557\u2588\u2588\u2551 \u2588\u2588\u2551
2254
+ \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u255D\u255A\u2550\u255D\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u255D
2255
+ `;
2256
+ }
2257
+ });
2258
+
2259
+ // src/tui/components/Sidebar.tsx
2260
+ import { Box, Text } from "ink";
2261
+ import { jsx, jsxs } from "react/jsx-runtime";
2262
+ function Sidebar({ screen }) {
2263
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", width: 14, borderStyle: "single", paddingX: 1, children: [
2264
+ /* @__PURE__ */ jsx(Text, { bold: true, color: colors.primary, children: "SkillKit" }),
2265
+ NAV.slice(0, 2).map((item) => /* @__PURE__ */ jsxs(Text, { inverse: screen === item.id, children: [
2266
+ screen === item.id ? symbols.bullet : " ",
2267
+ item.label
2268
+ ] }, item.id)),
2269
+ /* @__PURE__ */ jsx(Text, { children: " " }),
2270
+ NAV.slice(2).map((item) => /* @__PURE__ */ jsxs(Text, { inverse: screen === item.id, children: [
2271
+ screen === item.id ? symbols.bullet : " ",
2272
+ item.label
2273
+ ] }, item.id)),
2274
+ /* @__PURE__ */ jsx(Box, { flexGrow: 1 }),
2275
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "? Help" }),
2276
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "q Quit" })
2277
+ ] });
2278
+ }
2279
+ var NAV;
2280
+ var init_Sidebar = __esm({
2281
+ "src/tui/components/Sidebar.tsx"() {
2282
+ "use strict";
2283
+ init_theme();
2284
+ NAV = [
2285
+ { id: "home", label: "Home" },
2286
+ { id: "browse", label: "Browse" },
2287
+ { id: "installed", label: "List" },
2288
+ { id: "sync", label: "Sync" },
2289
+ { id: "settings", label: "Config" }
2290
+ ];
2291
+ }
2292
+ });
2293
+
2294
+ // src/tui/screens/Home.tsx
2295
+ import { useState, useEffect } from "react";
2296
+ import { Box as Box2, Text as Text2 } from "ink";
2297
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
2298
+ function scramble(target, progress) {
2299
+ return target.split("\n").map((line) => {
2300
+ return line.split("").map((char, i) => {
2301
+ if (char === " ") return char;
2302
+ if (progress > i / line.length * 100) return char;
2303
+ return CHARS[Math.floor(Math.random() * CHARS.length)];
2304
+ }).join("");
2305
+ }).join("\n");
2306
+ }
2307
+ function Home({ cols = 80, rows = 24 }) {
2308
+ const [progress, setProgress] = useState(0);
2309
+ const [display, setDisplay] = useState("");
2310
+ const useLogo = cols < 80 ? logoSmall : logo;
2311
+ useEffect(() => {
2312
+ if (progress >= 100) {
2313
+ setDisplay(useLogo);
2314
+ return;
2315
+ }
2316
+ const t = setInterval(() => {
2317
+ setProgress((p) => {
2318
+ const next = p + 12;
2319
+ setDisplay(scramble(useLogo, next));
2320
+ return next;
2321
+ });
2322
+ }, 35);
2323
+ return () => clearInterval(t);
2324
+ }, [progress, useLogo]);
2325
+ return /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", children: [
2326
+ /* @__PURE__ */ jsx2(Text2, { color: colors.primary, children: display || useLogo }),
2327
+ /* @__PURE__ */ jsx2(Box2, { marginTop: 1, children: /* @__PURE__ */ jsx2(Text2, { children: "Manage AI agent skills from your terminal." }) }),
2328
+ /* @__PURE__ */ jsxs2(Box2, { marginTop: 1, flexDirection: "column", children: [
2329
+ /* @__PURE__ */ jsx2(Text2, { bold: true, children: "Quick Actions:" }),
2330
+ /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: " [b] Browse skills marketplace" }),
2331
+ /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: " [l] View installed skills" }),
2332
+ /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: " [s] Sync skills across agents" }),
2333
+ /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: " [,] Settings" })
2334
+ ] }),
2335
+ rows >= 18 && /* @__PURE__ */ jsxs2(Box2, { marginTop: 1, flexDirection: "column", children: [
2336
+ /* @__PURE__ */ jsx2(Text2, { bold: true, children: "Navigation:" }),
2337
+ /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: " \u2191\u2193 Navigate lists" }),
2338
+ /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: " Enter Select / Confirm" }),
2339
+ /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: " Esc Go back / Home" }),
2340
+ /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: " q Quit" })
2341
+ ] }),
2342
+ /* @__PURE__ */ jsx2(Box2, { marginTop: 1, children: /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: "v1.1.0 - Works with 17 AI agents" }) })
2343
+ ] });
2344
+ }
2345
+ var CHARS, logoSmall;
2346
+ var init_Home = __esm({
2347
+ "src/tui/screens/Home.tsx"() {
2348
+ "use strict";
2349
+ init_theme();
2350
+ CHARS = "01\u2588\u2593\u2592\u2591\u2554\u2557\u255A\u255D\u2551\u2550";
2351
+ logoSmall = `
2352
+ \u2554\u2550\u2557\u2566\u2554\u2550\u2566\u2566 \u2566 \u2566\u2554\u2550\u2566\u2554\u2566\u2557
2353
+ \u255A\u2550\u2557\u2560\u2569\u2557\u2551\u2551 \u2551 \u2560\u2569\u2557\u2551 \u2551
2354
+ \u255A\u2550\u255D\u2569 \u2569\u2569\u2569\u2550\u255D\u2569\u2550\u255D\u2569 \u2569\u2569 \u2569
2355
+ `.trim();
2356
+ }
2357
+ });
2358
+
2359
+ // src/tui/hooks/useMarketplace.ts
2360
+ import { useState as useState2, useCallback, useEffect as useEffect2 } from "react";
2361
+ function useMarketplace() {
2362
+ const [allSkills, setAllSkills] = useState2([]);
2363
+ const [filteredSkills, setFilteredSkills] = useState2([]);
2364
+ const [loading, setLoading] = useState2(false);
2365
+ const [error, setError] = useState2(null);
2366
+ const [currentRepo, setCurrentRepo] = useState2(null);
2367
+ const [fetchedRepos, setFetchedRepos] = useState2(/* @__PURE__ */ new Set());
2368
+ const fetchRepo = useCallback(async (source) => {
2369
+ if (fetchedRepos.has(source)) return;
2370
+ setLoading(true);
2371
+ setError(null);
2372
+ setCurrentRepo(source);
2373
+ try {
2374
+ const provider = detectProvider(source);
2375
+ if (!provider) {
2376
+ throw new Error(`Could not detect provider for: ${source}`);
2377
+ }
2378
+ const result = await provider.clone(source, "", { depth: 1 });
2379
+ if (!result.success || !result.discoveredSkills) {
2380
+ throw new Error(result.error || "Failed to fetch skills");
2381
+ }
2382
+ const repoName = POPULAR_REPOS.find((r) => r.source === source)?.name || source;
2383
+ const newSkills = result.discoveredSkills.map((skill) => ({
2384
+ name: skill.name,
2385
+ source,
2386
+ repoName,
2387
+ description: void 0
2388
+ }));
2389
+ setAllSkills((prev) => {
2390
+ const updated = [...prev, ...newSkills];
2391
+ return updated.sort((a, b) => a.name.localeCompare(b.name));
2392
+ });
2393
+ setFetchedRepos((prev) => /* @__PURE__ */ new Set([...prev, source]));
2394
+ if (result.tempRoot) {
2395
+ const { rmSync: rmSync8 } = await import("fs");
2396
+ rmSync8(result.tempRoot, { recursive: true, force: true });
2397
+ }
2398
+ } catch (err) {
2399
+ setError(err instanceof Error ? err.message : "Failed to fetch repository");
2400
+ } finally {
2401
+ setLoading(false);
2402
+ setCurrentRepo(null);
2403
+ }
2404
+ }, [fetchedRepos]);
2405
+ const fetchAllRepos = useCallback(async () => {
2406
+ setLoading(true);
2407
+ setError(null);
2408
+ for (const repo of POPULAR_REPOS) {
2409
+ if (!fetchedRepos.has(repo.source)) {
2410
+ setCurrentRepo(repo.source);
2411
+ try {
2412
+ await fetchRepo(repo.source);
2413
+ } catch {
2414
+ }
2415
+ }
2416
+ }
2417
+ setLoading(false);
2418
+ setCurrentRepo(null);
2419
+ }, [fetchRepo, fetchedRepos]);
2420
+ const search = useCallback((query) => {
2421
+ if (!query.trim()) {
2422
+ setFilteredSkills(allSkills);
2423
+ } else {
2424
+ const lowerQuery = query.toLowerCase();
2425
+ setFilteredSkills(
2426
+ allSkills.filter(
2427
+ (s) => s.name.toLowerCase().includes(lowerQuery) || s.source.toLowerCase().includes(lowerQuery) || s.repoName.toLowerCase().includes(lowerQuery) || s.description?.toLowerCase().includes(lowerQuery)
2428
+ )
2429
+ );
2430
+ }
2431
+ }, [allSkills]);
2432
+ const refresh = useCallback(() => {
2433
+ setFetchedRepos(/* @__PURE__ */ new Set());
2434
+ setAllSkills([]);
2435
+ setFilteredSkills([]);
2436
+ }, []);
2437
+ useEffect2(() => {
2438
+ setFilteredSkills(allSkills);
2439
+ }, [allSkills]);
2440
+ const skills = filteredSkills.map((s) => ({
2441
+ name: s.name,
2442
+ description: s.description || s.repoName,
2443
+ source: s.source
2444
+ }));
2445
+ return {
2446
+ skills,
2447
+ loading,
2448
+ error,
2449
+ totalCount: allSkills.length,
2450
+ repos: POPULAR_REPOS,
2451
+ currentRepo,
2452
+ refresh,
2453
+ search,
2454
+ fetchRepo,
2455
+ fetchAllRepos
2456
+ };
2457
+ }
2458
+ var POPULAR_REPOS;
2459
+ var init_useMarketplace = __esm({
2460
+ "src/tui/hooks/useMarketplace.ts"() {
2461
+ "use strict";
2462
+ init_providers();
2463
+ POPULAR_REPOS = [
2464
+ { source: "anthropics/skills", name: "Anthropic Official" },
2465
+ { source: "vercel-labs/agent-skills", name: "Vercel Labs" },
2466
+ { source: "expo/skills", name: "Expo / React Native" },
2467
+ { source: "remotion-dev/skills", name: "Remotion Video" },
2468
+ { source: "ComposioHQ/awesome-claude-skills", name: "Composio Awesome" },
2469
+ { source: "travisvn/awesome-claude-skills", name: "Travis Awesome" },
2470
+ { source: "mhattingpete/claude-skills-marketplace", name: "Skills Marketplace" },
2471
+ { source: "coreyhaines31/marketingskills", name: "Marketing Skills" },
2472
+ { source: "obra/superpowers", name: "Superpowers TDD" },
2473
+ { source: "softaworks/agent-toolkit", name: "Softaworks Toolkit" },
2474
+ { source: "wshobson/agents", name: "Dev Patterns" },
2475
+ { source: "langgenius/dify", name: "Dify Frontend" },
2476
+ { source: "trailofbits/skills", name: "Trail of Bits Security" },
2477
+ { source: "better-auth/skills", name: "Better Auth" },
2478
+ { source: "onmax/nuxt-skills", name: "Nuxt / Vue" },
2479
+ { source: "hyf0/vue-skills", name: "Vue Best Practices" },
2480
+ { source: "jezweb/claude-skills", name: "Cloudflare / TanStack" },
2481
+ { source: "elysiajs/skills", name: "ElysiaJS / Bun" },
2482
+ { source: "kadajett/agent-nestjs-skills", name: "NestJS" },
2483
+ { source: "callstackincubator/agent-skills", name: "React Native" },
2484
+ { source: "cloudai-x/threejs-skills", name: "Three.js" },
2485
+ { source: "emalorenzo/three-agent-skills", name: "Three.js Advanced" },
2486
+ { source: "dimillian/skills", name: "SwiftUI iOS" },
2487
+ { source: "stripe/ai", name: "Stripe Payments" },
2488
+ { source: "waynesutton/convexskills", name: "Convex Backend" },
2489
+ { source: "kepano/obsidian-skills", name: "Obsidian Notes" },
2490
+ { source: "jimliu/baoyu-skills", name: "Baoyu Tools" },
2491
+ { source: "giuseppe-trisciuoglio/developer-kit", name: "Shadcn / Radix" },
2492
+ { source: "openrouterteam/agent-skills", name: "OpenRouter SDK" },
2493
+ { source: "intellectronica/agent-skills", name: "Context7" },
2494
+ { source: "boristane/agent-skills", name: "Logging Patterns" },
2495
+ { source: "f/awesome-chatgpt-prompts", name: "ChatGPT Prompts" },
2496
+ { source: "rohitg00/openskills", name: "OpenSkills" }
2497
+ ];
2498
+ }
2499
+ });
2500
+
2501
+ // src/tui/screens/Browse.tsx
2502
+ import { useState as useState3 } from "react";
2503
+ import { existsSync as existsSync30, mkdirSync as mkdirSync5, cpSync as cpSync3, rmSync as rmSync7 } from "fs";
2504
+ import { join as join28 } from "path";
2505
+ import { Box as Box3, Text as Text3, useInput } from "ink";
2506
+ import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
2507
+ function Browse({ rows = 24 }) {
2508
+ const { repos, skills, loading, currentRepo, fetchRepo, fetchAllRepos } = useMarketplace();
2509
+ const [view, setView] = useState3("repos");
2510
+ const [sel, setSel] = useState3(0);
2511
+ const [installing, setInstalling] = useState3(null);
2512
+ const [message, setMessage] = useState3(null);
2513
+ const [selectedSkill, setSelectedSkill] = useState3(null);
2514
+ const [agents, setAgents] = useState3([]);
2515
+ const items = view === "repos" ? repos : view === "skills" ? skills : agents;
2516
+ const maxVisible = Math.max(5, rows - 8);
2517
+ const start = Math.max(0, Math.min(sel - Math.floor(maxVisible / 2), items.length - maxVisible));
2518
+ const visible = items.slice(start, start + maxVisible);
2519
+ const showAgentSelection = async (skillName, source) => {
2520
+ setSelectedSkill({ name: skillName, source });
2521
+ const adapters2 = getAllAdapters();
2522
+ const agentList = [];
2523
+ for (const a of adapters2) {
2524
+ agentList.push({
2525
+ type: a.type,
2526
+ name: a.name,
2527
+ detected: await a.isDetected()
2528
+ });
2529
+ }
2530
+ setAgents(agentList);
2531
+ setView("agents");
2532
+ setSel(0);
2533
+ };
2534
+ const installSkill = async (skillName, source, agentType) => {
2535
+ setInstalling(skillName);
2536
+ setMessage(null);
2537
+ try {
2538
+ const provider = detectProvider(source);
2539
+ if (!provider) {
2540
+ setMessage(`Error: Unknown provider for ${source}`);
2541
+ setInstalling(null);
2542
+ return;
2543
+ }
2544
+ const result = await provider.clone(source, "", { depth: 1 });
2545
+ if (!result.success || !result.discoveredSkills) {
2546
+ setMessage(`Error: ${result.error || "Failed to fetch"}`);
2547
+ setInstalling(null);
2548
+ return;
2549
+ }
2550
+ const skill = result.discoveredSkills.find((s) => s.name === skillName);
2551
+ if (!skill) {
2552
+ setMessage(`Error: Skill ${skillName} not found`);
2553
+ setInstalling(null);
2554
+ return;
2555
+ }
2556
+ const targetAgentType = agentType || await detectAgent();
2557
+ const adapter = getAdapter(targetAgentType);
2558
+ const installDir = getInstallDir(false, targetAgentType);
2559
+ if (!existsSync30(installDir)) {
2560
+ mkdirSync5(installDir, { recursive: true });
2561
+ }
2562
+ const targetPath = join28(installDir, skillName);
2563
+ if (existsSync30(targetPath)) {
2564
+ rmSync7(targetPath, { recursive: true, force: true });
2565
+ }
2566
+ cpSync3(skill.path, targetPath, { recursive: true, dereference: true });
2567
+ const metadata = {
2568
+ name: skillName,
2569
+ description: "",
2570
+ source,
2571
+ sourceType: provider.type,
2572
+ subpath: skillName,
2573
+ installedAt: (/* @__PURE__ */ new Date()).toISOString(),
2574
+ enabled: true
2575
+ };
2576
+ saveSkillMetadata(targetPath, metadata);
2577
+ if (result.tempRoot) {
2578
+ rmSync7(result.tempRoot, { recursive: true, force: true });
2579
+ }
2580
+ setMessage(`\u2713 Installed ${skillName} to ${adapter.name}`);
2581
+ if (!agentType) {
2582
+ setView("skills");
2583
+ }
2584
+ } catch (err) {
2585
+ setMessage(`Error: ${err instanceof Error ? err.message : "Unknown error"}`);
2586
+ } finally {
2587
+ setInstalling(null);
2588
+ if (agentType) {
2589
+ setSelectedSkill(null);
2590
+ }
2591
+ }
2592
+ };
2593
+ useInput((input, key) => {
2594
+ if (loading || installing) return;
2595
+ if (key.upArrow) setSel((i) => Math.max(0, i - 1));
2596
+ else if (key.downArrow) setSel((i) => Math.min(items.length - 1, i + 1));
2597
+ else if (key.return) {
2598
+ if (view === "repos" && repos[sel]) {
2599
+ fetchRepo(repos[sel].source);
2600
+ setView("skills");
2601
+ setSel(0);
2602
+ setMessage(null);
2603
+ } else if (view === "skills" && skills[sel]?.source) {
2604
+ installSkill(skills[sel].name, skills[sel].source);
2605
+ } else if (view === "agents" && agents[sel]) {
2606
+ installSkill(selectedSkill.name, selectedSkill.source, agents[sel].type);
2607
+ }
2608
+ } else if (input === "m" && view === "skills" && skills[sel]?.source) {
2609
+ showAgentSelection(skills[sel].name, skills[sel].source);
2610
+ } else if (input === "r") {
2611
+ if (view === "skills") {
2612
+ setView("repos");
2613
+ setSel(0);
2614
+ setMessage(null);
2615
+ } else if (view === "agents") {
2616
+ setView("skills");
2617
+ setSel(0);
2618
+ }
2619
+ } else if (input === "a" && view === "repos") {
2620
+ fetchAllRepos();
2621
+ setView("skills");
2622
+ setSel(0);
2623
+ }
2624
+ });
2625
+ if (view === "agents") {
2626
+ return /* @__PURE__ */ jsxs3(Box3, { flexDirection: "column", children: [
2627
+ /* @__PURE__ */ jsx3(Text3, { bold: true, color: colors.primary, children: "SELECT AGENT" }),
2628
+ /* @__PURE__ */ jsxs3(Text3, { dimColor: true, children: [
2629
+ 'Install "',
2630
+ selectedSkill?.name,
2631
+ '" to which agent?'
2632
+ ] }),
2633
+ /* @__PURE__ */ jsx3(Text3, { dimColor: true, children: "(All agents supported - directory created if needed)" }),
2634
+ /* @__PURE__ */ jsx3(Box3, { marginTop: 1, flexDirection: "column", children: visible.map((agent, i) => {
2635
+ const idx = start + i;
2636
+ const isSel = idx === sel;
2637
+ const a = agent;
2638
+ const status = a.detected ? "(ready)" : "(will create)";
2639
+ return /* @__PURE__ */ jsxs3(Text3, { inverse: isSel, children: [
2640
+ isSel ? symbols.pointer : " ",
2641
+ " ",
2642
+ a.name.padEnd(20),
2643
+ " ",
2644
+ /* @__PURE__ */ jsx3(Text3, { color: colors.secondaryDim, children: status })
2645
+ ] }, a.type);
2646
+ }) }),
2647
+ /* @__PURE__ */ jsx3(Box3, { marginTop: 1, children: /* @__PURE__ */ jsx3(Text3, { dimColor: true, children: "Enter=install to selected agent r=back q=quit" }) })
2648
+ ] });
2649
+ }
2650
+ return /* @__PURE__ */ jsxs3(Box3, { flexDirection: "column", children: [
2651
+ /* @__PURE__ */ jsx3(Text3, { bold: true, color: colors.primary, children: view === "repos" ? "REPOSITORIES" : "SKILLS" }),
2652
+ loading && /* @__PURE__ */ jsxs3(Text3, { dimColor: true, children: [
2653
+ "Loading ",
2654
+ currentRepo,
2655
+ "..."
2656
+ ] }),
2657
+ installing && /* @__PURE__ */ jsxs3(Text3, { children: [
2658
+ "Installing ",
2659
+ installing,
2660
+ "..."
2661
+ ] }),
2662
+ message && /* @__PURE__ */ jsx3(Text3, { dimColor: true, children: message }),
2663
+ /* @__PURE__ */ jsxs3(Text3, { dimColor: true, children: [
2664
+ items.length,
2665
+ " items"
2666
+ ] }),
2667
+ /* @__PURE__ */ jsxs3(Box3, { marginTop: 1, flexDirection: "column", children: [
2668
+ start > 0 && /* @__PURE__ */ jsxs3(Text3, { dimColor: true, children: [
2669
+ " \u2191 ",
2670
+ start,
2671
+ " more"
2672
+ ] }),
2673
+ visible.map((item, i) => {
2674
+ const idx = start + i;
2675
+ const isSel = idx === sel;
2676
+ const name = view === "repos" ? item.name : item.name;
2677
+ const src = view === "repos" ? item.source : item.source || "";
2678
+ return /* @__PURE__ */ jsxs3(Text3, { inverse: isSel, children: [
2679
+ isSel ? symbols.pointer : " ",
2680
+ name.padEnd(25),
2681
+ " ",
2682
+ /* @__PURE__ */ jsx3(Text3, { color: colors.secondaryDim, children: src })
2683
+ ] }, src + name);
2684
+ }),
2685
+ start + maxVisible < items.length && /* @__PURE__ */ jsxs3(Text3, { dimColor: true, children: [
2686
+ " \u2193 ",
2687
+ items.length - start - maxVisible,
2688
+ " more"
2689
+ ] })
2690
+ ] }),
2691
+ /* @__PURE__ */ jsx3(Box3, { marginTop: 1, children: /* @__PURE__ */ jsx3(Text3, { dimColor: true, children: view === "repos" ? "Enter=fetch a=all q=quit" : "Enter=quick install m=choose agent r=back q=quit" }) })
2692
+ ] });
2693
+ }
2694
+ var init_Browse = __esm({
2695
+ "src/tui/screens/Browse.tsx"() {
2696
+ "use strict";
2697
+ init_theme();
2698
+ init_useMarketplace();
2699
+ init_providers();
2700
+ init_agents();
2701
+ init_config();
2702
+ }
2703
+ });
2704
+
2705
+ // src/tui/hooks/useSkills.ts
2706
+ import { useState as useState4, useEffect as useEffect3 } from "react";
2707
+ function useSkills() {
2708
+ const [skills, setSkills] = useState4([]);
2709
+ const [loading, setLoading] = useState4(true);
2710
+ const [error, setError] = useState4(null);
2711
+ const refresh = () => {
2712
+ setLoading(true);
2713
+ setError(null);
2714
+ try {
2715
+ const searchDirs = getSearchDirs();
2716
+ const foundSkills = findAllSkills(searchDirs);
2717
+ const skillItems = foundSkills.map((s) => ({
2718
+ name: s.name,
2719
+ description: s.description,
2720
+ source: s.metadata?.source,
2721
+ enabled: s.enabled
2722
+ }));
2723
+ setSkills(skillItems);
2724
+ } catch (err) {
2725
+ setError(err instanceof Error ? err.message : "Failed to load skills");
2726
+ } finally {
2727
+ setLoading(false);
2728
+ }
2729
+ };
2730
+ const remove = async (name) => {
2731
+ const { rmSync: rmSync8 } = await import("fs");
2732
+ const foundSkill = skills.find((s) => s.name === name);
2733
+ if (foundSkill) {
2734
+ const searchDirs = getSearchDirs();
2735
+ const allSkills = findAllSkills(searchDirs);
2736
+ const skill = allSkills.find((s) => s.name === name);
2737
+ if (skill) {
2738
+ rmSync8(skill.path, { recursive: true, force: true });
2739
+ refresh();
2740
+ }
2741
+ }
2742
+ };
2743
+ useEffect3(() => {
2744
+ refresh();
2745
+ }, []);
2746
+ return { skills, loading, error, refresh, remove };
2747
+ }
2748
+ var init_useSkills = __esm({
2749
+ "src/tui/hooks/useSkills.ts"() {
2750
+ "use strict";
2751
+ init_config();
2752
+ init_skills();
2753
+ }
2754
+ });
2755
+
2756
+ // src/tui/screens/Installed.tsx
2757
+ import { useState as useState5 } from "react";
2758
+ import { Box as Box4, Text as Text4, useInput as useInput2 } from "ink";
2759
+ import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
2760
+ function Installed({ rows = 24 }) {
2761
+ const { skills, loading, refresh, remove } = useSkills();
2762
+ const [sel, setSel] = useState5(0);
2763
+ const maxVisible = Math.max(5, rows - 6);
2764
+ const start = Math.max(0, Math.min(sel - Math.floor(maxVisible / 2), skills.length - maxVisible));
2765
+ const visible = skills.slice(start, start + maxVisible);
2766
+ useInput2((input, key) => {
2767
+ if (loading) return;
2768
+ if (key.upArrow) setSel((i) => Math.max(0, i - 1));
2769
+ else if (key.downArrow) setSel((i) => Math.min(skills.length - 1, i + 1));
2770
+ else if (input === "r") refresh();
2771
+ else if (input === "d" && skills[sel]) remove(skills[sel].name);
2772
+ });
2773
+ return /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", children: [
2774
+ /* @__PURE__ */ jsx4(Text4, { bold: true, color: colors.primary, children: "INSTALLED SKILLS" }),
2775
+ /* @__PURE__ */ jsxs4(Text4, { dimColor: true, children: [
2776
+ skills.length,
2777
+ " skills"
2778
+ ] }),
2779
+ loading && /* @__PURE__ */ jsx4(Text4, { children: "Loading..." }),
2780
+ !loading && skills.length === 0 && /* @__PURE__ */ jsx4(Text4, { dimColor: true, children: "No skills installed. Press b to browse." }),
2781
+ !loading && skills.length > 0 && /* @__PURE__ */ jsxs4(Box4, { marginTop: 1, flexDirection: "column", children: [
2782
+ start > 0 && /* @__PURE__ */ jsxs4(Text4, { dimColor: true, children: [
2783
+ " \u2191 ",
2784
+ start,
2785
+ " more"
2786
+ ] }),
2787
+ visible.map((skill, i) => {
2788
+ const idx = start + i;
2789
+ const isSel = idx === sel;
2790
+ return /* @__PURE__ */ jsxs4(Text4, { inverse: isSel, children: [
2791
+ isSel ? symbols.pointer : " ",
2792
+ skill.name.padEnd(30),
2793
+ " ",
2794
+ skill.source && /* @__PURE__ */ jsx4(Text4, { color: colors.secondaryDim, children: skill.source })
2795
+ ] }, skill.name);
2796
+ }),
2797
+ start + maxVisible < skills.length && /* @__PURE__ */ jsxs4(Text4, { dimColor: true, children: [
2798
+ " \u2193 ",
2799
+ skills.length - start - maxVisible,
2800
+ " more"
2801
+ ] })
2802
+ ] }),
2803
+ /* @__PURE__ */ jsx4(Box4, { marginTop: 1, children: /* @__PURE__ */ jsx4(Text4, { dimColor: true, children: "r=refresh d=delete q=quit" }) })
2804
+ ] });
2805
+ }
2806
+ var init_Installed = __esm({
2807
+ "src/tui/screens/Installed.tsx"() {
2808
+ "use strict";
2809
+ init_theme();
2810
+ init_useSkills();
2811
+ }
2812
+ });
2813
+
2814
+ // src/tui/screens/Sync.tsx
2815
+ import { useState as useState6, useEffect as useEffect4 } from "react";
2816
+ import { Box as Box5, Text as Text5, useInput as useInput3 } from "ink";
2817
+ import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
2818
+ function Sync({ rows = 24 }) {
2819
+ const [agents, setAgents] = useState6([]);
2820
+ const [loading, setLoading] = useState6(true);
2821
+ const [sel, setSel] = useState6(0);
2822
+ const [syncing, setSyncing] = useState6(false);
2823
+ const maxVisible = Math.max(5, rows - 6);
2824
+ const start = Math.max(0, Math.min(sel - Math.floor(maxVisible / 2), agents.length - maxVisible));
2825
+ const visible = agents.slice(start, start + maxVisible);
2826
+ useEffect4(() => {
2827
+ (async () => {
2828
+ const adapters2 = getAllAdapters();
2829
+ const s = [];
2830
+ for (const a of adapters2) {
2831
+ s.push({ name: a.name, type: a.type, detected: await a.isDetected() });
2832
+ }
2833
+ setAgents(s);
2834
+ setLoading(false);
2835
+ })();
2836
+ }, []);
2837
+ useInput3((input, key) => {
2838
+ if (loading || syncing) return;
2839
+ if (key.upArrow) setSel((i) => Math.max(0, i - 1));
2840
+ else if (key.downArrow) setSel((i) => Math.min(agents.length - 1, i + 1));
2841
+ else if (input === "a") {
2842
+ setSyncing(true);
2843
+ setTimeout(() => setSyncing(false), 500);
2844
+ } else if (key.return && agents[sel]?.detected) {
2845
+ setSyncing(true);
2846
+ setTimeout(() => setSyncing(false), 300);
2847
+ }
2848
+ });
2849
+ const detected = agents.filter((a) => a.detected).length;
2850
+ return /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", children: [
2851
+ /* @__PURE__ */ jsx5(Text5, { bold: true, color: colors.primary, children: "SYNC SKILLS" }),
2852
+ /* @__PURE__ */ jsxs5(Text5, { dimColor: true, children: [
2853
+ detected,
2854
+ "/",
2855
+ agents.length,
2856
+ " agents detected"
2857
+ ] }),
2858
+ loading && /* @__PURE__ */ jsx5(Text5, { children: "Detecting agents..." }),
2859
+ syncing && /* @__PURE__ */ jsx5(Text5, { children: "Syncing..." }),
2860
+ !loading && !syncing && /* @__PURE__ */ jsxs5(Box5, { marginTop: 1, flexDirection: "column", children: [
2861
+ start > 0 && /* @__PURE__ */ jsxs5(Text5, { dimColor: true, children: [
2862
+ " \u2191 ",
2863
+ start,
2864
+ " more"
2865
+ ] }),
2866
+ visible.map((agent, i) => {
2867
+ const idx = start + i;
2868
+ const isSel = idx === sel;
2869
+ return /* @__PURE__ */ jsxs5(Text5, { inverse: isSel, dimColor: !agent.detected, children: [
2870
+ isSel ? symbols.pointer : " ",
2871
+ agent.detected ? symbols.checkboxOn : symbols.checkboxOff,
2872
+ " ",
2873
+ agent.name.padEnd(20),
2874
+ " ",
2875
+ agent.detected ? "Ready" : "N/A"
2876
+ ] }, agent.type);
2877
+ }),
2878
+ start + maxVisible < agents.length && /* @__PURE__ */ jsxs5(Text5, { dimColor: true, children: [
2879
+ " \u2193 ",
2880
+ agents.length - start - maxVisible,
2881
+ " more"
2882
+ ] })
2883
+ ] }),
2884
+ /* @__PURE__ */ jsx5(Box5, { marginTop: 1, children: /* @__PURE__ */ jsx5(Text5, { dimColor: true, children: "Enter=sync a=all q=quit" }) })
2885
+ ] });
2886
+ }
2887
+ var init_Sync = __esm({
2888
+ "src/tui/screens/Sync.tsx"() {
2889
+ "use strict";
2890
+ init_theme();
2891
+ init_agents();
2892
+ }
2893
+ });
2894
+
2895
+ // src/tui/screens/Settings.tsx
2896
+ import { useState as useState7 } from "react";
2897
+ import { Box as Box6, Text as Text6, useInput as useInput4 } from "ink";
2898
+ import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
2899
+ function Settings({}) {
2900
+ const [sel, setSel] = useState7(0);
2901
+ useInput4((_, key) => {
2902
+ if (key.upArrow) setSel((i) => Math.max(0, i - 1));
2903
+ else if (key.downArrow) setSel((i) => Math.min(SETTINGS.length - 1, i + 1));
2904
+ });
2905
+ return /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", children: [
2906
+ /* @__PURE__ */ jsx6(Text6, { bold: true, color: colors.primary, children: "SETTINGS" }),
2907
+ /* @__PURE__ */ jsx6(Text6, { dimColor: true, children: "Configure SkillKit" }),
2908
+ /* @__PURE__ */ jsx6(Box6, { marginTop: 1, flexDirection: "column", children: SETTINGS.map((s, i) => {
2909
+ const isSel = i === sel;
2910
+ return /* @__PURE__ */ jsxs6(Text6, { inverse: isSel, children: [
2911
+ isSel ? symbols.pointer : " ",
2912
+ s.label.padEnd(16),
2913
+ " ",
2914
+ /* @__PURE__ */ jsx6(Text6, { color: colors.secondaryDim, children: s.value })
2915
+ ] }, s.id);
2916
+ }) }),
2917
+ /* @__PURE__ */ jsx6(Box6, { marginTop: 1, children: /* @__PURE__ */ jsx6(Text6, { dimColor: true, children: "Enter=edit q=quit" }) })
2918
+ ] });
2919
+ }
2920
+ var SETTINGS;
2921
+ var init_Settings = __esm({
2922
+ "src/tui/screens/Settings.tsx"() {
2923
+ "use strict";
2924
+ init_theme();
2925
+ SETTINGS = [
2926
+ { id: "agent", label: "Default Agent", value: "auto-detect" },
2927
+ { id: "sync", label: "Auto Sync", value: "disabled" },
2928
+ { id: "cache", label: "Cache Dir", value: "~/.skillkit/cache" }
2929
+ ];
2930
+ }
2931
+ });
2932
+
2933
+ // src/tui/App.tsx
2934
+ import { useState as useState8 } from "react";
2935
+ import { Box as Box7, Text as Text7, useInput as useInput5, useApp, useStdout } from "ink";
2936
+ import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
2937
+ function App() {
2938
+ const [screen, setScreen] = useState8("home");
2939
+ const { exit } = useApp();
2940
+ const { stdout } = useStdout();
2941
+ const cols = stdout?.columns || 80;
2942
+ const rows = stdout?.rows || 24;
2943
+ const showSidebar = cols >= 70;
2944
+ useInput5((input, key) => {
2945
+ if (input === "q") {
2946
+ exit();
2947
+ return;
2948
+ }
2949
+ if (key.escape) {
2950
+ setScreen("home");
2951
+ return;
2952
+ }
2953
+ if (input === "h") setScreen("home");
2954
+ if (input === "b") setScreen("browse");
2955
+ if (input === "l") setScreen("installed");
2956
+ if (input === "s") setScreen("sync");
2957
+ if (input === ",") setScreen("settings");
2958
+ });
2959
+ const renderScreen = () => {
2960
+ switch (screen) {
2961
+ case "home":
2962
+ return /* @__PURE__ */ jsx7(Home, { onNavigate: setScreen, cols, rows });
2963
+ case "browse":
2964
+ return /* @__PURE__ */ jsx7(Browse, { cols, rows });
2965
+ case "installed":
2966
+ return /* @__PURE__ */ jsx7(Installed, { cols, rows });
2967
+ case "sync":
2968
+ return /* @__PURE__ */ jsx7(Sync, { cols, rows });
2969
+ case "settings":
2970
+ return /* @__PURE__ */ jsx7(Settings, { cols, rows });
2971
+ }
2972
+ };
2973
+ return /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", children: [
2974
+ /* @__PURE__ */ jsxs7(Box7, { flexDirection: "row", flexGrow: 1, children: [
2975
+ showSidebar && /* @__PURE__ */ jsx7(Sidebar, { screen, onNavigate: setScreen }),
2976
+ /* @__PURE__ */ jsx7(Box7, { flexDirection: "column", flexGrow: 1, marginLeft: 1, children: renderScreen() })
2977
+ ] }),
2978
+ /* @__PURE__ */ jsx7(Text7, { dimColor: true, children: "h Home b Browse l List s Sync , Config Esc Back q Quit" })
2979
+ ] });
2980
+ }
2981
+ var init_App = __esm({
2982
+ "src/tui/App.tsx"() {
2983
+ "use strict";
2984
+ init_Sidebar();
2985
+ init_Home();
2986
+ init_Browse();
2987
+ init_Installed();
2988
+ init_Sync();
2989
+ init_Settings();
2990
+ }
2991
+ });
2992
+
2993
+ // src/tui/index.tsx
2994
+ var tui_exports = {};
2995
+ __export(tui_exports, {
2996
+ startTUI: () => startTUI
2997
+ });
2998
+ import { render } from "ink";
2999
+ import { jsx as jsx8 } from "react/jsx-runtime";
3000
+ function startTUI() {
3001
+ const { waitUntilExit } = render(/* @__PURE__ */ jsx8(App, {}));
3002
+ return waitUntilExit();
3003
+ }
3004
+ var init_tui = __esm({
3005
+ "src/tui/index.tsx"() {
3006
+ "use strict";
3007
+ init_App();
3008
+ }
3009
+ });
3010
+
3011
+ // src/cli.ts
3012
+ import { Cli, Builtins } from "clipanion";
1306
3013
 
1307
3014
  // src/commands/install.ts
3015
+ init_providers();
3016
+ init_config();
1308
3017
  init_skills();
3018
+ init_agents();
3019
+ import { existsSync as existsSync24, mkdirSync as mkdirSync2, cpSync, rmSync as rmSync4 } from "fs";
3020
+ import { join as join24 } from "path";
3021
+ import chalk from "chalk";
3022
+ import ora from "ora";
3023
+ import { Command, Option } from "clipanion";
1309
3024
  var InstallCommand = class extends Command {
1310
3025
  static paths = [["install"], ["i"]];
1311
3026
  static usage = Command.Usage({
@@ -1317,7 +3032,9 @@ var InstallCommand = class extends Command {
1317
3032
  ["Install specific skills (CI/CD)", "$0 install owner/repo --skills=pdf,xlsx"],
1318
3033
  ["Install all skills non-interactively", "$0 install owner/repo --all"],
1319
3034
  ["Install from local path", "$0 install ./my-skills"],
1320
- ["Install globally", "$0 install owner/repo --global"]
3035
+ ["Install globally", "$0 install owner/repo --global"],
3036
+ ["List available skills", "$0 install owner/repo --list"],
3037
+ ["Install to specific agents", "$0 install owner/repo --agent claude-code --agent cursor"]
1321
3038
  ]
1322
3039
  });
1323
3040
  source = Option.String({ required: true });
@@ -1339,6 +3056,12 @@ var InstallCommand = class extends Command {
1339
3056
  provider = Option.String("--provider,-p", {
1340
3057
  description: "Force specific provider (github, gitlab, bitbucket)"
1341
3058
  });
3059
+ list = Option.Boolean("--list,-l", false, {
3060
+ description: "List available skills without installing"
3061
+ });
3062
+ agent = Option.Array("--agent", {
3063
+ description: "Target specific agents (can specify multiple)"
3064
+ });
1342
3065
  async execute() {
1343
3066
  const spinner = ora();
1344
3067
  try {
@@ -1364,6 +3087,25 @@ var InstallCommand = class extends Command {
1364
3087
  }
1365
3088
  spinner.succeed(`Found ${result.skills?.length || 0} skill(s)`);
1366
3089
  const discoveredSkills = result.discoveredSkills || [];
3090
+ if (this.list) {
3091
+ if (discoveredSkills.length === 0) {
3092
+ console.log(chalk.yellow("\nNo skills found in this repository"));
3093
+ } else {
3094
+ console.log(chalk.cyan("\nAvailable skills:\n"));
3095
+ for (const skill of discoveredSkills) {
3096
+ console.log(` ${chalk.green(skill.name)}`);
3097
+ }
3098
+ console.log();
3099
+ console.log(chalk.dim(`Total: ${discoveredSkills.length} skill(s)`));
3100
+ console.log(chalk.dim("\nTo install specific skills: skillkit install <source> --skills=skill1,skill2"));
3101
+ console.log(chalk.dim("To install all skills: skillkit install <source> --all"));
3102
+ }
3103
+ const cleanupPath2 = result.tempRoot || result.path;
3104
+ if (!isLocalPath(this.source) && cleanupPath2 && existsSync24(cleanupPath2)) {
3105
+ rmSync4(cleanupPath2, { recursive: true, force: true });
3106
+ }
3107
+ return 0;
3108
+ }
1367
3109
  let skillsToInstall = discoveredSkills;
1368
3110
  if (this.skills) {
1369
3111
  const requestedSkills = this.skills.split(",").map((s) => s.trim());
@@ -1389,53 +3131,78 @@ var InstallCommand = class extends Command {
1389
3131
  console.log(chalk.yellow("No skills to install"));
1390
3132
  return 0;
1391
3133
  }
1392
- const installDir = getInstallDir(this.global);
1393
- if (!existsSync14(installDir)) {
1394
- mkdirSync2(installDir, { recursive: true });
1395
- }
1396
- let installed = 0;
1397
- for (const skill of skillsToInstall) {
1398
- const skillName = skill.name;
1399
- const sourcePath = skill.path;
1400
- const targetPath = join14(installDir, skillName);
1401
- if (existsSync14(targetPath) && !this.force) {
1402
- console.log(chalk.yellow(` Skipping ${skillName} (already exists, use --force to overwrite)`));
1403
- continue;
1404
- }
1405
- const securityRoot = result.tempRoot || result.path;
1406
- if (!isPathInside(sourcePath, securityRoot)) {
1407
- console.log(chalk.red(` Skipping ${skillName} (path traversal detected)`));
1408
- continue;
1409
- }
1410
- spinner.start(`Installing ${skillName}...`);
1411
- try {
1412
- if (existsSync14(targetPath)) {
1413
- rmSync4(targetPath, { recursive: true, force: true });
3134
+ let targetAgents;
3135
+ if (this.agent && this.agent.length > 0) {
3136
+ targetAgents = this.agent;
3137
+ } else {
3138
+ const detectedAgent = await detectAgent();
3139
+ targetAgents = [detectedAgent];
3140
+ }
3141
+ let totalInstalled = 0;
3142
+ const installResults = [];
3143
+ for (const agentType of targetAgents) {
3144
+ const adapter = getAdapter(agentType);
3145
+ const installDir = getInstallDir(this.global, agentType);
3146
+ if (!existsSync24(installDir)) {
3147
+ mkdirSync2(installDir, { recursive: true });
3148
+ }
3149
+ if (targetAgents.length > 1) {
3150
+ console.log(chalk.cyan(`
3151
+ Installing to ${adapter.name}...`));
3152
+ }
3153
+ let installed = 0;
3154
+ for (const skill of skillsToInstall) {
3155
+ const skillName = skill.name;
3156
+ const sourcePath = skill.path;
3157
+ const targetPath = join24(installDir, skillName);
3158
+ if (existsSync24(targetPath) && !this.force) {
3159
+ console.log(chalk.yellow(` Skipping ${skillName} (already exists, use --force to overwrite)`));
3160
+ continue;
3161
+ }
3162
+ const securityRoot = result.tempRoot || result.path;
3163
+ if (!isPathInside(sourcePath, securityRoot)) {
3164
+ console.log(chalk.red(` Skipping ${skillName} (path traversal detected)`));
3165
+ continue;
3166
+ }
3167
+ spinner.start(`Installing ${skillName}...`);
3168
+ try {
3169
+ if (existsSync24(targetPath)) {
3170
+ rmSync4(targetPath, { recursive: true, force: true });
3171
+ }
3172
+ cpSync(sourcePath, targetPath, { recursive: true, dereference: true });
3173
+ const metadata = {
3174
+ name: skillName,
3175
+ description: "",
3176
+ source: this.source,
3177
+ sourceType: providerAdapter.type,
3178
+ subpath: skillName,
3179
+ installedAt: (/* @__PURE__ */ new Date()).toISOString(),
3180
+ enabled: true
3181
+ };
3182
+ saveSkillMetadata(targetPath, metadata);
3183
+ spinner.succeed(chalk.green(`Installed ${skillName}`));
3184
+ installed++;
3185
+ } catch (error) {
3186
+ spinner.fail(chalk.red(`Failed to install ${skillName}`));
3187
+ console.error(chalk.dim(error instanceof Error ? error.message : String(error)));
1414
3188
  }
1415
- cpSync(sourcePath, targetPath, { recursive: true, dereference: true });
1416
- const metadata = {
1417
- name: skillName,
1418
- description: "",
1419
- source: this.source,
1420
- sourceType: providerAdapter.type,
1421
- subpath: skillName,
1422
- installedAt: (/* @__PURE__ */ new Date()).toISOString(),
1423
- enabled: true
1424
- };
1425
- saveSkillMetadata(targetPath, metadata);
1426
- spinner.succeed(chalk.green(`Installed ${skillName}`));
1427
- installed++;
1428
- } catch (error) {
1429
- spinner.fail(chalk.red(`Failed to install ${skillName}`));
1430
- console.error(chalk.dim(error instanceof Error ? error.message : String(error)));
1431
3189
  }
3190
+ totalInstalled += installed;
3191
+ installResults.push({ agent: adapter.name, dir: installDir, count: installed });
1432
3192
  }
1433
3193
  const cleanupPath = result.tempRoot || result.path;
1434
- if (!isLocalPath(this.source) && cleanupPath && existsSync14(cleanupPath)) {
3194
+ if (!isLocalPath(this.source) && cleanupPath && existsSync24(cleanupPath)) {
1435
3195
  rmSync4(cleanupPath, { recursive: true, force: true });
1436
3196
  }
1437
3197
  console.log();
1438
- console.log(chalk.green(`Installed ${installed} skill(s) to ${installDir}`));
3198
+ if (targetAgents.length > 1) {
3199
+ console.log(chalk.green(`Installed ${totalInstalled} skill(s) across ${targetAgents.length} agents:`));
3200
+ for (const r of installResults) {
3201
+ console.log(chalk.dim(` - ${r.agent}: ${r.count} skill(s) to ${r.dir}`));
3202
+ }
3203
+ } else {
3204
+ console.log(chalk.green(`Installed ${totalInstalled} skill(s) to ${installResults[0]?.dir}`));
3205
+ }
1439
3206
  if (!this.yes) {
1440
3207
  console.log(chalk.dim("\nRun `skillkit sync` to update your agent config"));
1441
3208
  }
@@ -1449,11 +3216,13 @@ var InstallCommand = class extends Command {
1449
3216
  };
1450
3217
 
1451
3218
  // src/commands/sync.ts
1452
- import { existsSync as existsSync15, readFileSync as readFileSync3, writeFileSync as writeFileSync2, mkdirSync as mkdirSync3 } from "fs";
3219
+ init_config();
3220
+ init_skills();
3221
+ init_agents();
3222
+ import { existsSync as existsSync25, readFileSync as readFileSync3, writeFileSync as writeFileSync2, mkdirSync as mkdirSync3 } from "fs";
1453
3223
  import { dirname as dirname2 } from "path";
1454
3224
  import chalk2 from "chalk";
1455
3225
  import { Command as Command2, Option as Option2 } from "clipanion";
1456
- init_skills();
1457
3226
  var SyncCommand = class extends Command2 {
1458
3227
  static paths = [["sync"], ["s"]];
1459
3228
  static usage = Command2.Usage({
@@ -1511,12 +3280,12 @@ var SyncCommand = class extends Command2 {
1511
3280
  return 0;
1512
3281
  }
1513
3282
  let existingContent = "";
1514
- if (existsSync15(outputPath)) {
3283
+ if (existsSync25(outputPath)) {
1515
3284
  existingContent = readFileSync3(outputPath, "utf-8");
1516
3285
  }
1517
3286
  const newContent = updateConfigContent(existingContent, config, agentType);
1518
3287
  const dir = dirname2(outputPath);
1519
- if (!existsSync15(dir)) {
3288
+ if (!existsSync25(dir)) {
1520
3289
  mkdirSync3(dir, { recursive: true });
1521
3290
  }
1522
3291
  writeFileSync2(outputPath, newContent, "utf-8");
@@ -1565,9 +3334,10 @@ function updateConfigContent(existing, newConfig, agentType) {
1565
3334
  }
1566
3335
 
1567
3336
  // src/commands/read.ts
3337
+ init_config();
3338
+ init_skills();
1568
3339
  import chalk3 from "chalk";
1569
3340
  import { Command as Command3, Option as Option3 } from "clipanion";
1570
- init_skills();
1571
3341
  var ReadCommand = class extends Command3 {
1572
3342
  static paths = [["read"], ["r"]];
1573
3343
  static usage = Command3.Usage({
@@ -1626,9 +3396,10 @@ var ReadCommand = class extends Command3 {
1626
3396
  };
1627
3397
 
1628
3398
  // src/commands/list.ts
3399
+ init_config();
3400
+ init_skills();
1629
3401
  import chalk4 from "chalk";
1630
3402
  import { Command as Command4, Option as Option4 } from "clipanion";
1631
- init_skills();
1632
3403
  var ListCommand = class extends Command4 {
1633
3404
  static paths = [["list"], ["ls"], ["l"]];
1634
3405
  static usage = Command4.Usage({
@@ -1714,9 +3485,10 @@ function truncate(str, maxLen) {
1714
3485
  }
1715
3486
 
1716
3487
  // src/commands/enable.ts
3488
+ init_config();
3489
+ init_skills();
1717
3490
  import chalk5 from "chalk";
1718
3491
  import { Command as Command5, Option as Option5 } from "clipanion";
1719
- init_skills();
1720
3492
  var EnableCommand = class extends Command5 {
1721
3493
  static paths = [["enable"]];
1722
3494
  static usage = Command5.Usage({
@@ -1799,13 +3571,14 @@ var DisableCommand = class extends Command5 {
1799
3571
  };
1800
3572
 
1801
3573
  // src/commands/update.ts
1802
- import { existsSync as existsSync16, rmSync as rmSync5, cpSync as cpSync2 } from "fs";
1803
- import { join as join15 } from "path";
3574
+ init_config();
3575
+ init_skills();
3576
+ init_providers();
3577
+ import { existsSync as existsSync26, rmSync as rmSync5, cpSync as cpSync2 } from "fs";
3578
+ import { join as join25 } from "path";
1804
3579
  import chalk6 from "chalk";
1805
3580
  import ora2 from "ora";
1806
3581
  import { Command as Command6, Option as Option6 } from "clipanion";
1807
- init_skills();
1808
- init_providers();
1809
3582
  var UpdateCommand = class extends Command6 {
1810
3583
  static paths = [["update"], ["u"]];
1811
3584
  static usage = Command6.Usage({
@@ -1852,14 +3625,14 @@ var UpdateCommand = class extends Command6 {
1852
3625
  spinner.start(`Updating ${skill.name}...`);
1853
3626
  try {
1854
3627
  if (isLocalPath(metadata.source)) {
1855
- const localPath = metadata.subpath ? join15(metadata.source, metadata.subpath) : metadata.source;
1856
- if (!existsSync16(localPath)) {
3628
+ const localPath = metadata.subpath ? join25(metadata.source, metadata.subpath) : metadata.source;
3629
+ if (!existsSync26(localPath)) {
1857
3630
  spinner.warn(chalk6.yellow(`${skill.name}: local source missing`));
1858
3631
  skipped++;
1859
3632
  continue;
1860
3633
  }
1861
- const skillMdPath = join15(localPath, "SKILL.md");
1862
- if (!existsSync16(skillMdPath)) {
3634
+ const skillMdPath = join25(localPath, "SKILL.md");
3635
+ if (!existsSync26(skillMdPath)) {
1863
3636
  spinner.warn(chalk6.yellow(`${skill.name}: no SKILL.md at source`));
1864
3637
  skipped++;
1865
3638
  continue;
@@ -1883,9 +3656,9 @@ var UpdateCommand = class extends Command6 {
1883
3656
  failed++;
1884
3657
  continue;
1885
3658
  }
1886
- const sourcePath = metadata.subpath ? join15(result.path, metadata.subpath) : result.path;
1887
- const skillMdPath = join15(sourcePath, "SKILL.md");
1888
- if (!existsSync16(skillMdPath)) {
3659
+ const sourcePath = metadata.subpath ? join25(result.path, metadata.subpath) : result.path;
3660
+ const skillMdPath = join25(sourcePath, "SKILL.md");
3661
+ if (!existsSync26(skillMdPath)) {
1889
3662
  spinner.warn(chalk6.yellow(`${skill.name}: no SKILL.md in source`));
1890
3663
  rmSync5(result.path, { recursive: true, force: true });
1891
3664
  skipped++;
@@ -1916,10 +3689,11 @@ var UpdateCommand = class extends Command6 {
1916
3689
  };
1917
3690
 
1918
3691
  // src/commands/remove.ts
1919
- import { existsSync as existsSync17, rmSync as rmSync6 } from "fs";
3692
+ init_config();
3693
+ init_skills();
3694
+ import { existsSync as existsSync27, rmSync as rmSync6 } from "fs";
1920
3695
  import chalk7 from "chalk";
1921
3696
  import { Command as Command7, Option as Option7 } from "clipanion";
1922
- init_skills();
1923
3697
  var RemoveCommand = class extends Command7 {
1924
3698
  static paths = [["remove"], ["rm"], ["uninstall"]];
1925
3699
  static usage = Command7.Usage({
@@ -1944,7 +3718,7 @@ var RemoveCommand = class extends Command7 {
1944
3718
  console.log(chalk7.yellow(`Skill not found: ${skillName}`));
1945
3719
  continue;
1946
3720
  }
1947
- if (!existsSync17(skill.path)) {
3721
+ if (!existsSync27(skill.path)) {
1948
3722
  console.log(chalk7.yellow(`Path not found: ${skill.path}`));
1949
3723
  continue;
1950
3724
  }
@@ -1966,6 +3740,8 @@ var RemoveCommand = class extends Command7 {
1966
3740
  };
1967
3741
 
1968
3742
  // src/commands/init.ts
3743
+ init_config();
3744
+ init_agents();
1969
3745
  import chalk8 from "chalk";
1970
3746
  import { Command as Command8, Option as Option8 } from "clipanion";
1971
3747
  var InitCommand = class extends Command8 {
@@ -2031,8 +3807,8 @@ var InitCommand = class extends Command8 {
2031
3807
 
2032
3808
  // src/commands/validate.ts
2033
3809
  init_skills();
2034
- import { existsSync as existsSync18, readdirSync as readdirSync2 } from "fs";
2035
- import { join as join16, basename as basename6 } from "path";
3810
+ import { existsSync as existsSync28, readdirSync as readdirSync2 } from "fs";
3811
+ import { join as join26, basename as basename6 } from "path";
2036
3812
  import chalk9 from "chalk";
2037
3813
  import { Command as Command9, Option as Option9 } from "clipanion";
2038
3814
  var ValidateCommand = class extends Command9 {
@@ -2050,7 +3826,7 @@ var ValidateCommand = class extends Command9 {
2050
3826
  });
2051
3827
  async execute() {
2052
3828
  const targetPath = this.skillPath;
2053
- if (!existsSync18(targetPath)) {
3829
+ if (!existsSync28(targetPath)) {
2054
3830
  console.error(chalk9.red(`Path does not exist: ${targetPath}`));
2055
3831
  return 1;
2056
3832
  }
@@ -2059,8 +3835,8 @@ var ValidateCommand = class extends Command9 {
2059
3835
  const entries = readdirSync2(targetPath, { withFileTypes: true });
2060
3836
  for (const entry of entries) {
2061
3837
  if (entry.isDirectory()) {
2062
- const skillPath = join16(targetPath, entry.name);
2063
- if (existsSync18(join16(skillPath, "SKILL.md"))) {
3838
+ const skillPath = join26(targetPath, entry.name);
3839
+ if (existsSync28(join26(skillPath, "SKILL.md"))) {
2064
3840
  skillPaths.push(skillPath);
2065
3841
  }
2066
3842
  }
@@ -2102,11 +3878,137 @@ var ValidateCommand = class extends Command9 {
2102
3878
  }
2103
3879
  };
2104
3880
 
3881
+ // src/commands/create.ts
3882
+ import { existsSync as existsSync29, mkdirSync as mkdirSync4, writeFileSync as writeFileSync3 } from "fs";
3883
+ import { join as join27 } from "path";
3884
+ import chalk10 from "chalk";
3885
+ import { Command as Command10, Option as Option10 } from "clipanion";
3886
+ var CreateCommand = class extends Command10 {
3887
+ static paths = [["create"], ["new"]];
3888
+ static usage = Command10.Usage({
3889
+ description: "Create a new skill with proper structure",
3890
+ examples: [
3891
+ ["Create a new skill", "$0 create my-skill"],
3892
+ ["Create with all optional directories", "$0 create my-skill --full"],
3893
+ ["Create with scripts directory", "$0 create my-skill --scripts"]
3894
+ ]
3895
+ });
3896
+ name = Option10.String({ required: true, name: "skill-name" });
3897
+ full = Option10.Boolean("--full,-f", false, {
3898
+ description: "Include all optional directories (references, scripts, assets)"
3899
+ });
3900
+ scripts = Option10.Boolean("--scripts", false, {
3901
+ description: "Include scripts directory"
3902
+ });
3903
+ references = Option10.Boolean("--references", false, {
3904
+ description: "Include references directory"
3905
+ });
3906
+ assets = Option10.Boolean("--assets", false, {
3907
+ description: "Include assets directory"
3908
+ });
3909
+ directory = Option10.String("--dir,-d", {
3910
+ description: "Parent directory to create skill in (default: current directory)"
3911
+ });
3912
+ async execute() {
3913
+ const skillName = this.name.toLowerCase();
3914
+ if (!/^[a-z0-9]+(-[a-z0-9]+)*$/.test(skillName)) {
3915
+ console.error(chalk10.red("Invalid skill name"));
3916
+ console.error(chalk10.dim("Must be lowercase alphanumeric with hyphens (e.g., my-skill)"));
3917
+ return 1;
3918
+ }
3919
+ const parentDir = this.directory || process.cwd();
3920
+ const skillDir = join27(parentDir, skillName);
3921
+ if (existsSync29(skillDir)) {
3922
+ console.error(chalk10.red(`Directory already exists: ${skillDir}`));
3923
+ return 1;
3924
+ }
3925
+ try {
3926
+ mkdirSync4(skillDir, { recursive: true });
3927
+ const skillMd = generateSkillMd(skillName);
3928
+ writeFileSync3(join27(skillDir, "SKILL.md"), skillMd);
3929
+ if (this.full || this.references) {
3930
+ const refsDir = join27(skillDir, "references");
3931
+ mkdirSync4(refsDir);
3932
+ writeFileSync3(join27(refsDir, ".gitkeep"), "");
3933
+ }
3934
+ if (this.full || this.scripts) {
3935
+ const scriptsDir = join27(skillDir, "scripts");
3936
+ mkdirSync4(scriptsDir);
3937
+ writeFileSync3(join27(scriptsDir, ".gitkeep"), "");
3938
+ }
3939
+ if (this.full || this.assets) {
3940
+ const assetsDir = join27(skillDir, "assets");
3941
+ mkdirSync4(assetsDir);
3942
+ writeFileSync3(join27(assetsDir, ".gitkeep"), "");
3943
+ }
3944
+ console.log(chalk10.green(`Created skill: ${skillName}`));
3945
+ console.log();
3946
+ console.log(chalk10.dim("Structure:"));
3947
+ console.log(chalk10.dim(` ${skillDir}/`));
3948
+ console.log(chalk10.dim(" \u251C\u2500\u2500 SKILL.md"));
3949
+ if (this.full || this.references) console.log(chalk10.dim(" \u251C\u2500\u2500 references/"));
3950
+ if (this.full || this.scripts) console.log(chalk10.dim(" \u251C\u2500\u2500 scripts/"));
3951
+ if (this.full || this.assets) console.log(chalk10.dim(" \u2514\u2500\u2500 assets/"));
3952
+ console.log();
3953
+ console.log(chalk10.cyan("Next steps:"));
3954
+ console.log(chalk10.dim(" 1. Edit SKILL.md with your instructions"));
3955
+ console.log(chalk10.dim(" 2. Validate: skillkit validate " + skillDir));
3956
+ console.log(chalk10.dim(" 3. Test: skillkit read " + skillName));
3957
+ return 0;
3958
+ } catch (error) {
3959
+ console.error(chalk10.red("Failed to create skill"));
3960
+ console.error(chalk10.dim(error instanceof Error ? error.message : String(error)));
3961
+ return 1;
3962
+ }
3963
+ }
3964
+ };
3965
+ function generateSkillMd(name) {
3966
+ const title = name.split("-").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
3967
+ return `---
3968
+ name: ${name}
3969
+ description: Describe what this skill does and when to use it. Include trigger keywords.
3970
+ ---
3971
+
3972
+ # ${title}
3973
+
3974
+ Instructions for the AI agent on how to use this skill.
3975
+
3976
+ ## When to Use
3977
+
3978
+ - Scenario 1
3979
+ - Scenario 2
3980
+
3981
+ ## Steps
3982
+
3983
+ 1. First step
3984
+ 2. Second step
3985
+ 3. Third step
3986
+ `;
3987
+ }
3988
+
3989
+ // src/commands/ui.ts
3990
+ import { Command as Command11 } from "clipanion";
3991
+ var UICommand = class extends Command11 {
3992
+ static paths = [["ui"], ["tui"]];
3993
+ static usage = Command11.Usage({
3994
+ description: "Launch the interactive TUI (Terminal User Interface)",
3995
+ examples: [
3996
+ ["Open interactive TUI", "$0 ui"],
3997
+ ["Alias for TUI", "$0 tui"]
3998
+ ]
3999
+ });
4000
+ async execute() {
4001
+ const { startTUI: startTUI2 } = await Promise.resolve().then(() => (init_tui(), tui_exports));
4002
+ await startTUI2();
4003
+ return 0;
4004
+ }
4005
+ };
4006
+
2105
4007
  // src/cli.ts
2106
4008
  var cli = new Cli({
2107
4009
  binaryLabel: "skillkit",
2108
4010
  binaryName: "skillkit",
2109
- binaryVersion: "1.0.0"
4011
+ binaryVersion: "1.1.0"
2110
4012
  });
2111
4013
  cli.register(Builtins.HelpCommand);
2112
4014
  cli.register(Builtins.VersionCommand);
@@ -2120,5 +4022,7 @@ cli.register(UpdateCommand);
2120
4022
  cli.register(RemoveCommand);
2121
4023
  cli.register(InitCommand);
2122
4024
  cli.register(ValidateCommand);
4025
+ cli.register(CreateCommand);
4026
+ cli.register(UICommand);
2123
4027
  cli.runExit(process.argv.slice(2));
2124
4028
  //# sourceMappingURL=cli.js.map