codex-skills-mcp 1.0.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 +221 -0
- package/dist/config.d.ts +22 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +95 -0
- package/dist/config.js.map +1 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +160 -0
- package/dist/index.js.map +1 -0
- package/dist/loader/index.d.ts +68 -0
- package/dist/loader/index.d.ts.map +1 -0
- package/dist/loader/index.js +246 -0
- package/dist/loader/index.js.map +1 -0
- package/dist/remote/github.d.ts +14 -0
- package/dist/remote/github.d.ts.map +1 -0
- package/dist/remote/github.js +90 -0
- package/dist/remote/github.js.map +1 -0
- package/dist/search/index.d.ts +45 -0
- package/dist/search/index.d.ts.map +1 -0
- package/dist/search/index.js +149 -0
- package/dist/search/index.js.map +1 -0
- package/dist/tools/list-categories.d.ts +4 -0
- package/dist/tools/list-categories.d.ts.map +1 -0
- package/dist/tools/list-categories.js +18 -0
- package/dist/tools/list-categories.js.map +1 -0
- package/dist/tools/list-skill-files.d.ts +5 -0
- package/dist/tools/list-skill-files.d.ts.map +1 -0
- package/dist/tools/list-skill-files.js +61 -0
- package/dist/tools/list-skill-files.js.map +1 -0
- package/dist/tools/load-skill-file.d.ts +5 -0
- package/dist/tools/load-skill-file.d.ts.map +1 -0
- package/dist/tools/load-skill-file.js +41 -0
- package/dist/tools/load-skill-file.js.map +1 -0
- package/dist/tools/plan-workflow.d.ts +4 -0
- package/dist/tools/plan-workflow.d.ts.map +1 -0
- package/dist/tools/plan-workflow.js +53 -0
- package/dist/tools/plan-workflow.js.map +1 -0
- package/dist/tools/read-skill.d.ts +5 -0
- package/dist/tools/read-skill.d.ts.map +1 -0
- package/dist/tools/read-skill.js +100 -0
- package/dist/tools/read-skill.js.map +1 -0
- package/dist/tools/search-skills.d.ts +4 -0
- package/dist/tools/search-skills.d.ts.map +1 -0
- package/dist/tools/search-skills.js +32 -0
- package/dist/tools/search-skills.js.map +1 -0
- package/package.json +39 -0
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
import { readFileSync, readdirSync, statSync, existsSync } from "node:fs";
|
|
2
|
+
import { resolve, join, relative, extname } from "node:path";
|
|
3
|
+
import { ensureSkillFetched } from "../remote/github.js";
|
|
4
|
+
// Files/dirs to skip when scanning structure
|
|
5
|
+
const SKIP_NAMES = new Set([
|
|
6
|
+
"node_modules", ".git", ".github", "__pycache__",
|
|
7
|
+
".DS_Store", ".env", ".venv", "venv",
|
|
8
|
+
"dist", "build", ".next", ".cache",
|
|
9
|
+
]);
|
|
10
|
+
// Max file size to return via load_skill_file (500KB)
|
|
11
|
+
const MAX_FILE_SIZE = 500 * 1024;
|
|
12
|
+
/**
|
|
13
|
+
* Skill loader — reads SKILL.md, scans structure, detects dependencies.
|
|
14
|
+
*/
|
|
15
|
+
export class SkillLoader {
|
|
16
|
+
config;
|
|
17
|
+
manifest;
|
|
18
|
+
skillsDir;
|
|
19
|
+
constructor(config, manifest) {
|
|
20
|
+
this.config = config;
|
|
21
|
+
this.manifest = manifest;
|
|
22
|
+
this.skillsDir = config.skillsDir;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Resolve the absolute filesystem path for a skill.
|
|
26
|
+
*/
|
|
27
|
+
resolveSkillPath(entry) {
|
|
28
|
+
// relative_path starts with "./" and is relative to the manifest dir
|
|
29
|
+
const relPath = entry.relative_path.replace(/^\.\//, "");
|
|
30
|
+
return resolve(this.skillsDir, relPath);
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Read a skill's SKILL.md + structure + dependencies.
|
|
34
|
+
*/
|
|
35
|
+
async readSkill(entry) {
|
|
36
|
+
if (this.config.isRemote) {
|
|
37
|
+
await ensureSkillFetched(this.config, entry);
|
|
38
|
+
}
|
|
39
|
+
const skillPath = this.resolveSkillPath(entry);
|
|
40
|
+
// Read SKILL.md
|
|
41
|
+
let instructions = "";
|
|
42
|
+
const skillMdPath = join(skillPath, "SKILL.md");
|
|
43
|
+
if (existsSync(skillMdPath)) {
|
|
44
|
+
instructions = readFileSync(skillMdPath, "utf-8");
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
instructions = `[No SKILL.md found for ${entry.name}]\n\nDescription: ${entry.description}`;
|
|
48
|
+
}
|
|
49
|
+
// Scan structure
|
|
50
|
+
const structure = this.scanStructure(skillPath, entry);
|
|
51
|
+
// Detect dependencies
|
|
52
|
+
const dependencies = this.detectDependencies(skillPath);
|
|
53
|
+
return { instructions, structure, dependencies };
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Scan the file tree of a skill (max depth 2 by default).
|
|
57
|
+
*/
|
|
58
|
+
scanStructure(dirPath, entry, maxDepth = 2) {
|
|
59
|
+
const files = this.scanDirectory(dirPath, 0, maxDepth);
|
|
60
|
+
// Find sub-skills: look for nested SKILL.md files
|
|
61
|
+
const subSkills = [];
|
|
62
|
+
this.findSubSkills(dirPath, dirPath, subSkills);
|
|
63
|
+
return { files, sub_skills: subSkills };
|
|
64
|
+
}
|
|
65
|
+
scanDirectory(dirPath, currentDepth, maxDepth) {
|
|
66
|
+
if (!existsSync(dirPath))
|
|
67
|
+
return [];
|
|
68
|
+
const nodes = [];
|
|
69
|
+
try {
|
|
70
|
+
const entries = readdirSync(dirPath, { withFileTypes: true });
|
|
71
|
+
for (const entry of entries) {
|
|
72
|
+
if (SKIP_NAMES.has(entry.name))
|
|
73
|
+
continue;
|
|
74
|
+
if (entry.name.startsWith(".") && entry.name !== ".env.example")
|
|
75
|
+
continue;
|
|
76
|
+
const fullPath = join(dirPath, entry.name);
|
|
77
|
+
if (entry.isDirectory()) {
|
|
78
|
+
const node = {
|
|
79
|
+
name: entry.name,
|
|
80
|
+
type: "directory",
|
|
81
|
+
};
|
|
82
|
+
if (currentDepth < maxDepth) {
|
|
83
|
+
node.children = this.scanDirectory(fullPath, currentDepth + 1, maxDepth);
|
|
84
|
+
}
|
|
85
|
+
nodes.push(node);
|
|
86
|
+
}
|
|
87
|
+
else if (entry.isFile()) {
|
|
88
|
+
try {
|
|
89
|
+
const stat = statSync(fullPath);
|
|
90
|
+
nodes.push({
|
|
91
|
+
name: entry.name,
|
|
92
|
+
type: "file",
|
|
93
|
+
size_bytes: stat.size,
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
catch {
|
|
97
|
+
nodes.push({ name: entry.name, type: "file" });
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
catch {
|
|
103
|
+
// Permission denied or other errors
|
|
104
|
+
}
|
|
105
|
+
return nodes;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Recursively find sub-skill SKILL.md files (not the root one).
|
|
109
|
+
*/
|
|
110
|
+
findSubSkills(rootPath, currentPath, results, depth = 0) {
|
|
111
|
+
if (depth > 4)
|
|
112
|
+
return;
|
|
113
|
+
try {
|
|
114
|
+
const entries = readdirSync(currentPath, { withFileTypes: true });
|
|
115
|
+
for (const entry of entries) {
|
|
116
|
+
if (!entry.isDirectory())
|
|
117
|
+
continue;
|
|
118
|
+
if (SKIP_NAMES.has(entry.name))
|
|
119
|
+
continue;
|
|
120
|
+
const subDir = join(currentPath, entry.name);
|
|
121
|
+
const subSkillMd = join(subDir, "SKILL.md");
|
|
122
|
+
if (existsSync(subSkillMd)) {
|
|
123
|
+
// Extract name from frontmatter or use folder name
|
|
124
|
+
const content = readFileSync(subSkillMd, "utf-8");
|
|
125
|
+
const nameMatch = content.match(/^---[\s\S]*?name:\s*(.+?)$/m);
|
|
126
|
+
const descMatch = content.match(/^---[\s\S]*?description:\s*(.+?)$/m);
|
|
127
|
+
results.push({
|
|
128
|
+
name: nameMatch ? nameMatch[1].trim() : entry.name,
|
|
129
|
+
path: relative(rootPath, subDir),
|
|
130
|
+
description: descMatch ? descMatch[1].trim() : "",
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
// Recurse deeper
|
|
134
|
+
this.findSubSkills(rootPath, subDir, results, depth + 1);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
catch {
|
|
138
|
+
// Permission denied
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Detect language and package manager from project files.
|
|
143
|
+
*/
|
|
144
|
+
detectDependencies(skillPath) {
|
|
145
|
+
// Python
|
|
146
|
+
if (existsSync(join(skillPath, "requirements.txt"))) {
|
|
147
|
+
return {
|
|
148
|
+
language: "python",
|
|
149
|
+
package_manager: "pip",
|
|
150
|
+
setup_command: "pip install -r requirements.txt",
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
if (existsSync(join(skillPath, "pyproject.toml"))) {
|
|
154
|
+
if (existsSync(join(skillPath, "uv.lock"))) {
|
|
155
|
+
return {
|
|
156
|
+
language: "python",
|
|
157
|
+
package_manager: "uv",
|
|
158
|
+
setup_command: "uv sync",
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
return {
|
|
162
|
+
language: "python",
|
|
163
|
+
package_manager: "pip",
|
|
164
|
+
setup_command: "pip install .",
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
// Node.js
|
|
168
|
+
if (existsSync(join(skillPath, "package.json"))) {
|
|
169
|
+
return {
|
|
170
|
+
language: "typescript/javascript",
|
|
171
|
+
package_manager: "npm",
|
|
172
|
+
setup_command: "npm install",
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
// Go
|
|
176
|
+
if (existsSync(join(skillPath, "go.mod"))) {
|
|
177
|
+
return {
|
|
178
|
+
language: "go",
|
|
179
|
+
package_manager: "go mod",
|
|
180
|
+
setup_command: "go mod download",
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
// Pure skill (no runtime dependencies)
|
|
184
|
+
return { language: "markdown-only" };
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Load a specific file from within a skill directory.
|
|
188
|
+
*/
|
|
189
|
+
async loadSkillFile(entry, filePath) {
|
|
190
|
+
if (this.config.isRemote) {
|
|
191
|
+
await ensureSkillFetched(this.config, entry);
|
|
192
|
+
}
|
|
193
|
+
const skillPath = this.resolveSkillPath(entry);
|
|
194
|
+
const fullPath = resolve(skillPath, filePath);
|
|
195
|
+
// Security: ensure the resolved path is within the skill directory
|
|
196
|
+
if (!fullPath.startsWith(skillPath)) {
|
|
197
|
+
throw new Error("Path traversal detected: file must be within skill directory");
|
|
198
|
+
}
|
|
199
|
+
if (!existsSync(fullPath)) {
|
|
200
|
+
throw new Error(`File not found: ${filePath}`);
|
|
201
|
+
}
|
|
202
|
+
const stat = statSync(fullPath);
|
|
203
|
+
if (stat.isDirectory()) {
|
|
204
|
+
throw new Error(`Path is a directory, not a file: ${filePath}`);
|
|
205
|
+
}
|
|
206
|
+
if (stat.size > MAX_FILE_SIZE) {
|
|
207
|
+
throw new Error(`File too large (${Math.round(stat.size / 1024)}KB). Max: ${MAX_FILE_SIZE / 1024}KB`);
|
|
208
|
+
}
|
|
209
|
+
// Check if binary
|
|
210
|
+
const ext = extname(fullPath).toLowerCase();
|
|
211
|
+
const binaryExts = new Set([
|
|
212
|
+
".png", ".jpg", ".jpeg", ".gif", ".ico", ".webp",
|
|
213
|
+
".woff", ".woff2", ".ttf", ".eot",
|
|
214
|
+
".zip", ".7z", ".tar", ".gz",
|
|
215
|
+
".exe", ".dll", ".so", ".dylib",
|
|
216
|
+
".pdf", ".doc", ".docx",
|
|
217
|
+
]);
|
|
218
|
+
if (binaryExts.has(ext)) {
|
|
219
|
+
return {
|
|
220
|
+
content: `[Binary file: ${filePath} (${stat.size} bytes)]`,
|
|
221
|
+
size_bytes: stat.size,
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
const content = readFileSync(fullPath, "utf-8");
|
|
225
|
+
return { content, size_bytes: stat.size };
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* List files in a subdirectory of a skill.
|
|
229
|
+
*/
|
|
230
|
+
async listSkillFiles(entry, subPath = "", maxDepth = 2) {
|
|
231
|
+
if (this.config.isRemote) {
|
|
232
|
+
await ensureSkillFetched(this.config, entry);
|
|
233
|
+
}
|
|
234
|
+
const skillPath = this.resolveSkillPath(entry);
|
|
235
|
+
const targetPath = subPath ? resolve(skillPath, subPath) : skillPath;
|
|
236
|
+
// Security check
|
|
237
|
+
if (!targetPath.startsWith(skillPath)) {
|
|
238
|
+
throw new Error("Path traversal detected");
|
|
239
|
+
}
|
|
240
|
+
if (!existsSync(targetPath)) {
|
|
241
|
+
throw new Error(`Path not found: ${subPath || "."}`);
|
|
242
|
+
}
|
|
243
|
+
return this.scanDirectory(targetPath, 0, maxDepth);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/loader/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAC1E,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAE7D,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAgCzD,6CAA6C;AAC7C,MAAM,UAAU,GAAG,IAAI,GAAG,CAAC;IACzB,cAAc,EAAE,MAAM,EAAE,SAAS,EAAE,aAAa;IAChD,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;IACpC,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ;CACnC,CAAC,CAAC;AAEH,sDAAsD;AACtD,MAAM,aAAa,GAAG,GAAG,GAAG,IAAI,CAAC;AAEjC;;GAEG;AACH,MAAM,OAAO,WAAW;IAIZ;IACA;IAJF,SAAS,CAAS;IAE1B,YACU,MAAc,EACd,QAAyB;QADzB,WAAM,GAAN,MAAM,CAAQ;QACd,aAAQ,GAAR,QAAQ,CAAiB;QAEjC,IAAI,CAAC,SAAS,GAAG,MAAM,CAAC,SAAS,CAAC;IACpC,CAAC;IAED;;OAEG;IACH,gBAAgB,CAAC,KAAoB;QACnC,qEAAqE;QACrE,MAAM,OAAO,GAAG,KAAK,CAAC,aAAa,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;QACzD,OAAO,OAAO,CAAC,IAAI,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;IAC1C,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,SAAS,CAAC,KAAoB;QAClC,IAAI,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC;YACzB,MAAM,kBAAkB,CAAC,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;QAC/C,CAAC;QAED,MAAM,SAAS,GAAG,IAAI,CAAC,gBAAgB,CAAC,KAAK,CAAC,CAAC;QAE/C,gBAAgB;QAChB,IAAI,YAAY,GAAG,EAAE,CAAC;QACtB,MAAM,WAAW,GAAG,IAAI,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC;QAChD,IAAI,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;YAC5B,YAAY,GAAG,YAAY,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;QACpD,CAAC;aAAM,CAAC;YACN,YAAY,GAAG,0BAA0B,KAAK,CAAC,IAAI,qBAAqB,KAAK,CAAC,WAAW,EAAE,CAAC;QAC9F,CAAC;QAED,iBAAiB;QACjB,MAAM,SAAS,GAAG,IAAI,CAAC,aAAa,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;QAEvD,sBAAsB;QACtB,MAAM,YAAY,GAAG,IAAI,CAAC,kBAAkB,CAAC,SAAS,CAAC,CAAC;QAExD,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,YAAY,EAAE,CAAC;IACnD,CAAC;IAED;;OAEG;IACH,aAAa,CACX,OAAe,EACf,KAAoB,EACpB,WAAmB,CAAC;QAEpB,MAAM,KAAK,GAAG,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE,CAAC,EAAE,QAAQ,CAAC,CAAC;QAEvD,kDAAkD;QAClD,MAAM,SAAS,GAAmB,EAAE,CAAC;QACrC,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE,OAAO,EAAE,SAAS,CAAC,CAAC;QAEhD,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,CAAC;IAC1C,CAAC;IAEO,aAAa,CACnB,OAAe,EACf,YAAoB,EACpB,QAAgB;QAEhB,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC;YAAE,OAAO,EAAE,CAAC;QAEpC,MAAM,KAAK,GAAe,EAAE,CAAC;QAE7B,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,WAAW,CAAC,OAAO,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;YAE9D,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;gBAC5B,IAAI,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC;oBAAE,SAAS;gBACzC,IAAI,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,KAAK,CAAC,IAAI,KAAK,cAAc;oBAAE,SAAS;gBAE1E,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;gBAE3C,IAAI,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC;oBACxB,MAAM,IAAI,GAAa;wBACrB,IAAI,EAAE,KAAK,CAAC,IAAI;wBAChB,IAAI,EAAE,WAAW;qBAClB,CAAC;oBACF,IAAI,YAAY,GAAG,QAAQ,EAAE,CAAC;wBAC5B,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,aAAa,CAAC,QAAQ,EAAE,YAAY,GAAG,CAAC,EAAE,QAAQ,CAAC,CAAC;oBAC3E,CAAC;oBACD,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBACnB,CAAC;qBAAM,IAAI,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC;oBAC1B,IAAI,CAAC;wBACH,MAAM,IAAI,GAAG,QAAQ,CAAC,QAAQ,CAAC,CAAC;wBAChC,KAAK,CAAC,IAAI,CAAC;4BACT,IAAI,EAAE,KAAK,CAAC,IAAI;4BAChB,IAAI,EAAE,MAAM;4BACZ,UAAU,EAAE,IAAI,CAAC,IAAI;yBACtB,CAAC,CAAC;oBACL,CAAC;oBAAC,MAAM,CAAC;wBACP,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC;oBACjD,CAAC;gBACH,CAAC;YACH,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,oCAAoC;QACtC,CAAC;QAED,OAAO,KAAK,CAAC;IACf,CAAC;IAED;;OAEG;IACK,aAAa,CACnB,QAAgB,EAChB,WAAmB,EACnB,OAAuB,EACvB,QAAgB,CAAC;QAEjB,IAAI,KAAK,GAAG,CAAC;YAAE,OAAO;QAEtB,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,WAAW,CAAC,WAAW,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;YAElE,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;gBAC5B,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE;oBAAE,SAAS;gBACnC,IAAI,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC;oBAAE,SAAS;gBAEzC,MAAM,MAAM,GAAG,IAAI,CAAC,WAAW,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;gBAC7C,MAAM,UAAU,GAAG,IAAI,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;gBAE5C,IAAI,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;oBAC3B,mDAAmD;oBACnD,MAAM,OAAO,GAAG,YAAY,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;oBAClD,MAAM,SAAS,GAAG,OAAO,CAAC,KAAK,CAAC,6BAA6B,CAAC,CAAC;oBAC/D,MAAM,SAAS,GAAG,OAAO,CAAC,KAAK,CAAC,oCAAoC,CAAC,CAAC;oBAEtE,OAAO,CAAC,IAAI,CAAC;wBACX,IAAI,EAAE,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI;wBAClD,IAAI,EAAE,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;wBAChC,WAAW,EAAE,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE;qBAClD,CAAC,CAAC;gBACL,CAAC;gBAED,iBAAiB;gBACjB,IAAI,CAAC,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC;YAC3D,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,oBAAoB;QACtB,CAAC;IACH,CAAC;IAED;;OAEG;IACK,kBAAkB,CAAC,SAAiB;QAC1C,SAAS;QACT,IAAI,UAAU,CAAC,IAAI,CAAC,SAAS,EAAE,kBAAkB,CAAC,CAAC,EAAE,CAAC;YACpD,OAAO;gBACL,QAAQ,EAAE,QAAQ;gBAClB,eAAe,EAAE,KAAK;gBACtB,aAAa,EAAE,iCAAiC;aACjD,CAAC;QACJ,CAAC;QACD,IAAI,UAAU,CAAC,IAAI,CAAC,SAAS,EAAE,gBAAgB,CAAC,CAAC,EAAE,CAAC;YAClD,IAAI,UAAU,CAAC,IAAI,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC,EAAE,CAAC;gBAC3C,OAAO;oBACL,QAAQ,EAAE,QAAQ;oBAClB,eAAe,EAAE,IAAI;oBACrB,aAAa,EAAE,SAAS;iBACzB,CAAC;YACJ,CAAC;YACD,OAAO;gBACL,QAAQ,EAAE,QAAQ;gBAClB,eAAe,EAAE,KAAK;gBACtB,aAAa,EAAE,eAAe;aAC/B,CAAC;QACJ,CAAC;QAED,UAAU;QACV,IAAI,UAAU,CAAC,IAAI,CAAC,SAAS,EAAE,cAAc,CAAC,CAAC,EAAE,CAAC;YAChD,OAAO;gBACL,QAAQ,EAAE,uBAAuB;gBACjC,eAAe,EAAE,KAAK;gBACtB,aAAa,EAAE,aAAa;aAC7B,CAAC;QACJ,CAAC;QAED,KAAK;QACL,IAAI,UAAU,CAAC,IAAI,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC,EAAE,CAAC;YAC1C,OAAO;gBACL,QAAQ,EAAE,IAAI;gBACd,eAAe,EAAE,QAAQ;gBACzB,aAAa,EAAE,iBAAiB;aACjC,CAAC;QACJ,CAAC;QAED,uCAAuC;QACvC,OAAO,EAAE,QAAQ,EAAE,eAAe,EAAE,CAAC;IACvC,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,aAAa,CACjB,KAAoB,EACpB,QAAgB;QAEhB,IAAI,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC;YACzB,MAAM,kBAAkB,CAAC,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;QAC/C,CAAC;QAED,MAAM,SAAS,GAAG,IAAI,CAAC,gBAAgB,CAAC,KAAK,CAAC,CAAC;QAC/C,MAAM,QAAQ,GAAG,OAAO,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;QAE9C,mEAAmE;QACnE,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;YACpC,MAAM,IAAI,KAAK,CAAC,8DAA8D,CAAC,CAAC;QAClF,CAAC;QAED,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC1B,MAAM,IAAI,KAAK,CAAC,mBAAmB,QAAQ,EAAE,CAAC,CAAC;QACjD,CAAC;QAED,MAAM,IAAI,GAAG,QAAQ,CAAC,QAAQ,CAAC,CAAC;QAChC,IAAI,IAAI,CAAC,WAAW,EAAE,EAAE,CAAC;YACvB,MAAM,IAAI,KAAK,CAAC,oCAAoC,QAAQ,EAAE,CAAC,CAAC;QAClE,CAAC;QAED,IAAI,IAAI,CAAC,IAAI,GAAG,aAAa,EAAE,CAAC;YAC9B,MAAM,IAAI,KAAK,CACb,mBAAmB,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,aAAa,aAAa,GAAG,IAAI,IAAI,CACrF,CAAC;QACJ,CAAC;QAED,kBAAkB;QAClB,MAAM,GAAG,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC,WAAW,EAAE,CAAC;QAC5C,MAAM,UAAU,GAAG,IAAI,GAAG,CAAC;YACzB,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO;YAChD,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM;YACjC,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK;YAC5B,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ;YAC/B,MAAM,EAAE,MAAM,EAAE,OAAO;SACxB,CAAC,CAAC;QAEH,IAAI,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;YACxB,OAAO;gBACL,OAAO,EAAE,iBAAiB,QAAQ,KAAK,IAAI,CAAC,IAAI,UAAU;gBAC1D,UAAU,EAAE,IAAI,CAAC,IAAI;aACtB,CAAC;QACJ,CAAC;QAED,MAAM,OAAO,GAAG,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QAChD,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC;IAC5C,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,cAAc,CAClB,KAAoB,EACpB,UAAkB,EAAE,EACpB,WAAmB,CAAC;QAEpB,IAAI,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC;YACzB,MAAM,kBAAkB,CAAC,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;QAC/C,CAAC;QAED,MAAM,SAAS,GAAG,IAAI,CAAC,gBAAgB,CAAC,KAAK,CAAC,CAAC;QAC/C,MAAM,UAAU,GAAG,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QAErE,iBAAiB;QACjB,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;YACtC,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;QAC7C,CAAC;QAED,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;YAC5B,MAAM,IAAI,KAAK,CAAC,mBAAmB,OAAO,IAAI,GAAG,EAAE,CAAC,CAAC;QACvD,CAAC;QAED,OAAO,IAAI,CAAC,aAAa,CAAC,UAAU,EAAE,CAAC,EAAE,QAAQ,CAAC,CAAC;IACrD,CAAC;CACF"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Config, ManifestEntry } from "../config.js";
|
|
2
|
+
/**
|
|
3
|
+
* Initialize remote caching by fetching the repository tree
|
|
4
|
+
*/
|
|
5
|
+
export declare function initRemote(config: Config): Promise<void>;
|
|
6
|
+
/**
|
|
7
|
+
* Download the manifest file
|
|
8
|
+
*/
|
|
9
|
+
export declare function fetchManifest(config: Config): Promise<void>;
|
|
10
|
+
/**
|
|
11
|
+
* Ensure a skill's directory is downloaded and cached
|
|
12
|
+
*/
|
|
13
|
+
export declare function ensureSkillFetched(config: Config, entry: ManifestEntry): Promise<void>;
|
|
14
|
+
//# sourceMappingURL=github.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"github.d.ts","sourceRoot":"","sources":["../../src/remote/github.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAiC1D;;GAEG;AACH,wBAAsB,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAkB9D;AAED;;GAEG;AACH,wBAAsB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAUjE;AAED;;GAEG;AACH,wBAAsB,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAmD5F"}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { writeFileSync, existsSync, mkdirSync, readFileSync } from "node:fs";
|
|
2
|
+
import { resolve, dirname } from "node:path";
|
|
3
|
+
/**
|
|
4
|
+
* Fetch with optional auth token
|
|
5
|
+
*/
|
|
6
|
+
async function fetchWithAuth(url, token) {
|
|
7
|
+
const headers = {};
|
|
8
|
+
if (token) {
|
|
9
|
+
headers["Authorization"] = `Bearer ${token}`;
|
|
10
|
+
}
|
|
11
|
+
const res = await fetch(url, { headers });
|
|
12
|
+
if (!res.ok) {
|
|
13
|
+
throw new Error(`Failed to fetch ${url}: ${res.status} ${res.statusText}`);
|
|
14
|
+
}
|
|
15
|
+
return res;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Initialize remote caching by fetching the repository tree
|
|
19
|
+
*/
|
|
20
|
+
export async function initRemote(config) {
|
|
21
|
+
const treePath = resolve(config.skillsDir, "tree.json");
|
|
22
|
+
if (existsSync(treePath)) {
|
|
23
|
+
return; // Already initialized in this run
|
|
24
|
+
}
|
|
25
|
+
const url = `https://api.github.com/repos/${config.githubRepo}/git/trees/${config.githubBranch}?recursive=1`;
|
|
26
|
+
console.error(`[codex-skills-mcp] Fetching repo tree from ${url}...`);
|
|
27
|
+
const res = await fetchWithAuth(url, config.githubToken);
|
|
28
|
+
const data = (await res.json());
|
|
29
|
+
if (data.truncated) {
|
|
30
|
+
console.error("[codex-skills-mcp] Warning: GitHub tree is truncated, some files may be missing.");
|
|
31
|
+
}
|
|
32
|
+
writeFileSync(treePath, JSON.stringify(data.tree, null, 2), "utf-8");
|
|
33
|
+
console.error(`[codex-skills-mcp] Cached ${data.tree.length} tree items.`);
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Download the manifest file
|
|
37
|
+
*/
|
|
38
|
+
export async function fetchManifest(config) {
|
|
39
|
+
if (existsSync(config.manifestPath))
|
|
40
|
+
return;
|
|
41
|
+
const rawUrl = `https://raw.githubusercontent.com/${config.githubRepo}/${config.githubBranch}/${config.githubPath}/skills_manifest.json`;
|
|
42
|
+
console.error(`[codex-skills-mcp] Fetching manifest from ${rawUrl}...`);
|
|
43
|
+
const res = await fetchWithAuth(rawUrl, config.githubToken);
|
|
44
|
+
const text = await res.text();
|
|
45
|
+
writeFileSync(config.manifestPath, text, "utf-8");
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Ensure a skill's directory is downloaded and cached
|
|
49
|
+
*/
|
|
50
|
+
export async function ensureSkillFetched(config, entry) {
|
|
51
|
+
const relPath = entry.relative_path.replace(/^\.\//, "");
|
|
52
|
+
const skillLocalPath = resolve(config.skillsDir, relPath);
|
|
53
|
+
if (existsSync(skillLocalPath)) {
|
|
54
|
+
return; // Already fetched
|
|
55
|
+
}
|
|
56
|
+
const treePath = resolve(config.skillsDir, "tree.json");
|
|
57
|
+
if (!existsSync(treePath)) {
|
|
58
|
+
throw new Error("Tree cache not found, run initRemote first.");
|
|
59
|
+
}
|
|
60
|
+
const tree = JSON.parse(readFileSync(treePath, "utf-8"));
|
|
61
|
+
// The prefix in github is githubPath + relPath
|
|
62
|
+
// e.g. "codex-skills/01_代码工程与架构/planning-with-files"
|
|
63
|
+
let prefix = config.githubPath ? `${config.githubPath}/${relPath}` : relPath;
|
|
64
|
+
if (prefix.startsWith("/"))
|
|
65
|
+
prefix = prefix.slice(1);
|
|
66
|
+
if (prefix.startsWith("./"))
|
|
67
|
+
prefix = prefix.slice(2);
|
|
68
|
+
const filesToFetch = tree.filter((item) => item.type === "blob" && item.path.startsWith(prefix + "/"));
|
|
69
|
+
if (filesToFetch.length === 0) {
|
|
70
|
+
console.error(`[codex-skills-mcp] Warning: No files found in remote tree for prefix ${prefix}`);
|
|
71
|
+
// Create an empty dir to prevent repeated failures
|
|
72
|
+
mkdirSync(skillLocalPath, { recursive: true });
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
console.error(`[codex-skills-mcp] Fetching ${filesToFetch.length} files for skill: ${entry.name}...`);
|
|
76
|
+
for (const file of filesToFetch) {
|
|
77
|
+
const rawUrl = `https://raw.githubusercontent.com/${config.githubRepo}/${config.githubBranch}/${file.path}`;
|
|
78
|
+
// Determine local path by stripping githubPath prefix
|
|
79
|
+
let relativeFilePath = file.path;
|
|
80
|
+
if (config.githubPath && relativeFilePath.startsWith(config.githubPath + "/")) {
|
|
81
|
+
relativeFilePath = relativeFilePath.substring(config.githubPath.length + 1);
|
|
82
|
+
}
|
|
83
|
+
const localFilePath = resolve(config.skillsDir, relativeFilePath);
|
|
84
|
+
mkdirSync(dirname(localFilePath), { recursive: true });
|
|
85
|
+
const res = await fetchWithAuth(rawUrl, config.githubToken);
|
|
86
|
+
const buffer = await res.arrayBuffer();
|
|
87
|
+
writeFileSync(localFilePath, Buffer.from(buffer));
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
//# sourceMappingURL=github.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"github.js","sourceRoot":"","sources":["../../src/remote/github.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { ManifestEntry } from "../config.js";
|
|
2
|
+
interface SearchResult {
|
|
3
|
+
name: string;
|
|
4
|
+
description: string;
|
|
5
|
+
category: string;
|
|
6
|
+
has_sub_skills: boolean;
|
|
7
|
+
score: number;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Lightweight keyword search engine with TF-IDF-like scoring.
|
|
11
|
+
* No external dependencies — pure string matching with Leading Words boosting.
|
|
12
|
+
*/
|
|
13
|
+
export declare class SkillSearchEngine {
|
|
14
|
+
private index;
|
|
15
|
+
private categories;
|
|
16
|
+
constructor(manifest: ManifestEntry[]);
|
|
17
|
+
private buildIndex;
|
|
18
|
+
/**
|
|
19
|
+
* Extract Leading Words from description.
|
|
20
|
+
* Format: "...。Leading Words: word1, word2, word3"
|
|
21
|
+
*/
|
|
22
|
+
private extractLeadingWords;
|
|
23
|
+
private tokenize;
|
|
24
|
+
/**
|
|
25
|
+
* Search skills by query string.
|
|
26
|
+
* Scoring: exact name match > Leading Words match > description token match
|
|
27
|
+
*/
|
|
28
|
+
search(query: string, options?: {
|
|
29
|
+
category?: string;
|
|
30
|
+
limit?: number;
|
|
31
|
+
}): SearchResult[];
|
|
32
|
+
/**
|
|
33
|
+
* Get all categories with skill counts.
|
|
34
|
+
*/
|
|
35
|
+
getCategories(): {
|
|
36
|
+
name: string;
|
|
37
|
+
skill_count: number;
|
|
38
|
+
}[];
|
|
39
|
+
/**
|
|
40
|
+
* Find a skill entry by exact name.
|
|
41
|
+
*/
|
|
42
|
+
findByName(name: string): ManifestEntry | undefined;
|
|
43
|
+
}
|
|
44
|
+
export {};
|
|
45
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/search/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAElD,UAAU,YAAY;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,EAAE,OAAO,CAAC;IACxB,KAAK,EAAE,MAAM,CAAC;CACf;AASD;;;GAGG;AACH,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,KAAK,CAAoB;IACjC,OAAO,CAAC,UAAU,CAAkC;gBAExC,QAAQ,EAAE,aAAa,EAAE;IAIrC,OAAO,CAAC,UAAU;IAiClB;;;OAGG;IACH,OAAO,CAAC,mBAAmB;IAS3B,OAAO,CAAC,QAAQ;IA2BhB;;;OAGG;IACH,MAAM,CACJ,KAAK,EAAE,MAAM,EACb,OAAO,GAAE;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAO,GAClD,YAAY,EAAE;IAiEjB;;OAEG;IACH,aAAa,IAAI;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,EAAE;IAMxD;;OAEG;IACH,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS;CAMpD"}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lightweight keyword search engine with TF-IDF-like scoring.
|
|
3
|
+
* No external dependencies — pure string matching with Leading Words boosting.
|
|
4
|
+
*/
|
|
5
|
+
export class SkillSearchEngine {
|
|
6
|
+
index = [];
|
|
7
|
+
categories = new Map();
|
|
8
|
+
constructor(manifest) {
|
|
9
|
+
this.buildIndex(manifest);
|
|
10
|
+
}
|
|
11
|
+
buildIndex(manifest) {
|
|
12
|
+
const categoryCounts = new Map();
|
|
13
|
+
for (const entry of manifest) {
|
|
14
|
+
// Skip the router entry itself
|
|
15
|
+
if (entry.name === "00_codex_skills")
|
|
16
|
+
continue;
|
|
17
|
+
// Extract Leading Words from description
|
|
18
|
+
const leadingWords = this.extractLeadingWords(entry.description);
|
|
19
|
+
// Tokenize all searchable fields
|
|
20
|
+
const allText = [
|
|
21
|
+
entry.name,
|
|
22
|
+
entry.description,
|
|
23
|
+
entry.category,
|
|
24
|
+
entry.folder,
|
|
25
|
+
].join(" ");
|
|
26
|
+
const tokens = this.tokenize(allText);
|
|
27
|
+
// Detect if this is a sub-skill (path depth > 2 segments)
|
|
28
|
+
const pathSegments = entry.relative_path.split("/").filter(Boolean);
|
|
29
|
+
const isSubSkill = pathSegments.length > 3;
|
|
30
|
+
this.index.push({ entry, tokens, leadingWords, isSubSkill });
|
|
31
|
+
// Count categories
|
|
32
|
+
const count = categoryCounts.get(entry.category) || 0;
|
|
33
|
+
categoryCounts.set(entry.category, count + 1);
|
|
34
|
+
}
|
|
35
|
+
this.categories = categoryCounts;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Extract Leading Words from description.
|
|
39
|
+
* Format: "...。Leading Words: word1, word2, word3"
|
|
40
|
+
*/
|
|
41
|
+
extractLeadingWords(description) {
|
|
42
|
+
const match = description.match(/Leading\s*Words?\s*[::]\s*(.+)$/i);
|
|
43
|
+
if (!match)
|
|
44
|
+
return [];
|
|
45
|
+
return match[1]
|
|
46
|
+
.split(/[,,、]/)
|
|
47
|
+
.map((w) => w.trim().toLowerCase())
|
|
48
|
+
.filter(Boolean);
|
|
49
|
+
}
|
|
50
|
+
tokenize(text) {
|
|
51
|
+
const raw = text
|
|
52
|
+
.toLowerCase()
|
|
53
|
+
.replace(/[^\w\u4e00-\u9fff\s-]/g, " ")
|
|
54
|
+
.split(/\s+/)
|
|
55
|
+
.filter((t) => t.length > 1);
|
|
56
|
+
// Generate CJK bigrams for better Chinese matching
|
|
57
|
+
const result = [...raw];
|
|
58
|
+
for (const token of raw) {
|
|
59
|
+
const cjkChars = token.match(/[\u4e00-\u9fff]/g);
|
|
60
|
+
if (cjkChars && cjkChars.length >= 2) {
|
|
61
|
+
// Generate bigrams: "前端性能" → ["前端", "端性", "性能"]
|
|
62
|
+
const cjkStr = cjkChars.join("");
|
|
63
|
+
for (let i = 0; i < cjkStr.length - 1; i++) {
|
|
64
|
+
result.push(cjkStr.substring(i, i + 2));
|
|
65
|
+
}
|
|
66
|
+
// Also add individual chars for broader matching
|
|
67
|
+
for (const c of cjkChars) {
|
|
68
|
+
result.push(c);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return result;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Search skills by query string.
|
|
76
|
+
* Scoring: exact name match > Leading Words match > description token match
|
|
77
|
+
*/
|
|
78
|
+
search(query, options = {}) {
|
|
79
|
+
const { category, limit = 10 } = options;
|
|
80
|
+
const queryTokens = this.tokenize(query);
|
|
81
|
+
if (queryTokens.length === 0)
|
|
82
|
+
return [];
|
|
83
|
+
const results = [];
|
|
84
|
+
for (const item of this.index) {
|
|
85
|
+
// Category filter
|
|
86
|
+
if (category && item.entry.category !== category)
|
|
87
|
+
continue;
|
|
88
|
+
let score = 0;
|
|
89
|
+
// 1. Exact name match (highest priority)
|
|
90
|
+
const nameLower = item.entry.name.toLowerCase();
|
|
91
|
+
for (const qt of queryTokens) {
|
|
92
|
+
if (nameLower === qt || nameLower.includes(qt)) {
|
|
93
|
+
score += 10;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
// 2. Leading Words match (high priority)
|
|
97
|
+
for (const qt of queryTokens) {
|
|
98
|
+
for (const lw of item.leadingWords) {
|
|
99
|
+
if (lw.includes(qt) || qt.includes(lw)) {
|
|
100
|
+
score += 5;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
// 3. General token match
|
|
105
|
+
for (const qt of queryTokens) {
|
|
106
|
+
let tokenHits = 0;
|
|
107
|
+
for (const token of item.tokens) {
|
|
108
|
+
if (token.includes(qt) || qt.includes(token)) {
|
|
109
|
+
tokenHits++;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
// Normalize by token count to avoid long descriptions always winning
|
|
113
|
+
score += tokenHits > 0 ? 1 + Math.log(tokenHits) : 0;
|
|
114
|
+
}
|
|
115
|
+
// 4. Sub-skills get a slight penalty to prefer top-level skills
|
|
116
|
+
if (item.isSubSkill) {
|
|
117
|
+
score *= 0.7;
|
|
118
|
+
}
|
|
119
|
+
if (score > 0) {
|
|
120
|
+
results.push({
|
|
121
|
+
name: item.entry.name,
|
|
122
|
+
description: item.entry.description,
|
|
123
|
+
category: item.entry.category,
|
|
124
|
+
has_sub_skills: false, // Will be enriched by loader
|
|
125
|
+
score: Math.round(score * 100) / 100,
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
// Sort by score descending
|
|
130
|
+
results.sort((a, b) => b.score - a.score);
|
|
131
|
+
return results.slice(0, limit);
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Get all categories with skill counts.
|
|
135
|
+
*/
|
|
136
|
+
getCategories() {
|
|
137
|
+
return Array.from(this.categories.entries())
|
|
138
|
+
.map(([name, skill_count]) => ({ name, skill_count }))
|
|
139
|
+
.sort((a, b) => a.name.localeCompare(b.name));
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Find a skill entry by exact name.
|
|
143
|
+
*/
|
|
144
|
+
findByName(name) {
|
|
145
|
+
const nameLower = name.toLowerCase();
|
|
146
|
+
return this.index.find((item) => item.entry.name.toLowerCase() === nameLower)?.entry;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/search/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import type { SkillSearchEngine } from "../search/index.js";
|
|
3
|
+
export declare function registerListCategories(server: McpServer, searchEngine: SkillSearchEngine): void;
|
|
4
|
+
//# sourceMappingURL=list-categories.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list-categories.d.ts","sourceRoot":"","sources":["../../src/tools/list-categories.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAE5D,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,SAAS,EACjB,YAAY,EAAE,iBAAiB,GAC9B,IAAI,CAwBN"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export function registerListCategories(server, searchEngine) {
|
|
2
|
+
server.tool("list_categories", "List all skill categories in the codex-skills library with their skill counts. Use this to get an overview of available domains.", {}, async () => {
|
|
3
|
+
const categories = searchEngine.getCategories();
|
|
4
|
+
const formatted = categories
|
|
5
|
+
.map((c) => `- **${c.name}**: ${c.skill_count} skills`)
|
|
6
|
+
.join("\n");
|
|
7
|
+
const total = categories.reduce((sum, c) => sum + c.skill_count, 0);
|
|
8
|
+
return {
|
|
9
|
+
content: [
|
|
10
|
+
{
|
|
11
|
+
type: "text",
|
|
12
|
+
text: `Codex-Skills Library: ${total} skills across ${categories.length} categories\n\n${formatted}\n\nUse search_skills(query) to find skills, or search_skills(query, category) to filter by category.`,
|
|
13
|
+
},
|
|
14
|
+
],
|
|
15
|
+
};
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=list-categories.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list-categories.js","sourceRoot":"","sources":["../../src/tools/list-categories.ts"],"names":[],"mappings":"AAGA,MAAM,UAAU,sBAAsB,CACpC,MAAiB,EACjB,YAA+B;IAE/B,MAAM,CAAC,IAAI,CACT,iBAAiB,EACjB,kIAAkI,EAClI,EAAE,EACF,KAAK,IAAI,EAAE;QACT,MAAM,UAAU,GAAG,YAAY,CAAC,aAAa,EAAE,CAAC;QAEhD,MAAM,SAAS,GAAG,UAAU;aACzB,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC,IAAI,OAAO,CAAC,CAAC,WAAW,SAAS,CAAC;aACtD,IAAI,CAAC,IAAI,CAAC,CAAC;QAEd,MAAM,KAAK,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;QAEpE,OAAO;YACL,OAAO,EAAE;gBACP;oBACE,IAAI,EAAE,MAAe;oBACrB,IAAI,EAAE,yBAAyB,KAAK,kBAAkB,UAAU,CAAC,MAAM,kBAAkB,SAAS,uGAAuG;iBAC1M;aACF;SACF,CAAC;IACJ,CAAC,CACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import type { SkillSearchEngine } from "../search/index.js";
|
|
3
|
+
import type { SkillLoader } from "../loader/index.js";
|
|
4
|
+
export declare function registerListSkillFiles(server: McpServer, searchEngine: SkillSearchEngine, loader: SkillLoader): void;
|
|
5
|
+
//# sourceMappingURL=list-skill-files.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list-skill-files.d.ts","sourceRoot":"","sources":["../../src/tools/list-skill-files.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAC5D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEtD,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,SAAS,EACjB,YAAY,EAAE,iBAAiB,EAC/B,MAAM,EAAE,WAAW,GAClB,IAAI,CA8CN"}
|