skillkit 1.0.1 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +52 -15
- package/dist/cli.js +1139 -216
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +130 -9
- package/dist/index.js +969 -197
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
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
|
|
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);
|
|
@@ -664,17 +766,17 @@ import { Cli, Builtins } from "clipanion";
|
|
|
664
766
|
|
|
665
767
|
// src/commands/install.ts
|
|
666
768
|
init_providers();
|
|
667
|
-
import { existsSync as
|
|
668
|
-
import { join as
|
|
769
|
+
import { existsSync as existsSync24, mkdirSync as mkdirSync2, cpSync, rmSync as rmSync4 } from "fs";
|
|
770
|
+
import { join as join24 } from "path";
|
|
669
771
|
import chalk from "chalk";
|
|
670
772
|
import ora from "ora";
|
|
671
773
|
import { Command, Option } from "clipanion";
|
|
672
774
|
|
|
673
775
|
// src/core/config.ts
|
|
674
776
|
init_types();
|
|
675
|
-
import { existsSync as
|
|
676
|
-
import { join as
|
|
677
|
-
import { homedir as
|
|
777
|
+
import { existsSync as existsSync23, readFileSync as readFileSync2, writeFileSync, mkdirSync } from "fs";
|
|
778
|
+
import { join as join23, dirname } from "path";
|
|
779
|
+
import { homedir as homedir17 } from "os";
|
|
678
780
|
import { parse as parseYaml2, stringify as stringifyYaml } from "yaml";
|
|
679
781
|
|
|
680
782
|
// src/agents/claude-code.ts
|
|
@@ -846,13 +948,665 @@ Skills are loaded on-demand to keep context clean. Only load skills when relevan
|
|
|
846
948
|
}
|
|
847
949
|
parseConfig(content) {
|
|
848
950
|
const skillNames = [];
|
|
849
|
-
const tableRegex = /^\|\s*([a-z0-9-]+)\s*\|/gm;
|
|
951
|
+
const tableRegex = /^\|\s*([a-z0-9-]+)\s*\|/gm;
|
|
952
|
+
let match;
|
|
953
|
+
while ((match = tableRegex.exec(content)) !== null) {
|
|
954
|
+
const name = match[1].trim();
|
|
955
|
+
if (name && name !== "Skill" && name !== "-------") {
|
|
956
|
+
skillNames.push(name);
|
|
957
|
+
}
|
|
958
|
+
}
|
|
959
|
+
return skillNames;
|
|
960
|
+
}
|
|
961
|
+
getInvokeCommand(skillName) {
|
|
962
|
+
return `skillkit read ${skillName}`;
|
|
963
|
+
}
|
|
964
|
+
async isDetected() {
|
|
965
|
+
const codexDir = join8(process.cwd(), ".codex");
|
|
966
|
+
const globalCodex = join8(homedir3(), ".codex");
|
|
967
|
+
return existsSync8(codexDir) || existsSync8(globalCodex);
|
|
968
|
+
}
|
|
969
|
+
};
|
|
970
|
+
|
|
971
|
+
// src/agents/gemini-cli.ts
|
|
972
|
+
import { existsSync as existsSync9 } from "fs";
|
|
973
|
+
import { join as join9 } from "path";
|
|
974
|
+
import { homedir as homedir4 } from "os";
|
|
975
|
+
var GeminiCliAdapter = class {
|
|
976
|
+
type = "gemini-cli";
|
|
977
|
+
name = "Gemini CLI";
|
|
978
|
+
skillsDir = ".gemini/skills";
|
|
979
|
+
configFile = "GEMINI.md";
|
|
980
|
+
generateConfig(skills) {
|
|
981
|
+
const enabledSkills = skills.filter((s) => s.enabled);
|
|
982
|
+
if (enabledSkills.length === 0) {
|
|
983
|
+
return "";
|
|
984
|
+
}
|
|
985
|
+
const skillsJson = enabledSkills.map((s) => ({
|
|
986
|
+
name: s.name,
|
|
987
|
+
description: s.description,
|
|
988
|
+
invoke: `skillkit read ${s.name}`,
|
|
989
|
+
location: s.location
|
|
990
|
+
}));
|
|
991
|
+
return `# Skills Configuration
|
|
992
|
+
|
|
993
|
+
You have access to specialized skills that extend your capabilities.
|
|
994
|
+
|
|
995
|
+
## Available Skills
|
|
996
|
+
|
|
997
|
+
${enabledSkills.map((s) => `### ${s.name}
|
|
998
|
+
${s.description}
|
|
999
|
+
|
|
1000
|
+
Invoke: \`skillkit read ${s.name}\``).join("\n\n")}
|
|
1001
|
+
|
|
1002
|
+
## Skills Data
|
|
1003
|
+
|
|
1004
|
+
\`\`\`json
|
|
1005
|
+
${JSON.stringify(skillsJson, null, 2)}
|
|
1006
|
+
\`\`\`
|
|
1007
|
+
|
|
1008
|
+
## Usage Instructions
|
|
1009
|
+
|
|
1010
|
+
1. When a task matches a skill's description, load it using the invoke command
|
|
1011
|
+
2. Skills provide step-by-step instructions for complex tasks
|
|
1012
|
+
3. Each skill is self-contained with its own resources
|
|
1013
|
+
`;
|
|
1014
|
+
}
|
|
1015
|
+
parseConfig(content) {
|
|
1016
|
+
const skillNames = [];
|
|
1017
|
+
const jsonMatch = content.match(/```json\s*([\s\S]*?)```/);
|
|
1018
|
+
if (jsonMatch) {
|
|
1019
|
+
try {
|
|
1020
|
+
const skills = JSON.parse(jsonMatch[1]);
|
|
1021
|
+
if (Array.isArray(skills)) {
|
|
1022
|
+
skills.forEach((s) => {
|
|
1023
|
+
if (s.name) skillNames.push(s.name);
|
|
1024
|
+
});
|
|
1025
|
+
}
|
|
1026
|
+
} catch {
|
|
1027
|
+
}
|
|
1028
|
+
}
|
|
1029
|
+
if (skillNames.length === 0) {
|
|
1030
|
+
const headerRegex = /^### ([a-z0-9-]+)$/gm;
|
|
1031
|
+
let match;
|
|
1032
|
+
while ((match = headerRegex.exec(content)) !== null) {
|
|
1033
|
+
skillNames.push(match[1].trim());
|
|
1034
|
+
}
|
|
1035
|
+
}
|
|
1036
|
+
return skillNames;
|
|
1037
|
+
}
|
|
1038
|
+
getInvokeCommand(skillName) {
|
|
1039
|
+
return `skillkit read ${skillName}`;
|
|
1040
|
+
}
|
|
1041
|
+
async isDetected() {
|
|
1042
|
+
const geminiMd = join9(process.cwd(), "GEMINI.md");
|
|
1043
|
+
const geminiDir = join9(process.cwd(), ".gemini");
|
|
1044
|
+
const globalGemini = join9(homedir4(), ".gemini");
|
|
1045
|
+
return existsSync9(geminiMd) || existsSync9(geminiDir) || existsSync9(globalGemini);
|
|
1046
|
+
}
|
|
1047
|
+
};
|
|
1048
|
+
|
|
1049
|
+
// src/agents/opencode.ts
|
|
1050
|
+
import { existsSync as existsSync10 } from "fs";
|
|
1051
|
+
import { join as join10 } from "path";
|
|
1052
|
+
import { homedir as homedir5 } from "os";
|
|
1053
|
+
var OpenCodeAdapter = class {
|
|
1054
|
+
type = "opencode";
|
|
1055
|
+
name = "OpenCode";
|
|
1056
|
+
skillsDir = ".opencode/skills";
|
|
1057
|
+
configFile = "AGENTS.md";
|
|
1058
|
+
generateConfig(skills) {
|
|
1059
|
+
const enabledSkills = skills.filter((s) => s.enabled);
|
|
1060
|
+
if (enabledSkills.length === 0) {
|
|
1061
|
+
return "";
|
|
1062
|
+
}
|
|
1063
|
+
const skillsXml = enabledSkills.map(createSkillXml).join("\n\n");
|
|
1064
|
+
return `<!-- SKILLKIT_START -->
|
|
1065
|
+
# Skills
|
|
1066
|
+
|
|
1067
|
+
The following skills are available to help complete tasks:
|
|
1068
|
+
|
|
1069
|
+
<skills>
|
|
1070
|
+
${skillsXml}
|
|
1071
|
+
</skills>
|
|
1072
|
+
|
|
1073
|
+
## How to Use
|
|
1074
|
+
|
|
1075
|
+
When a task matches a skill's description:
|
|
1076
|
+
|
|
1077
|
+
\`\`\`bash
|
|
1078
|
+
skillkit read <skill-name>
|
|
1079
|
+
\`\`\`
|
|
1080
|
+
|
|
1081
|
+
This loads the skill's instructions into context.
|
|
1082
|
+
|
|
1083
|
+
<!-- SKILLKIT_END -->`;
|
|
1084
|
+
}
|
|
1085
|
+
parseConfig(content) {
|
|
1086
|
+
const skillNames = [];
|
|
1087
|
+
const skillRegex = /<name>([^<]+)<\/name>/g;
|
|
1088
|
+
let match;
|
|
1089
|
+
while ((match = skillRegex.exec(content)) !== null) {
|
|
1090
|
+
skillNames.push(match[1].trim());
|
|
1091
|
+
}
|
|
1092
|
+
return skillNames;
|
|
1093
|
+
}
|
|
1094
|
+
getInvokeCommand(skillName) {
|
|
1095
|
+
return `skillkit read ${skillName}`;
|
|
1096
|
+
}
|
|
1097
|
+
async isDetected() {
|
|
1098
|
+
const opencodeDir = join10(process.cwd(), ".opencode");
|
|
1099
|
+
const globalOpencode = join10(homedir5(), ".opencode");
|
|
1100
|
+
return existsSync10(opencodeDir) || existsSync10(globalOpencode);
|
|
1101
|
+
}
|
|
1102
|
+
};
|
|
1103
|
+
|
|
1104
|
+
// src/agents/antigravity.ts
|
|
1105
|
+
import { existsSync as existsSync11 } from "fs";
|
|
1106
|
+
import { join as join11 } from "path";
|
|
1107
|
+
import { homedir as homedir6 } from "os";
|
|
1108
|
+
var AntigravityAdapter = class {
|
|
1109
|
+
type = "antigravity";
|
|
1110
|
+
name = "Antigravity";
|
|
1111
|
+
skillsDir = ".antigravity/skills";
|
|
1112
|
+
configFile = "AGENTS.md";
|
|
1113
|
+
generateConfig(skills) {
|
|
1114
|
+
const enabledSkills = skills.filter((s) => s.enabled);
|
|
1115
|
+
if (enabledSkills.length === 0) {
|
|
1116
|
+
return "";
|
|
1117
|
+
}
|
|
1118
|
+
const skillsYaml = enabledSkills.map((s) => ` - name: ${s.name}
|
|
1119
|
+
description: "${s.description}"
|
|
1120
|
+
invoke: skillkit read ${s.name}`).join("\n");
|
|
1121
|
+
return `# Antigravity Skills Configuration
|
|
1122
|
+
|
|
1123
|
+
<!-- skills:
|
|
1124
|
+
${skillsYaml}
|
|
1125
|
+
-->
|
|
1126
|
+
|
|
1127
|
+
## Available Skills
|
|
1128
|
+
|
|
1129
|
+
${enabledSkills.map((s) => `### ${s.name}
|
|
1130
|
+
|
|
1131
|
+
${s.description}
|
|
1132
|
+
|
|
1133
|
+
**Usage:** \`skillkit read ${s.name}\`
|
|
1134
|
+
`).join("\n")}
|
|
1135
|
+
|
|
1136
|
+
## How Skills Work
|
|
1137
|
+
|
|
1138
|
+
1. Skills provide specialized knowledge for specific tasks
|
|
1139
|
+
2. Load a skill when the current task matches its description
|
|
1140
|
+
3. Skills are loaded on-demand to preserve context window
|
|
1141
|
+
`;
|
|
1142
|
+
}
|
|
1143
|
+
parseConfig(content) {
|
|
1144
|
+
const skillNames = [];
|
|
1145
|
+
const yamlMatch = content.match(/<!-- skills:\s*([\s\S]*?)-->/);
|
|
1146
|
+
if (yamlMatch) {
|
|
1147
|
+
const nameRegex = /name:\s*([a-z0-9-]+)/g;
|
|
1148
|
+
let match;
|
|
1149
|
+
while ((match = nameRegex.exec(yamlMatch[1])) !== null) {
|
|
1150
|
+
skillNames.push(match[1].trim());
|
|
1151
|
+
}
|
|
1152
|
+
}
|
|
1153
|
+
if (skillNames.length === 0) {
|
|
1154
|
+
const headerRegex = /^### ([a-z0-9-]+)$/gm;
|
|
1155
|
+
let match;
|
|
1156
|
+
while ((match = headerRegex.exec(content)) !== null) {
|
|
1157
|
+
skillNames.push(match[1].trim());
|
|
1158
|
+
}
|
|
1159
|
+
}
|
|
1160
|
+
return skillNames;
|
|
1161
|
+
}
|
|
1162
|
+
getInvokeCommand(skillName) {
|
|
1163
|
+
return `skillkit read ${skillName}`;
|
|
1164
|
+
}
|
|
1165
|
+
async isDetected() {
|
|
1166
|
+
const agDir = join11(process.cwd(), ".antigravity");
|
|
1167
|
+
const globalAg = join11(homedir6(), ".antigravity");
|
|
1168
|
+
return existsSync11(agDir) || existsSync11(globalAg);
|
|
1169
|
+
}
|
|
1170
|
+
};
|
|
1171
|
+
|
|
1172
|
+
// src/agents/amp.ts
|
|
1173
|
+
import { existsSync as existsSync12 } from "fs";
|
|
1174
|
+
import { join as join12 } from "path";
|
|
1175
|
+
import { homedir as homedir7 } from "os";
|
|
1176
|
+
var AmpAdapter = class {
|
|
1177
|
+
type = "amp";
|
|
1178
|
+
name = "Amp";
|
|
1179
|
+
skillsDir = ".agents/skills";
|
|
1180
|
+
configFile = "AGENTS.md";
|
|
1181
|
+
globalSkillsDir = join12(homedir7(), ".config", "agents", "skills");
|
|
1182
|
+
generateConfig(skills) {
|
|
1183
|
+
const enabledSkills = skills.filter((s) => s.enabled);
|
|
1184
|
+
if (enabledSkills.length === 0) {
|
|
1185
|
+
return "";
|
|
1186
|
+
}
|
|
1187
|
+
const skillsXml = enabledSkills.map(createSkillXml).join("\n\n");
|
|
1188
|
+
return `<skills_system priority="1">
|
|
1189
|
+
|
|
1190
|
+
## Available Skills
|
|
1191
|
+
|
|
1192
|
+
<!-- SKILLS_TABLE_START -->
|
|
1193
|
+
<usage>
|
|
1194
|
+
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.
|
|
1195
|
+
|
|
1196
|
+
How to use skills:
|
|
1197
|
+
- Invoke: \`skillkit read <skill-name>\` or \`npx skillkit read <skill-name>\`
|
|
1198
|
+
- The skill content will load with detailed instructions on how to complete the task
|
|
1199
|
+
- Base directory provided in output for resolving bundled resources (references/, scripts/, assets/)
|
|
1200
|
+
|
|
1201
|
+
Usage notes:
|
|
1202
|
+
- Only use skills listed in <available_skills> below
|
|
1203
|
+
- Do not invoke a skill that is already loaded in your context
|
|
1204
|
+
- Each skill invocation is stateless
|
|
1205
|
+
</usage>
|
|
1206
|
+
|
|
1207
|
+
<available_skills>
|
|
1208
|
+
|
|
1209
|
+
${skillsXml}
|
|
1210
|
+
|
|
1211
|
+
</available_skills>
|
|
1212
|
+
<!-- SKILLS_TABLE_END -->
|
|
1213
|
+
|
|
1214
|
+
</skills_system>`;
|
|
1215
|
+
}
|
|
1216
|
+
parseConfig(content) {
|
|
1217
|
+
const skillNames = [];
|
|
1218
|
+
const skillRegex = /<name>([^<]+)<\/name>/g;
|
|
1219
|
+
let match;
|
|
1220
|
+
while ((match = skillRegex.exec(content)) !== null) {
|
|
1221
|
+
skillNames.push(match[1].trim());
|
|
1222
|
+
}
|
|
1223
|
+
return skillNames;
|
|
1224
|
+
}
|
|
1225
|
+
getInvokeCommand(skillName) {
|
|
1226
|
+
return `skillkit read ${skillName}`;
|
|
1227
|
+
}
|
|
1228
|
+
async isDetected() {
|
|
1229
|
+
const projectAgents = join12(process.cwd(), ".agents");
|
|
1230
|
+
const globalAgents = join12(homedir7(), ".config", "agents");
|
|
1231
|
+
return existsSync12(projectAgents) || existsSync12(globalAgents);
|
|
1232
|
+
}
|
|
1233
|
+
};
|
|
1234
|
+
|
|
1235
|
+
// src/agents/clawdbot.ts
|
|
1236
|
+
import { existsSync as existsSync13 } from "fs";
|
|
1237
|
+
import { join as join13 } from "path";
|
|
1238
|
+
import { homedir as homedir8 } from "os";
|
|
1239
|
+
var ClawdbotAdapter = class {
|
|
1240
|
+
type = "clawdbot";
|
|
1241
|
+
name = "Clawdbot";
|
|
1242
|
+
skillsDir = "skills";
|
|
1243
|
+
configFile = "AGENTS.md";
|
|
1244
|
+
globalSkillsDir = join13(homedir8(), ".clawdbot", "skills");
|
|
1245
|
+
generateConfig(skills) {
|
|
1246
|
+
const enabledSkills = skills.filter((s) => s.enabled);
|
|
1247
|
+
if (enabledSkills.length === 0) {
|
|
1248
|
+
return "";
|
|
1249
|
+
}
|
|
1250
|
+
const skillsXml = enabledSkills.map(createSkillXml).join("\n\n");
|
|
1251
|
+
return `<skills_system priority="1">
|
|
1252
|
+
|
|
1253
|
+
## Available Skills
|
|
1254
|
+
|
|
1255
|
+
<!-- SKILLS_TABLE_START -->
|
|
1256
|
+
<usage>
|
|
1257
|
+
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.
|
|
1258
|
+
|
|
1259
|
+
How to use skills:
|
|
1260
|
+
- Invoke: \`skillkit read <skill-name>\` or \`npx skillkit read <skill-name>\`
|
|
1261
|
+
- The skill content will load with detailed instructions on how to complete the task
|
|
1262
|
+
- Base directory provided in output for resolving bundled resources (references/, scripts/, assets/)
|
|
1263
|
+
|
|
1264
|
+
Usage notes:
|
|
1265
|
+
- Only use skills listed in <available_skills> below
|
|
1266
|
+
- Do not invoke a skill that is already loaded in your context
|
|
1267
|
+
- Each skill invocation is stateless
|
|
1268
|
+
</usage>
|
|
1269
|
+
|
|
1270
|
+
<available_skills>
|
|
1271
|
+
|
|
1272
|
+
${skillsXml}
|
|
1273
|
+
|
|
1274
|
+
</available_skills>
|
|
1275
|
+
<!-- SKILLS_TABLE_END -->
|
|
1276
|
+
|
|
1277
|
+
</skills_system>`;
|
|
1278
|
+
}
|
|
1279
|
+
parseConfig(content) {
|
|
1280
|
+
const skillNames = [];
|
|
1281
|
+
const skillRegex = /<name>([^<]+)<\/name>/g;
|
|
1282
|
+
let match;
|
|
1283
|
+
while ((match = skillRegex.exec(content)) !== null) {
|
|
1284
|
+
skillNames.push(match[1].trim());
|
|
1285
|
+
}
|
|
1286
|
+
return skillNames;
|
|
1287
|
+
}
|
|
1288
|
+
getInvokeCommand(skillName) {
|
|
1289
|
+
return `skillkit read ${skillName}`;
|
|
1290
|
+
}
|
|
1291
|
+
async isDetected() {
|
|
1292
|
+
const projectSkills = join13(process.cwd(), "skills");
|
|
1293
|
+
const globalClawdbot = join13(homedir8(), ".clawdbot");
|
|
1294
|
+
return existsSync13(globalClawdbot) || existsSync13(projectSkills) && existsSync13(join13(process.cwd(), ".clawdbot"));
|
|
1295
|
+
}
|
|
1296
|
+
};
|
|
1297
|
+
|
|
1298
|
+
// src/agents/droid.ts
|
|
1299
|
+
import { existsSync as existsSync14 } from "fs";
|
|
1300
|
+
import { join as join14 } from "path";
|
|
1301
|
+
import { homedir as homedir9 } from "os";
|
|
1302
|
+
var DroidAdapter = class {
|
|
1303
|
+
type = "droid";
|
|
1304
|
+
name = "Droid (Factory)";
|
|
1305
|
+
skillsDir = ".factory/skills";
|
|
1306
|
+
configFile = "AGENTS.md";
|
|
1307
|
+
globalSkillsDir = join14(homedir9(), ".factory", "skills");
|
|
1308
|
+
generateConfig(skills) {
|
|
1309
|
+
const enabledSkills = skills.filter((s) => s.enabled);
|
|
1310
|
+
if (enabledSkills.length === 0) {
|
|
1311
|
+
return "";
|
|
1312
|
+
}
|
|
1313
|
+
const skillsXml = enabledSkills.map(createSkillXml).join("\n\n");
|
|
1314
|
+
return `<skills_system priority="1">
|
|
1315
|
+
|
|
1316
|
+
## Available Skills
|
|
1317
|
+
|
|
1318
|
+
<!-- SKILLS_TABLE_START -->
|
|
1319
|
+
<usage>
|
|
1320
|
+
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.
|
|
1321
|
+
|
|
1322
|
+
How to use skills:
|
|
1323
|
+
- Invoke: \`skillkit read <skill-name>\` or \`npx skillkit read <skill-name>\`
|
|
1324
|
+
- The skill content will load with detailed instructions on how to complete the task
|
|
1325
|
+
- Base directory provided in output for resolving bundled resources (references/, scripts/, assets/)
|
|
1326
|
+
|
|
1327
|
+
Usage notes:
|
|
1328
|
+
- Only use skills listed in <available_skills> below
|
|
1329
|
+
- Do not invoke a skill that is already loaded in your context
|
|
1330
|
+
- Each skill invocation is stateless
|
|
1331
|
+
</usage>
|
|
1332
|
+
|
|
1333
|
+
<available_skills>
|
|
1334
|
+
|
|
1335
|
+
${skillsXml}
|
|
1336
|
+
|
|
1337
|
+
</available_skills>
|
|
1338
|
+
<!-- SKILLS_TABLE_END -->
|
|
1339
|
+
|
|
1340
|
+
</skills_system>`;
|
|
1341
|
+
}
|
|
1342
|
+
parseConfig(content) {
|
|
1343
|
+
const skillNames = [];
|
|
1344
|
+
const skillRegex = /<name>([^<]+)<\/name>/g;
|
|
1345
|
+
let match;
|
|
1346
|
+
while ((match = skillRegex.exec(content)) !== null) {
|
|
1347
|
+
skillNames.push(match[1].trim());
|
|
1348
|
+
}
|
|
1349
|
+
return skillNames;
|
|
1350
|
+
}
|
|
1351
|
+
getInvokeCommand(skillName) {
|
|
1352
|
+
return `skillkit read ${skillName}`;
|
|
1353
|
+
}
|
|
1354
|
+
async isDetected() {
|
|
1355
|
+
const projectFactory = join14(process.cwd(), ".factory");
|
|
1356
|
+
const globalFactory = join14(homedir9(), ".factory");
|
|
1357
|
+
return existsSync14(projectFactory) || existsSync14(globalFactory);
|
|
1358
|
+
}
|
|
1359
|
+
};
|
|
1360
|
+
|
|
1361
|
+
// src/agents/github-copilot.ts
|
|
1362
|
+
import { existsSync as existsSync15 } from "fs";
|
|
1363
|
+
import { join as join15 } from "path";
|
|
1364
|
+
import { homedir as homedir10 } from "os";
|
|
1365
|
+
var GitHubCopilotAdapter = class {
|
|
1366
|
+
type = "github-copilot";
|
|
1367
|
+
name = "GitHub Copilot";
|
|
1368
|
+
skillsDir = ".github/skills";
|
|
1369
|
+
configFile = "AGENTS.md";
|
|
1370
|
+
globalSkillsDir = join15(homedir10(), ".copilot", "skills");
|
|
1371
|
+
generateConfig(skills) {
|
|
1372
|
+
const enabledSkills = skills.filter((s) => s.enabled);
|
|
1373
|
+
if (enabledSkills.length === 0) {
|
|
1374
|
+
return "";
|
|
1375
|
+
}
|
|
1376
|
+
const skillsXml = enabledSkills.map(createSkillXml).join("\n\n");
|
|
1377
|
+
return `<skills_system priority="1">
|
|
1378
|
+
|
|
1379
|
+
## Available Skills
|
|
1380
|
+
|
|
1381
|
+
<!-- SKILLS_TABLE_START -->
|
|
1382
|
+
<usage>
|
|
1383
|
+
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.
|
|
1384
|
+
|
|
1385
|
+
How to use skills:
|
|
1386
|
+
- Invoke: \`skillkit read <skill-name>\` or \`npx skillkit read <skill-name>\`
|
|
1387
|
+
- The skill content will load with detailed instructions on how to complete the task
|
|
1388
|
+
- Base directory provided in output for resolving bundled resources (references/, scripts/, assets/)
|
|
1389
|
+
|
|
1390
|
+
Usage notes:
|
|
1391
|
+
- Only use skills listed in <available_skills> below
|
|
1392
|
+
- Do not invoke a skill that is already loaded in your context
|
|
1393
|
+
- Each skill invocation is stateless
|
|
1394
|
+
</usage>
|
|
1395
|
+
|
|
1396
|
+
<available_skills>
|
|
1397
|
+
|
|
1398
|
+
${skillsXml}
|
|
1399
|
+
|
|
1400
|
+
</available_skills>
|
|
1401
|
+
<!-- SKILLS_TABLE_END -->
|
|
1402
|
+
|
|
1403
|
+
</skills_system>`;
|
|
1404
|
+
}
|
|
1405
|
+
parseConfig(content) {
|
|
1406
|
+
const skillNames = [];
|
|
1407
|
+
const skillRegex = /<name>([^<]+)<\/name>/g;
|
|
1408
|
+
let match;
|
|
1409
|
+
while ((match = skillRegex.exec(content)) !== null) {
|
|
1410
|
+
skillNames.push(match[1].trim());
|
|
1411
|
+
}
|
|
1412
|
+
return skillNames;
|
|
1413
|
+
}
|
|
1414
|
+
getInvokeCommand(skillName) {
|
|
1415
|
+
return `skillkit read ${skillName}`;
|
|
1416
|
+
}
|
|
1417
|
+
async isDetected() {
|
|
1418
|
+
const projectGithub = join15(process.cwd(), ".github", "skills");
|
|
1419
|
+
const globalCopilot = join15(homedir10(), ".copilot");
|
|
1420
|
+
return existsSync15(projectGithub) || existsSync15(globalCopilot);
|
|
1421
|
+
}
|
|
1422
|
+
};
|
|
1423
|
+
|
|
1424
|
+
// src/agents/goose.ts
|
|
1425
|
+
import { existsSync as existsSync16 } from "fs";
|
|
1426
|
+
import { join as join16 } from "path";
|
|
1427
|
+
import { homedir as homedir11 } from "os";
|
|
1428
|
+
var GooseAdapter = class {
|
|
1429
|
+
type = "goose";
|
|
1430
|
+
name = "Goose";
|
|
1431
|
+
skillsDir = ".goose/skills";
|
|
1432
|
+
configFile = "AGENTS.md";
|
|
1433
|
+
globalSkillsDir = join16(homedir11(), ".config", "goose", "skills");
|
|
1434
|
+
generateConfig(skills) {
|
|
1435
|
+
const enabledSkills = skills.filter((s) => s.enabled);
|
|
1436
|
+
if (enabledSkills.length === 0) {
|
|
1437
|
+
return "";
|
|
1438
|
+
}
|
|
1439
|
+
const skillsXml = enabledSkills.map(createSkillXml).join("\n\n");
|
|
1440
|
+
return `<skills_system priority="1">
|
|
1441
|
+
|
|
1442
|
+
## Available Skills
|
|
1443
|
+
|
|
1444
|
+
<!-- SKILLS_TABLE_START -->
|
|
1445
|
+
<usage>
|
|
1446
|
+
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.
|
|
1447
|
+
|
|
1448
|
+
How to use skills:
|
|
1449
|
+
- Invoke: \`skillkit read <skill-name>\` or \`npx skillkit read <skill-name>\`
|
|
1450
|
+
- The skill content will load with detailed instructions on how to complete the task
|
|
1451
|
+
- Base directory provided in output for resolving bundled resources (references/, scripts/, assets/)
|
|
1452
|
+
|
|
1453
|
+
Usage notes:
|
|
1454
|
+
- Only use skills listed in <available_skills> below
|
|
1455
|
+
- Do not invoke a skill that is already loaded in your context
|
|
1456
|
+
- Each skill invocation is stateless
|
|
1457
|
+
</usage>
|
|
1458
|
+
|
|
1459
|
+
<available_skills>
|
|
1460
|
+
|
|
1461
|
+
${skillsXml}
|
|
1462
|
+
|
|
1463
|
+
</available_skills>
|
|
1464
|
+
<!-- SKILLS_TABLE_END -->
|
|
1465
|
+
|
|
1466
|
+
</skills_system>`;
|
|
1467
|
+
}
|
|
1468
|
+
parseConfig(content) {
|
|
1469
|
+
const skillNames = [];
|
|
1470
|
+
const skillRegex = /<name>([^<]+)<\/name>/g;
|
|
1471
|
+
let match;
|
|
1472
|
+
while ((match = skillRegex.exec(content)) !== null) {
|
|
1473
|
+
skillNames.push(match[1].trim());
|
|
1474
|
+
}
|
|
1475
|
+
return skillNames;
|
|
1476
|
+
}
|
|
1477
|
+
getInvokeCommand(skillName) {
|
|
1478
|
+
return `skillkit read ${skillName}`;
|
|
1479
|
+
}
|
|
1480
|
+
async isDetected() {
|
|
1481
|
+
const projectGoose = join16(process.cwd(), ".goose");
|
|
1482
|
+
const globalGoose = join16(homedir11(), ".config", "goose");
|
|
1483
|
+
return existsSync16(projectGoose) || existsSync16(globalGoose);
|
|
1484
|
+
}
|
|
1485
|
+
};
|
|
1486
|
+
|
|
1487
|
+
// src/agents/kilo.ts
|
|
1488
|
+
import { existsSync as existsSync17 } from "fs";
|
|
1489
|
+
import { join as join17 } from "path";
|
|
1490
|
+
import { homedir as homedir12 } from "os";
|
|
1491
|
+
var KiloAdapter = class {
|
|
1492
|
+
type = "kilo";
|
|
1493
|
+
name = "Kilo Code";
|
|
1494
|
+
skillsDir = ".kilocode/skills";
|
|
1495
|
+
configFile = "AGENTS.md";
|
|
1496
|
+
globalSkillsDir = join17(homedir12(), ".kilocode", "skills");
|
|
1497
|
+
generateConfig(skills) {
|
|
1498
|
+
const enabledSkills = skills.filter((s) => s.enabled);
|
|
1499
|
+
if (enabledSkills.length === 0) {
|
|
1500
|
+
return "";
|
|
1501
|
+
}
|
|
1502
|
+
const skillsXml = enabledSkills.map(createSkillXml).join("\n\n");
|
|
1503
|
+
return `<skills_system priority="1">
|
|
1504
|
+
|
|
1505
|
+
## Available Skills
|
|
1506
|
+
|
|
1507
|
+
<!-- SKILLS_TABLE_START -->
|
|
1508
|
+
<usage>
|
|
1509
|
+
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.
|
|
1510
|
+
|
|
1511
|
+
How to use skills:
|
|
1512
|
+
- Invoke: \`skillkit read <skill-name>\` or \`npx skillkit read <skill-name>\`
|
|
1513
|
+
- The skill content will load with detailed instructions on how to complete the task
|
|
1514
|
+
- Base directory provided in output for resolving bundled resources (references/, scripts/, assets/)
|
|
1515
|
+
|
|
1516
|
+
Usage notes:
|
|
1517
|
+
- Only use skills listed in <available_skills> below
|
|
1518
|
+
- Do not invoke a skill that is already loaded in your context
|
|
1519
|
+
- Each skill invocation is stateless
|
|
1520
|
+
</usage>
|
|
1521
|
+
|
|
1522
|
+
<available_skills>
|
|
1523
|
+
|
|
1524
|
+
${skillsXml}
|
|
1525
|
+
|
|
1526
|
+
</available_skills>
|
|
1527
|
+
<!-- SKILLS_TABLE_END -->
|
|
1528
|
+
|
|
1529
|
+
</skills_system>`;
|
|
1530
|
+
}
|
|
1531
|
+
parseConfig(content) {
|
|
1532
|
+
const skillNames = [];
|
|
1533
|
+
const skillRegex = /<name>([^<]+)<\/name>/g;
|
|
1534
|
+
let match;
|
|
1535
|
+
while ((match = skillRegex.exec(content)) !== null) {
|
|
1536
|
+
skillNames.push(match[1].trim());
|
|
1537
|
+
}
|
|
1538
|
+
return skillNames;
|
|
1539
|
+
}
|
|
1540
|
+
getInvokeCommand(skillName) {
|
|
1541
|
+
return `skillkit read ${skillName}`;
|
|
1542
|
+
}
|
|
1543
|
+
async isDetected() {
|
|
1544
|
+
const projectKilo = join17(process.cwd(), ".kilocode");
|
|
1545
|
+
const globalKilo = join17(homedir12(), ".kilocode");
|
|
1546
|
+
return existsSync17(projectKilo) || existsSync17(globalKilo);
|
|
1547
|
+
}
|
|
1548
|
+
};
|
|
1549
|
+
|
|
1550
|
+
// src/agents/kiro-cli.ts
|
|
1551
|
+
import { existsSync as existsSync18 } from "fs";
|
|
1552
|
+
import { join as join18 } from "path";
|
|
1553
|
+
import { homedir as homedir13 } from "os";
|
|
1554
|
+
var KiroCliAdapter = class {
|
|
1555
|
+
type = "kiro-cli";
|
|
1556
|
+
name = "Kiro CLI";
|
|
1557
|
+
skillsDir = ".kiro/skills";
|
|
1558
|
+
configFile = "AGENTS.md";
|
|
1559
|
+
globalSkillsDir = join18(homedir13(), ".kiro", "skills");
|
|
1560
|
+
generateConfig(skills) {
|
|
1561
|
+
const enabledSkills = skills.filter((s) => s.enabled);
|
|
1562
|
+
if (enabledSkills.length === 0) {
|
|
1563
|
+
return "";
|
|
1564
|
+
}
|
|
1565
|
+
const skillsXml = enabledSkills.map(createSkillXml).join("\n\n");
|
|
1566
|
+
return `<skills_system priority="1">
|
|
1567
|
+
|
|
1568
|
+
## Available Skills
|
|
1569
|
+
|
|
1570
|
+
<!-- SKILLS_TABLE_START -->
|
|
1571
|
+
<usage>
|
|
1572
|
+
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.
|
|
1573
|
+
|
|
1574
|
+
How to use skills:
|
|
1575
|
+
- Invoke: \`skillkit read <skill-name>\` or \`npx skillkit read <skill-name>\`
|
|
1576
|
+
- The skill content will load with detailed instructions on how to complete the task
|
|
1577
|
+
- Base directory provided in output for resolving bundled resources (references/, scripts/, assets/)
|
|
1578
|
+
|
|
1579
|
+
Usage notes:
|
|
1580
|
+
- Only use skills listed in <available_skills> below
|
|
1581
|
+
- Do not invoke a skill that is already loaded in your context
|
|
1582
|
+
- Each skill invocation is stateless
|
|
1583
|
+
</usage>
|
|
1584
|
+
|
|
1585
|
+
<available_skills>
|
|
1586
|
+
|
|
1587
|
+
${skillsXml}
|
|
1588
|
+
|
|
1589
|
+
</available_skills>
|
|
1590
|
+
<!-- SKILLS_TABLE_END -->
|
|
1591
|
+
|
|
1592
|
+
</skills_system>
|
|
1593
|
+
|
|
1594
|
+
**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\`:
|
|
1595
|
+
|
|
1596
|
+
\`\`\`json
|
|
1597
|
+
{
|
|
1598
|
+
"resources": [
|
|
1599
|
+
"skill://.kiro/skills/**/SKILL.md"
|
|
1600
|
+
]
|
|
1601
|
+
}
|
|
1602
|
+
\`\`\``;
|
|
1603
|
+
}
|
|
1604
|
+
parseConfig(content) {
|
|
1605
|
+
const skillNames = [];
|
|
1606
|
+
const skillRegex = /<name>([^<]+)<\/name>/g;
|
|
850
1607
|
let match;
|
|
851
|
-
while ((match =
|
|
852
|
-
|
|
853
|
-
if (name && name !== "Skill" && name !== "-------") {
|
|
854
|
-
skillNames.push(name);
|
|
855
|
-
}
|
|
1608
|
+
while ((match = skillRegex.exec(content)) !== null) {
|
|
1609
|
+
skillNames.push(match[1].trim());
|
|
856
1610
|
}
|
|
857
1611
|
return skillNames;
|
|
858
1612
|
}
|
|
@@ -860,76 +1614,62 @@ Skills are loaded on-demand to keep context clean. Only load skills when relevan
|
|
|
860
1614
|
return `skillkit read ${skillName}`;
|
|
861
1615
|
}
|
|
862
1616
|
async isDetected() {
|
|
863
|
-
const
|
|
864
|
-
const
|
|
865
|
-
return
|
|
1617
|
+
const projectKiro = join18(process.cwd(), ".kiro");
|
|
1618
|
+
const globalKiro = join18(homedir13(), ".kiro");
|
|
1619
|
+
return existsSync18(projectKiro) || existsSync18(globalKiro);
|
|
866
1620
|
}
|
|
867
1621
|
};
|
|
868
1622
|
|
|
869
|
-
// src/agents/
|
|
870
|
-
import { existsSync as
|
|
871
|
-
import { join as
|
|
872
|
-
import { homedir as
|
|
873
|
-
var
|
|
874
|
-
type = "
|
|
875
|
-
name = "
|
|
876
|
-
skillsDir = ".
|
|
877
|
-
configFile = "
|
|
1623
|
+
// src/agents/roo.ts
|
|
1624
|
+
import { existsSync as existsSync19 } from "fs";
|
|
1625
|
+
import { join as join19 } from "path";
|
|
1626
|
+
import { homedir as homedir14 } from "os";
|
|
1627
|
+
var RooAdapter = class {
|
|
1628
|
+
type = "roo";
|
|
1629
|
+
name = "Roo Code";
|
|
1630
|
+
skillsDir = ".roo/skills";
|
|
1631
|
+
configFile = "AGENTS.md";
|
|
1632
|
+
globalSkillsDir = join19(homedir14(), ".roo", "skills");
|
|
878
1633
|
generateConfig(skills) {
|
|
879
1634
|
const enabledSkills = skills.filter((s) => s.enabled);
|
|
880
1635
|
if (enabledSkills.length === 0) {
|
|
881
1636
|
return "";
|
|
882
1637
|
}
|
|
883
|
-
const
|
|
884
|
-
|
|
885
|
-
description: s.description,
|
|
886
|
-
invoke: `skillkit read ${s.name}`,
|
|
887
|
-
location: s.location
|
|
888
|
-
}));
|
|
889
|
-
return `# Skills Configuration
|
|
890
|
-
|
|
891
|
-
You have access to specialized skills that extend your capabilities.
|
|
1638
|
+
const skillsXml = enabledSkills.map(createSkillXml).join("\n\n");
|
|
1639
|
+
return `<skills_system priority="1">
|
|
892
1640
|
|
|
893
1641
|
## Available Skills
|
|
894
1642
|
|
|
895
|
-
|
|
896
|
-
|
|
1643
|
+
<!-- SKILLS_TABLE_START -->
|
|
1644
|
+
<usage>
|
|
1645
|
+
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.
|
|
897
1646
|
|
|
898
|
-
|
|
1647
|
+
How to use skills:
|
|
1648
|
+
- Invoke: \`skillkit read <skill-name>\` or \`npx skillkit read <skill-name>\`
|
|
1649
|
+
- The skill content will load with detailed instructions on how to complete the task
|
|
1650
|
+
- Base directory provided in output for resolving bundled resources (references/, scripts/, assets/)
|
|
899
1651
|
|
|
900
|
-
|
|
1652
|
+
Usage notes:
|
|
1653
|
+
- Only use skills listed in <available_skills> below
|
|
1654
|
+
- Do not invoke a skill that is already loaded in your context
|
|
1655
|
+
- Each skill invocation is stateless
|
|
1656
|
+
</usage>
|
|
901
1657
|
|
|
902
|
-
|
|
903
|
-
${JSON.stringify(skillsJson, null, 2)}
|
|
904
|
-
\`\`\`
|
|
1658
|
+
<available_skills>
|
|
905
1659
|
|
|
906
|
-
|
|
1660
|
+
${skillsXml}
|
|
907
1661
|
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
1662
|
+
</available_skills>
|
|
1663
|
+
<!-- SKILLS_TABLE_END -->
|
|
1664
|
+
|
|
1665
|
+
</skills_system>`;
|
|
912
1666
|
}
|
|
913
1667
|
parseConfig(content) {
|
|
914
1668
|
const skillNames = [];
|
|
915
|
-
const
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
if (Array.isArray(skills)) {
|
|
920
|
-
skills.forEach((s) => {
|
|
921
|
-
if (s.name) skillNames.push(s.name);
|
|
922
|
-
});
|
|
923
|
-
}
|
|
924
|
-
} catch {
|
|
925
|
-
}
|
|
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());
|
|
932
|
-
}
|
|
1669
|
+
const skillRegex = /<name>([^<]+)<\/name>/g;
|
|
1670
|
+
let match;
|
|
1671
|
+
while ((match = skillRegex.exec(content)) !== null) {
|
|
1672
|
+
skillNames.push(match[1].trim());
|
|
933
1673
|
}
|
|
934
1674
|
return skillNames;
|
|
935
1675
|
}
|
|
@@ -937,48 +1677,55 @@ ${JSON.stringify(skillsJson, null, 2)}
|
|
|
937
1677
|
return `skillkit read ${skillName}`;
|
|
938
1678
|
}
|
|
939
1679
|
async isDetected() {
|
|
940
|
-
const
|
|
941
|
-
const
|
|
942
|
-
|
|
943
|
-
return existsSync9(geminiMd) || existsSync9(geminiDir) || existsSync9(globalGemini);
|
|
1680
|
+
const projectRoo = join19(process.cwd(), ".roo");
|
|
1681
|
+
const globalRoo = join19(homedir14(), ".roo");
|
|
1682
|
+
return existsSync19(projectRoo) || existsSync19(globalRoo);
|
|
944
1683
|
}
|
|
945
1684
|
};
|
|
946
1685
|
|
|
947
|
-
// src/agents/
|
|
948
|
-
import { existsSync as
|
|
949
|
-
import { join as
|
|
950
|
-
import { homedir as
|
|
951
|
-
var
|
|
952
|
-
type = "
|
|
953
|
-
name = "
|
|
954
|
-
skillsDir = ".
|
|
1686
|
+
// src/agents/trae.ts
|
|
1687
|
+
import { existsSync as existsSync20 } from "fs";
|
|
1688
|
+
import { join as join20 } from "path";
|
|
1689
|
+
import { homedir as homedir15 } from "os";
|
|
1690
|
+
var TraeAdapter = class {
|
|
1691
|
+
type = "trae";
|
|
1692
|
+
name = "Trae";
|
|
1693
|
+
skillsDir = ".trae/skills";
|
|
955
1694
|
configFile = "AGENTS.md";
|
|
1695
|
+
globalSkillsDir = join20(homedir15(), ".trae", "skills");
|
|
956
1696
|
generateConfig(skills) {
|
|
957
1697
|
const enabledSkills = skills.filter((s) => s.enabled);
|
|
958
1698
|
if (enabledSkills.length === 0) {
|
|
959
1699
|
return "";
|
|
960
1700
|
}
|
|
961
1701
|
const skillsXml = enabledSkills.map(createSkillXml).join("\n\n");
|
|
962
|
-
return
|
|
963
|
-
# Skills
|
|
1702
|
+
return `<skills_system priority="1">
|
|
964
1703
|
|
|
965
|
-
|
|
1704
|
+
## Available Skills
|
|
966
1705
|
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
1706
|
+
<!-- SKILLS_TABLE_START -->
|
|
1707
|
+
<usage>
|
|
1708
|
+
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.
|
|
970
1709
|
|
|
971
|
-
|
|
1710
|
+
How to use skills:
|
|
1711
|
+
- Invoke: \`skillkit read <skill-name>\` or \`npx skillkit read <skill-name>\`
|
|
1712
|
+
- The skill content will load with detailed instructions on how to complete the task
|
|
1713
|
+
- Base directory provided in output for resolving bundled resources (references/, scripts/, assets/)
|
|
972
1714
|
|
|
973
|
-
|
|
1715
|
+
Usage notes:
|
|
1716
|
+
- Only use skills listed in <available_skills> below
|
|
1717
|
+
- Do not invoke a skill that is already loaded in your context
|
|
1718
|
+
- Each skill invocation is stateless
|
|
1719
|
+
</usage>
|
|
974
1720
|
|
|
975
|
-
|
|
976
|
-
skillkit read <skill-name>
|
|
977
|
-
\`\`\`
|
|
1721
|
+
<available_skills>
|
|
978
1722
|
|
|
979
|
-
|
|
1723
|
+
${skillsXml}
|
|
980
1724
|
|
|
981
|
-
|
|
1725
|
+
</available_skills>
|
|
1726
|
+
<!-- SKILLS_TABLE_END -->
|
|
1727
|
+
|
|
1728
|
+
</skills_system>`;
|
|
982
1729
|
}
|
|
983
1730
|
parseConfig(content) {
|
|
984
1731
|
const skillNames = [];
|
|
@@ -993,67 +1740,62 @@ This loads the skill's instructions into context.
|
|
|
993
1740
|
return `skillkit read ${skillName}`;
|
|
994
1741
|
}
|
|
995
1742
|
async isDetected() {
|
|
996
|
-
const
|
|
997
|
-
const
|
|
998
|
-
return
|
|
1743
|
+
const projectTrae = join20(process.cwd(), ".trae");
|
|
1744
|
+
const globalTrae = join20(homedir15(), ".trae");
|
|
1745
|
+
return existsSync20(projectTrae) || existsSync20(globalTrae);
|
|
999
1746
|
}
|
|
1000
1747
|
};
|
|
1001
1748
|
|
|
1002
|
-
// src/agents/
|
|
1003
|
-
import { existsSync as
|
|
1004
|
-
import { join as
|
|
1005
|
-
import { homedir as
|
|
1006
|
-
var
|
|
1007
|
-
type = "
|
|
1008
|
-
name = "
|
|
1009
|
-
skillsDir = ".
|
|
1749
|
+
// src/agents/windsurf.ts
|
|
1750
|
+
import { existsSync as existsSync21 } from "fs";
|
|
1751
|
+
import { join as join21 } from "path";
|
|
1752
|
+
import { homedir as homedir16 } from "os";
|
|
1753
|
+
var WindsurfAdapter = class {
|
|
1754
|
+
type = "windsurf";
|
|
1755
|
+
name = "Windsurf";
|
|
1756
|
+
skillsDir = ".windsurf/skills";
|
|
1010
1757
|
configFile = "AGENTS.md";
|
|
1758
|
+
globalSkillsDir = join21(homedir16(), ".codeium", "windsurf", "skills");
|
|
1011
1759
|
generateConfig(skills) {
|
|
1012
1760
|
const enabledSkills = skills.filter((s) => s.enabled);
|
|
1013
1761
|
if (enabledSkills.length === 0) {
|
|
1014
1762
|
return "";
|
|
1015
1763
|
}
|
|
1016
|
-
const
|
|
1017
|
-
|
|
1018
|
-
invoke: skillkit read ${s.name}`).join("\n");
|
|
1019
|
-
return `# Antigravity Skills Configuration
|
|
1020
|
-
|
|
1021
|
-
<!-- skills:
|
|
1022
|
-
${skillsYaml}
|
|
1023
|
-
-->
|
|
1764
|
+
const skillsXml = enabledSkills.map(createSkillXml).join("\n\n");
|
|
1765
|
+
return `<skills_system priority="1">
|
|
1024
1766
|
|
|
1025
1767
|
## Available Skills
|
|
1026
1768
|
|
|
1027
|
-
|
|
1769
|
+
<!-- SKILLS_TABLE_START -->
|
|
1770
|
+
<usage>
|
|
1771
|
+
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.
|
|
1028
1772
|
|
|
1029
|
-
|
|
1773
|
+
How to use skills:
|
|
1774
|
+
- Invoke: \`skillkit read <skill-name>\` or \`npx skillkit read <skill-name>\`
|
|
1775
|
+
- The skill content will load with detailed instructions on how to complete the task
|
|
1776
|
+
- Base directory provided in output for resolving bundled resources (references/, scripts/, assets/)
|
|
1030
1777
|
|
|
1031
|
-
|
|
1032
|
-
|
|
1778
|
+
Usage notes:
|
|
1779
|
+
- Only use skills listed in <available_skills> below
|
|
1780
|
+
- Do not invoke a skill that is already loaded in your context
|
|
1781
|
+
- Each skill invocation is stateless
|
|
1782
|
+
</usage>
|
|
1033
1783
|
|
|
1034
|
-
|
|
1784
|
+
<available_skills>
|
|
1035
1785
|
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1786
|
+
${skillsXml}
|
|
1787
|
+
|
|
1788
|
+
</available_skills>
|
|
1789
|
+
<!-- SKILLS_TABLE_END -->
|
|
1790
|
+
|
|
1791
|
+
</skills_system>`;
|
|
1040
1792
|
}
|
|
1041
1793
|
parseConfig(content) {
|
|
1042
1794
|
const skillNames = [];
|
|
1043
|
-
const
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
while ((match = nameRegex.exec(yamlMatch[1])) !== null) {
|
|
1048
|
-
skillNames.push(match[1].trim());
|
|
1049
|
-
}
|
|
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());
|
|
1056
|
-
}
|
|
1795
|
+
const skillRegex = /<name>([^<]+)<\/name>/g;
|
|
1796
|
+
let match;
|
|
1797
|
+
while ((match = skillRegex.exec(content)) !== null) {
|
|
1798
|
+
skillNames.push(match[1].trim());
|
|
1057
1799
|
}
|
|
1058
1800
|
return skillNames;
|
|
1059
1801
|
}
|
|
@@ -1061,15 +1803,15 @@ ${s.description}
|
|
|
1061
1803
|
return `skillkit read ${skillName}`;
|
|
1062
1804
|
}
|
|
1063
1805
|
async isDetected() {
|
|
1064
|
-
const
|
|
1065
|
-
const
|
|
1066
|
-
return
|
|
1806
|
+
const projectWindsurf = join21(process.cwd(), ".windsurf");
|
|
1807
|
+
const globalWindsurf = join21(homedir16(), ".codeium", "windsurf");
|
|
1808
|
+
return existsSync21(projectWindsurf) || existsSync21(globalWindsurf);
|
|
1067
1809
|
}
|
|
1068
1810
|
};
|
|
1069
1811
|
|
|
1070
1812
|
// src/agents/universal.ts
|
|
1071
|
-
import { existsSync as
|
|
1072
|
-
import { join as
|
|
1813
|
+
import { existsSync as existsSync22 } from "fs";
|
|
1814
|
+
import { join as join22 } from "path";
|
|
1073
1815
|
var UniversalAdapter = class {
|
|
1074
1816
|
type = "universal";
|
|
1075
1817
|
name = "Universal (Any Agent)";
|
|
@@ -1144,9 +1886,9 @@ ${skillsXml}
|
|
|
1144
1886
|
return `skillkit read ${skillName}`;
|
|
1145
1887
|
}
|
|
1146
1888
|
async isDetected() {
|
|
1147
|
-
const agentDir =
|
|
1148
|
-
const agentsMd =
|
|
1149
|
-
return
|
|
1889
|
+
const agentDir = join22(process.cwd(), ".agent");
|
|
1890
|
+
const agentsMd = join22(process.cwd(), "AGENTS.md");
|
|
1891
|
+
return existsSync22(agentDir) || existsSync22(agentsMd);
|
|
1150
1892
|
}
|
|
1151
1893
|
};
|
|
1152
1894
|
|
|
@@ -1158,6 +1900,16 @@ var adapters = {
|
|
|
1158
1900
|
"gemini-cli": new GeminiCliAdapter(),
|
|
1159
1901
|
opencode: new OpenCodeAdapter(),
|
|
1160
1902
|
antigravity: new AntigravityAdapter(),
|
|
1903
|
+
amp: new AmpAdapter(),
|
|
1904
|
+
clawdbot: new ClawdbotAdapter(),
|
|
1905
|
+
droid: new DroidAdapter(),
|
|
1906
|
+
"github-copilot": new GitHubCopilotAdapter(),
|
|
1907
|
+
goose: new GooseAdapter(),
|
|
1908
|
+
kilo: new KiloAdapter(),
|
|
1909
|
+
"kiro-cli": new KiroCliAdapter(),
|
|
1910
|
+
roo: new RooAdapter(),
|
|
1911
|
+
trae: new TraeAdapter(),
|
|
1912
|
+
windsurf: new WindsurfAdapter(),
|
|
1161
1913
|
universal: new UniversalAdapter()
|
|
1162
1914
|
};
|
|
1163
1915
|
function getAdapter(type) {
|
|
@@ -1174,6 +1926,16 @@ async function detectAgent() {
|
|
|
1174
1926
|
"gemini-cli",
|
|
1175
1927
|
"opencode",
|
|
1176
1928
|
"antigravity",
|
|
1929
|
+
"amp",
|
|
1930
|
+
"clawdbot",
|
|
1931
|
+
"droid",
|
|
1932
|
+
"github-copilot",
|
|
1933
|
+
"goose",
|
|
1934
|
+
"kilo",
|
|
1935
|
+
"kiro-cli",
|
|
1936
|
+
"roo",
|
|
1937
|
+
"trae",
|
|
1938
|
+
"windsurf",
|
|
1177
1939
|
"universal"
|
|
1178
1940
|
];
|
|
1179
1941
|
for (const type of checkOrder) {
|
|
@@ -1189,15 +1951,15 @@ async function detectAgent() {
|
|
|
1189
1951
|
var CONFIG_FILE = "skillkit.yaml";
|
|
1190
1952
|
var METADATA_FILE = ".skillkit.json";
|
|
1191
1953
|
function getProjectConfigPath() {
|
|
1192
|
-
return
|
|
1954
|
+
return join23(process.cwd(), CONFIG_FILE);
|
|
1193
1955
|
}
|
|
1194
1956
|
function getGlobalConfigPath() {
|
|
1195
|
-
return
|
|
1957
|
+
return join23(homedir17(), ".config", "skillkit", CONFIG_FILE);
|
|
1196
1958
|
}
|
|
1197
1959
|
function loadConfig() {
|
|
1198
1960
|
const projectPath = getProjectConfigPath();
|
|
1199
1961
|
const globalPath = getGlobalConfigPath();
|
|
1200
|
-
if (
|
|
1962
|
+
if (existsSync23(projectPath)) {
|
|
1201
1963
|
try {
|
|
1202
1964
|
const content = readFileSync2(projectPath, "utf-8");
|
|
1203
1965
|
const data = parseYaml2(content);
|
|
@@ -1208,7 +1970,7 @@ function loadConfig() {
|
|
|
1208
1970
|
} catch {
|
|
1209
1971
|
}
|
|
1210
1972
|
}
|
|
1211
|
-
if (
|
|
1973
|
+
if (existsSync23(globalPath)) {
|
|
1212
1974
|
try {
|
|
1213
1975
|
const content = readFileSync2(globalPath, "utf-8");
|
|
1214
1976
|
const data = parseYaml2(content);
|
|
@@ -1228,7 +1990,7 @@ function loadConfig() {
|
|
|
1228
1990
|
function saveConfig(config, global = false) {
|
|
1229
1991
|
const configPath = global ? getGlobalConfigPath() : getProjectConfigPath();
|
|
1230
1992
|
const dir = dirname(configPath);
|
|
1231
|
-
if (!
|
|
1993
|
+
if (!existsSync23(dir)) {
|
|
1232
1994
|
mkdirSync(dir, { recursive: true });
|
|
1233
1995
|
}
|
|
1234
1996
|
const content = stringifyYaml(config);
|
|
@@ -1238,32 +2000,32 @@ function getSearchDirs(agentType) {
|
|
|
1238
2000
|
const type = agentType || loadConfig().agent;
|
|
1239
2001
|
const adapter = getAdapter(type);
|
|
1240
2002
|
const dirs = [];
|
|
1241
|
-
dirs.push(
|
|
1242
|
-
dirs.push(
|
|
1243
|
-
dirs.push(
|
|
1244
|
-
dirs.push(
|
|
2003
|
+
dirs.push(join23(process.cwd(), adapter.skillsDir));
|
|
2004
|
+
dirs.push(join23(process.cwd(), ".agent", "skills"));
|
|
2005
|
+
dirs.push(join23(homedir17(), adapter.skillsDir));
|
|
2006
|
+
dirs.push(join23(homedir17(), ".agent", "skills"));
|
|
1245
2007
|
return dirs;
|
|
1246
2008
|
}
|
|
1247
2009
|
function getInstallDir(global = false, agentType) {
|
|
1248
2010
|
const type = agentType || loadConfig().agent;
|
|
1249
2011
|
const adapter = getAdapter(type);
|
|
1250
2012
|
if (global) {
|
|
1251
|
-
return
|
|
2013
|
+
return join23(homedir17(), adapter.skillsDir);
|
|
1252
2014
|
}
|
|
1253
|
-
return
|
|
2015
|
+
return join23(process.cwd(), adapter.skillsDir);
|
|
1254
2016
|
}
|
|
1255
2017
|
function getAgentConfigPath(agentType) {
|
|
1256
2018
|
const type = agentType || loadConfig().agent;
|
|
1257
2019
|
const adapter = getAdapter(type);
|
|
1258
|
-
return
|
|
2020
|
+
return join23(process.cwd(), adapter.configFile);
|
|
1259
2021
|
}
|
|
1260
2022
|
function saveSkillMetadata(skillPath, metadata) {
|
|
1261
|
-
const metadataPath =
|
|
2023
|
+
const metadataPath = join23(skillPath, METADATA_FILE);
|
|
1262
2024
|
writeFileSync(metadataPath, JSON.stringify(metadata, null, 2), "utf-8");
|
|
1263
2025
|
}
|
|
1264
2026
|
function loadSkillMetadata(skillPath) {
|
|
1265
|
-
const metadataPath =
|
|
1266
|
-
if (!
|
|
2027
|
+
const metadataPath = join23(skillPath, METADATA_FILE);
|
|
2028
|
+
if (!existsSync23(metadataPath)) {
|
|
1267
2029
|
return null;
|
|
1268
2030
|
}
|
|
1269
2031
|
try {
|
|
@@ -1286,8 +2048,8 @@ function setSkillEnabled(skillPath, enabled) {
|
|
|
1286
2048
|
async function initProject(agentType) {
|
|
1287
2049
|
const type = agentType || await detectAgent();
|
|
1288
2050
|
const adapter = getAdapter(type);
|
|
1289
|
-
const skillsDir =
|
|
1290
|
-
if (!
|
|
2051
|
+
const skillsDir = join23(process.cwd(), adapter.skillsDir);
|
|
2052
|
+
if (!existsSync23(skillsDir)) {
|
|
1291
2053
|
mkdirSync(skillsDir, { recursive: true });
|
|
1292
2054
|
}
|
|
1293
2055
|
const config = {
|
|
@@ -1296,8 +2058,8 @@ async function initProject(agentType) {
|
|
|
1296
2058
|
autoSync: true
|
|
1297
2059
|
};
|
|
1298
2060
|
saveConfig(config);
|
|
1299
|
-
const agentConfigPath =
|
|
1300
|
-
if (!
|
|
2061
|
+
const agentConfigPath = join23(process.cwd(), adapter.configFile);
|
|
2062
|
+
if (!existsSync23(agentConfigPath)) {
|
|
1301
2063
|
writeFileSync(agentConfigPath, `# ${adapter.name} Configuration
|
|
1302
2064
|
|
|
1303
2065
|
`, "utf-8");
|
|
@@ -1317,7 +2079,9 @@ var InstallCommand = class extends Command {
|
|
|
1317
2079
|
["Install specific skills (CI/CD)", "$0 install owner/repo --skills=pdf,xlsx"],
|
|
1318
2080
|
["Install all skills non-interactively", "$0 install owner/repo --all"],
|
|
1319
2081
|
["Install from local path", "$0 install ./my-skills"],
|
|
1320
|
-
["Install globally", "$0 install owner/repo --global"]
|
|
2082
|
+
["Install globally", "$0 install owner/repo --global"],
|
|
2083
|
+
["List available skills", "$0 install owner/repo --list"],
|
|
2084
|
+
["Install to specific agents", "$0 install owner/repo --agent claude-code --agent cursor"]
|
|
1321
2085
|
]
|
|
1322
2086
|
});
|
|
1323
2087
|
source = Option.String({ required: true });
|
|
@@ -1339,6 +2103,12 @@ var InstallCommand = class extends Command {
|
|
|
1339
2103
|
provider = Option.String("--provider,-p", {
|
|
1340
2104
|
description: "Force specific provider (github, gitlab, bitbucket)"
|
|
1341
2105
|
});
|
|
2106
|
+
list = Option.Boolean("--list,-l", false, {
|
|
2107
|
+
description: "List available skills without installing"
|
|
2108
|
+
});
|
|
2109
|
+
agent = Option.Array("--agent", {
|
|
2110
|
+
description: "Target specific agents (can specify multiple)"
|
|
2111
|
+
});
|
|
1342
2112
|
async execute() {
|
|
1343
2113
|
const spinner = ora();
|
|
1344
2114
|
try {
|
|
@@ -1364,6 +2134,25 @@ var InstallCommand = class extends Command {
|
|
|
1364
2134
|
}
|
|
1365
2135
|
spinner.succeed(`Found ${result.skills?.length || 0} skill(s)`);
|
|
1366
2136
|
const discoveredSkills = result.discoveredSkills || [];
|
|
2137
|
+
if (this.list) {
|
|
2138
|
+
if (discoveredSkills.length === 0) {
|
|
2139
|
+
console.log(chalk.yellow("\nNo skills found in this repository"));
|
|
2140
|
+
} else {
|
|
2141
|
+
console.log(chalk.cyan("\nAvailable skills:\n"));
|
|
2142
|
+
for (const skill of discoveredSkills) {
|
|
2143
|
+
console.log(` ${chalk.green(skill.name)}`);
|
|
2144
|
+
}
|
|
2145
|
+
console.log();
|
|
2146
|
+
console.log(chalk.dim(`Total: ${discoveredSkills.length} skill(s)`));
|
|
2147
|
+
console.log(chalk.dim("\nTo install specific skills: skillkit install <source> --skills=skill1,skill2"));
|
|
2148
|
+
console.log(chalk.dim("To install all skills: skillkit install <source> --all"));
|
|
2149
|
+
}
|
|
2150
|
+
const cleanupPath2 = result.tempRoot || result.path;
|
|
2151
|
+
if (!isLocalPath(this.source) && cleanupPath2 && existsSync24(cleanupPath2)) {
|
|
2152
|
+
rmSync4(cleanupPath2, { recursive: true, force: true });
|
|
2153
|
+
}
|
|
2154
|
+
return 0;
|
|
2155
|
+
}
|
|
1367
2156
|
let skillsToInstall = discoveredSkills;
|
|
1368
2157
|
if (this.skills) {
|
|
1369
2158
|
const requestedSkills = this.skills.split(",").map((s) => s.trim());
|
|
@@ -1389,53 +2178,78 @@ var InstallCommand = class extends Command {
|
|
|
1389
2178
|
console.log(chalk.yellow("No skills to install"));
|
|
1390
2179
|
return 0;
|
|
1391
2180
|
}
|
|
1392
|
-
|
|
1393
|
-
if (
|
|
1394
|
-
|
|
1395
|
-
}
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
2181
|
+
let targetAgents;
|
|
2182
|
+
if (this.agent && this.agent.length > 0) {
|
|
2183
|
+
targetAgents = this.agent;
|
|
2184
|
+
} else {
|
|
2185
|
+
const detectedAgent = await detectAgent();
|
|
2186
|
+
targetAgents = [detectedAgent];
|
|
2187
|
+
}
|
|
2188
|
+
let totalInstalled = 0;
|
|
2189
|
+
const installResults = [];
|
|
2190
|
+
for (const agentType of targetAgents) {
|
|
2191
|
+
const adapter = getAdapter(agentType);
|
|
2192
|
+
const installDir = getInstallDir(this.global, agentType);
|
|
2193
|
+
if (!existsSync24(installDir)) {
|
|
2194
|
+
mkdirSync2(installDir, { recursive: true });
|
|
1404
2195
|
}
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
continue;
|
|
2196
|
+
if (targetAgents.length > 1) {
|
|
2197
|
+
console.log(chalk.cyan(`
|
|
2198
|
+
Installing to ${adapter.name}...`));
|
|
1409
2199
|
}
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
2200
|
+
let installed = 0;
|
|
2201
|
+
for (const skill of skillsToInstall) {
|
|
2202
|
+
const skillName = skill.name;
|
|
2203
|
+
const sourcePath = skill.path;
|
|
2204
|
+
const targetPath = join24(installDir, skillName);
|
|
2205
|
+
if (existsSync24(targetPath) && !this.force) {
|
|
2206
|
+
console.log(chalk.yellow(` Skipping ${skillName} (already exists, use --force to overwrite)`));
|
|
2207
|
+
continue;
|
|
2208
|
+
}
|
|
2209
|
+
const securityRoot = result.tempRoot || result.path;
|
|
2210
|
+
if (!isPathInside(sourcePath, securityRoot)) {
|
|
2211
|
+
console.log(chalk.red(` Skipping ${skillName} (path traversal detected)`));
|
|
2212
|
+
continue;
|
|
2213
|
+
}
|
|
2214
|
+
spinner.start(`Installing ${skillName}...`);
|
|
2215
|
+
try {
|
|
2216
|
+
if (existsSync24(targetPath)) {
|
|
2217
|
+
rmSync4(targetPath, { recursive: true, force: true });
|
|
2218
|
+
}
|
|
2219
|
+
cpSync(sourcePath, targetPath, { recursive: true, dereference: true });
|
|
2220
|
+
const metadata = {
|
|
2221
|
+
name: skillName,
|
|
2222
|
+
description: "",
|
|
2223
|
+
source: this.source,
|
|
2224
|
+
sourceType: providerAdapter.type,
|
|
2225
|
+
subpath: skillName,
|
|
2226
|
+
installedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2227
|
+
enabled: true
|
|
2228
|
+
};
|
|
2229
|
+
saveSkillMetadata(targetPath, metadata);
|
|
2230
|
+
spinner.succeed(chalk.green(`Installed ${skillName}`));
|
|
2231
|
+
installed++;
|
|
2232
|
+
} catch (error) {
|
|
2233
|
+
spinner.fail(chalk.red(`Failed to install ${skillName}`));
|
|
2234
|
+
console.error(chalk.dim(error instanceof Error ? error.message : String(error)));
|
|
1414
2235
|
}
|
|
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
2236
|
}
|
|
2237
|
+
totalInstalled += installed;
|
|
2238
|
+
installResults.push({ agent: adapter.name, dir: installDir, count: installed });
|
|
1432
2239
|
}
|
|
1433
2240
|
const cleanupPath = result.tempRoot || result.path;
|
|
1434
|
-
if (!isLocalPath(this.source) && cleanupPath &&
|
|
2241
|
+
if (!isLocalPath(this.source) && cleanupPath && existsSync24(cleanupPath)) {
|
|
1435
2242
|
rmSync4(cleanupPath, { recursive: true, force: true });
|
|
1436
2243
|
}
|
|
1437
2244
|
console.log();
|
|
1438
|
-
|
|
2245
|
+
if (targetAgents.length > 1) {
|
|
2246
|
+
console.log(chalk.green(`Installed ${totalInstalled} skill(s) across ${targetAgents.length} agents:`));
|
|
2247
|
+
for (const r of installResults) {
|
|
2248
|
+
console.log(chalk.dim(` - ${r.agent}: ${r.count} skill(s) to ${r.dir}`));
|
|
2249
|
+
}
|
|
2250
|
+
} else {
|
|
2251
|
+
console.log(chalk.green(`Installed ${totalInstalled} skill(s) to ${installResults[0]?.dir}`));
|
|
2252
|
+
}
|
|
1439
2253
|
if (!this.yes) {
|
|
1440
2254
|
console.log(chalk.dim("\nRun `skillkit sync` to update your agent config"));
|
|
1441
2255
|
}
|
|
@@ -1449,7 +2263,7 @@ var InstallCommand = class extends Command {
|
|
|
1449
2263
|
};
|
|
1450
2264
|
|
|
1451
2265
|
// src/commands/sync.ts
|
|
1452
|
-
import { existsSync as
|
|
2266
|
+
import { existsSync as existsSync25, readFileSync as readFileSync3, writeFileSync as writeFileSync2, mkdirSync as mkdirSync3 } from "fs";
|
|
1453
2267
|
import { dirname as dirname2 } from "path";
|
|
1454
2268
|
import chalk2 from "chalk";
|
|
1455
2269
|
import { Command as Command2, Option as Option2 } from "clipanion";
|
|
@@ -1511,12 +2325,12 @@ var SyncCommand = class extends Command2 {
|
|
|
1511
2325
|
return 0;
|
|
1512
2326
|
}
|
|
1513
2327
|
let existingContent = "";
|
|
1514
|
-
if (
|
|
2328
|
+
if (existsSync25(outputPath)) {
|
|
1515
2329
|
existingContent = readFileSync3(outputPath, "utf-8");
|
|
1516
2330
|
}
|
|
1517
2331
|
const newContent = updateConfigContent(existingContent, config, agentType);
|
|
1518
2332
|
const dir = dirname2(outputPath);
|
|
1519
|
-
if (!
|
|
2333
|
+
if (!existsSync25(dir)) {
|
|
1520
2334
|
mkdirSync3(dir, { recursive: true });
|
|
1521
2335
|
}
|
|
1522
2336
|
writeFileSync2(outputPath, newContent, "utf-8");
|
|
@@ -1799,8 +2613,8 @@ var DisableCommand = class extends Command5 {
|
|
|
1799
2613
|
};
|
|
1800
2614
|
|
|
1801
2615
|
// src/commands/update.ts
|
|
1802
|
-
import { existsSync as
|
|
1803
|
-
import { join as
|
|
2616
|
+
import { existsSync as existsSync26, rmSync as rmSync5, cpSync as cpSync2 } from "fs";
|
|
2617
|
+
import { join as join25 } from "path";
|
|
1804
2618
|
import chalk6 from "chalk";
|
|
1805
2619
|
import ora2 from "ora";
|
|
1806
2620
|
import { Command as Command6, Option as Option6 } from "clipanion";
|
|
@@ -1852,14 +2666,14 @@ var UpdateCommand = class extends Command6 {
|
|
|
1852
2666
|
spinner.start(`Updating ${skill.name}...`);
|
|
1853
2667
|
try {
|
|
1854
2668
|
if (isLocalPath(metadata.source)) {
|
|
1855
|
-
const localPath = metadata.subpath ?
|
|
1856
|
-
if (!
|
|
2669
|
+
const localPath = metadata.subpath ? join25(metadata.source, metadata.subpath) : metadata.source;
|
|
2670
|
+
if (!existsSync26(localPath)) {
|
|
1857
2671
|
spinner.warn(chalk6.yellow(`${skill.name}: local source missing`));
|
|
1858
2672
|
skipped++;
|
|
1859
2673
|
continue;
|
|
1860
2674
|
}
|
|
1861
|
-
const skillMdPath =
|
|
1862
|
-
if (!
|
|
2675
|
+
const skillMdPath = join25(localPath, "SKILL.md");
|
|
2676
|
+
if (!existsSync26(skillMdPath)) {
|
|
1863
2677
|
spinner.warn(chalk6.yellow(`${skill.name}: no SKILL.md at source`));
|
|
1864
2678
|
skipped++;
|
|
1865
2679
|
continue;
|
|
@@ -1883,9 +2697,9 @@ var UpdateCommand = class extends Command6 {
|
|
|
1883
2697
|
failed++;
|
|
1884
2698
|
continue;
|
|
1885
2699
|
}
|
|
1886
|
-
const sourcePath = metadata.subpath ?
|
|
1887
|
-
const skillMdPath =
|
|
1888
|
-
if (!
|
|
2700
|
+
const sourcePath = metadata.subpath ? join25(result.path, metadata.subpath) : result.path;
|
|
2701
|
+
const skillMdPath = join25(sourcePath, "SKILL.md");
|
|
2702
|
+
if (!existsSync26(skillMdPath)) {
|
|
1889
2703
|
spinner.warn(chalk6.yellow(`${skill.name}: no SKILL.md in source`));
|
|
1890
2704
|
rmSync5(result.path, { recursive: true, force: true });
|
|
1891
2705
|
skipped++;
|
|
@@ -1916,7 +2730,7 @@ var UpdateCommand = class extends Command6 {
|
|
|
1916
2730
|
};
|
|
1917
2731
|
|
|
1918
2732
|
// src/commands/remove.ts
|
|
1919
|
-
import { existsSync as
|
|
2733
|
+
import { existsSync as existsSync27, rmSync as rmSync6 } from "fs";
|
|
1920
2734
|
import chalk7 from "chalk";
|
|
1921
2735
|
import { Command as Command7, Option as Option7 } from "clipanion";
|
|
1922
2736
|
init_skills();
|
|
@@ -1944,7 +2758,7 @@ var RemoveCommand = class extends Command7 {
|
|
|
1944
2758
|
console.log(chalk7.yellow(`Skill not found: ${skillName}`));
|
|
1945
2759
|
continue;
|
|
1946
2760
|
}
|
|
1947
|
-
if (!
|
|
2761
|
+
if (!existsSync27(skill.path)) {
|
|
1948
2762
|
console.log(chalk7.yellow(`Path not found: ${skill.path}`));
|
|
1949
2763
|
continue;
|
|
1950
2764
|
}
|
|
@@ -2031,8 +2845,8 @@ var InitCommand = class extends Command8 {
|
|
|
2031
2845
|
|
|
2032
2846
|
// src/commands/validate.ts
|
|
2033
2847
|
init_skills();
|
|
2034
|
-
import { existsSync as
|
|
2035
|
-
import { join as
|
|
2848
|
+
import { existsSync as existsSync28, readdirSync as readdirSync2 } from "fs";
|
|
2849
|
+
import { join as join26, basename as basename6 } from "path";
|
|
2036
2850
|
import chalk9 from "chalk";
|
|
2037
2851
|
import { Command as Command9, Option as Option9 } from "clipanion";
|
|
2038
2852
|
var ValidateCommand = class extends Command9 {
|
|
@@ -2050,7 +2864,7 @@ var ValidateCommand = class extends Command9 {
|
|
|
2050
2864
|
});
|
|
2051
2865
|
async execute() {
|
|
2052
2866
|
const targetPath = this.skillPath;
|
|
2053
|
-
if (!
|
|
2867
|
+
if (!existsSync28(targetPath)) {
|
|
2054
2868
|
console.error(chalk9.red(`Path does not exist: ${targetPath}`));
|
|
2055
2869
|
return 1;
|
|
2056
2870
|
}
|
|
@@ -2059,8 +2873,8 @@ var ValidateCommand = class extends Command9 {
|
|
|
2059
2873
|
const entries = readdirSync2(targetPath, { withFileTypes: true });
|
|
2060
2874
|
for (const entry of entries) {
|
|
2061
2875
|
if (entry.isDirectory()) {
|
|
2062
|
-
const skillPath =
|
|
2063
|
-
if (
|
|
2876
|
+
const skillPath = join26(targetPath, entry.name);
|
|
2877
|
+
if (existsSync28(join26(skillPath, "SKILL.md"))) {
|
|
2064
2878
|
skillPaths.push(skillPath);
|
|
2065
2879
|
}
|
|
2066
2880
|
}
|
|
@@ -2102,6 +2916,114 @@ var ValidateCommand = class extends Command9 {
|
|
|
2102
2916
|
}
|
|
2103
2917
|
};
|
|
2104
2918
|
|
|
2919
|
+
// src/commands/create.ts
|
|
2920
|
+
import { existsSync as existsSync29, mkdirSync as mkdirSync4, writeFileSync as writeFileSync3 } from "fs";
|
|
2921
|
+
import { join as join27 } from "path";
|
|
2922
|
+
import chalk10 from "chalk";
|
|
2923
|
+
import { Command as Command10, Option as Option10 } from "clipanion";
|
|
2924
|
+
var CreateCommand = class extends Command10 {
|
|
2925
|
+
static paths = [["create"], ["new"]];
|
|
2926
|
+
static usage = Command10.Usage({
|
|
2927
|
+
description: "Create a new skill with proper structure",
|
|
2928
|
+
examples: [
|
|
2929
|
+
["Create a new skill", "$0 create my-skill"],
|
|
2930
|
+
["Create with all optional directories", "$0 create my-skill --full"],
|
|
2931
|
+
["Create with scripts directory", "$0 create my-skill --scripts"]
|
|
2932
|
+
]
|
|
2933
|
+
});
|
|
2934
|
+
name = Option10.String({ required: true, name: "skill-name" });
|
|
2935
|
+
full = Option10.Boolean("--full,-f", false, {
|
|
2936
|
+
description: "Include all optional directories (references, scripts, assets)"
|
|
2937
|
+
});
|
|
2938
|
+
scripts = Option10.Boolean("--scripts", false, {
|
|
2939
|
+
description: "Include scripts directory"
|
|
2940
|
+
});
|
|
2941
|
+
references = Option10.Boolean("--references", false, {
|
|
2942
|
+
description: "Include references directory"
|
|
2943
|
+
});
|
|
2944
|
+
assets = Option10.Boolean("--assets", false, {
|
|
2945
|
+
description: "Include assets directory"
|
|
2946
|
+
});
|
|
2947
|
+
directory = Option10.String("--dir,-d", {
|
|
2948
|
+
description: "Parent directory to create skill in (default: current directory)"
|
|
2949
|
+
});
|
|
2950
|
+
async execute() {
|
|
2951
|
+
const skillName = this.name.toLowerCase();
|
|
2952
|
+
if (!/^[a-z0-9]+(-[a-z0-9]+)*$/.test(skillName)) {
|
|
2953
|
+
console.error(chalk10.red("Invalid skill name"));
|
|
2954
|
+
console.error(chalk10.dim("Must be lowercase alphanumeric with hyphens (e.g., my-skill)"));
|
|
2955
|
+
return 1;
|
|
2956
|
+
}
|
|
2957
|
+
const parentDir = this.directory || process.cwd();
|
|
2958
|
+
const skillDir = join27(parentDir, skillName);
|
|
2959
|
+
if (existsSync29(skillDir)) {
|
|
2960
|
+
console.error(chalk10.red(`Directory already exists: ${skillDir}`));
|
|
2961
|
+
return 1;
|
|
2962
|
+
}
|
|
2963
|
+
try {
|
|
2964
|
+
mkdirSync4(skillDir, { recursive: true });
|
|
2965
|
+
const skillMd = generateSkillMd(skillName);
|
|
2966
|
+
writeFileSync3(join27(skillDir, "SKILL.md"), skillMd);
|
|
2967
|
+
if (this.full || this.references) {
|
|
2968
|
+
const refsDir = join27(skillDir, "references");
|
|
2969
|
+
mkdirSync4(refsDir);
|
|
2970
|
+
writeFileSync3(join27(refsDir, ".gitkeep"), "");
|
|
2971
|
+
}
|
|
2972
|
+
if (this.full || this.scripts) {
|
|
2973
|
+
const scriptsDir = join27(skillDir, "scripts");
|
|
2974
|
+
mkdirSync4(scriptsDir);
|
|
2975
|
+
writeFileSync3(join27(scriptsDir, ".gitkeep"), "");
|
|
2976
|
+
}
|
|
2977
|
+
if (this.full || this.assets) {
|
|
2978
|
+
const assetsDir = join27(skillDir, "assets");
|
|
2979
|
+
mkdirSync4(assetsDir);
|
|
2980
|
+
writeFileSync3(join27(assetsDir, ".gitkeep"), "");
|
|
2981
|
+
}
|
|
2982
|
+
console.log(chalk10.green(`Created skill: ${skillName}`));
|
|
2983
|
+
console.log();
|
|
2984
|
+
console.log(chalk10.dim("Structure:"));
|
|
2985
|
+
console.log(chalk10.dim(` ${skillDir}/`));
|
|
2986
|
+
console.log(chalk10.dim(" \u251C\u2500\u2500 SKILL.md"));
|
|
2987
|
+
if (this.full || this.references) console.log(chalk10.dim(" \u251C\u2500\u2500 references/"));
|
|
2988
|
+
if (this.full || this.scripts) console.log(chalk10.dim(" \u251C\u2500\u2500 scripts/"));
|
|
2989
|
+
if (this.full || this.assets) console.log(chalk10.dim(" \u2514\u2500\u2500 assets/"));
|
|
2990
|
+
console.log();
|
|
2991
|
+
console.log(chalk10.cyan("Next steps:"));
|
|
2992
|
+
console.log(chalk10.dim(" 1. Edit SKILL.md with your instructions"));
|
|
2993
|
+
console.log(chalk10.dim(" 2. Validate: skillkit validate " + skillDir));
|
|
2994
|
+
console.log(chalk10.dim(" 3. Test: skillkit read " + skillName));
|
|
2995
|
+
return 0;
|
|
2996
|
+
} catch (error) {
|
|
2997
|
+
console.error(chalk10.red("Failed to create skill"));
|
|
2998
|
+
console.error(chalk10.dim(error instanceof Error ? error.message : String(error)));
|
|
2999
|
+
return 1;
|
|
3000
|
+
}
|
|
3001
|
+
}
|
|
3002
|
+
};
|
|
3003
|
+
function generateSkillMd(name) {
|
|
3004
|
+
const title = name.split("-").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
|
|
3005
|
+
return `---
|
|
3006
|
+
name: ${name}
|
|
3007
|
+
description: Describe what this skill does and when to use it. Include trigger keywords.
|
|
3008
|
+
---
|
|
3009
|
+
|
|
3010
|
+
# ${title}
|
|
3011
|
+
|
|
3012
|
+
Instructions for the AI agent on how to use this skill.
|
|
3013
|
+
|
|
3014
|
+
## When to Use
|
|
3015
|
+
|
|
3016
|
+
- Scenario 1
|
|
3017
|
+
- Scenario 2
|
|
3018
|
+
|
|
3019
|
+
## Steps
|
|
3020
|
+
|
|
3021
|
+
1. First step
|
|
3022
|
+
2. Second step
|
|
3023
|
+
3. Third step
|
|
3024
|
+
`;
|
|
3025
|
+
}
|
|
3026
|
+
|
|
2105
3027
|
// src/cli.ts
|
|
2106
3028
|
var cli = new Cli({
|
|
2107
3029
|
binaryLabel: "skillkit",
|
|
@@ -2120,5 +3042,6 @@ cli.register(UpdateCommand);
|
|
|
2120
3042
|
cli.register(RemoveCommand);
|
|
2121
3043
|
cli.register(InitCommand);
|
|
2122
3044
|
cli.register(ValidateCommand);
|
|
3045
|
+
cli.register(CreateCommand);
|
|
2123
3046
|
cli.runExit(process.argv.slice(2));
|
|
2124
3047
|
//# sourceMappingURL=cli.js.map
|