@templmf/temp-solf-lmf 0.0.43 → 0.0.45
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/ai-gateway/.env +42 -0
- package/ai-gateway/README.md +295 -0
- package/ai-gateway/package-lock.json +1370 -0
- package/ai-gateway/package.json +18 -0
- package/ai-gateway/src/index.js +132 -0
- package/ai-gateway/src/middleware/auth.js +45 -0
- package/ai-gateway/src/middleware/rateLimit.js +87 -0
- package/ai-gateway/src/routes/chat.js +657 -0
- package/ai-gateway/src/skills/detector.js +145 -0
- package/ai-gateway/src/skills/html.md +18 -0
- package/ai-gateway/src/skills/markdown.md +18 -0
- package/ai-gateway/src/skills/react.md +27 -0
- package/ai-gateway/src/skills/registry.js +441 -0
- package/ai-gateway/src/skills/skill-creator/LICENSE.txt +202 -0
- package/ai-gateway/src/skills/skill-creator/SKILL.md +485 -0
- package/ai-gateway/src/skills/skill-creator/agents/analyzer.md +274 -0
- package/ai-gateway/src/skills/skill-creator/agents/comparator.md +202 -0
- package/ai-gateway/src/skills/skill-creator/agents/grader.md +223 -0
- package/ai-gateway/src/skills/skill-creator/assets/eval_review.html +146 -0
- package/ai-gateway/src/skills/skill-creator/eval-viewer/generate_review.py +471 -0
- package/ai-gateway/src/skills/skill-creator/eval-viewer/viewer.html +1325 -0
- package/ai-gateway/src/skills/skill-creator/references/schemas.md +430 -0
- package/ai-gateway/src/skills/skill-creator/scripts/__init__.py +0 -0
- package/ai-gateway/src/skills/skill-creator/scripts/aggregate_benchmark.py +401 -0
- package/ai-gateway/src/skills/skill-creator/scripts/generate_report.py +326 -0
- package/ai-gateway/src/skills/skill-creator/scripts/improve_description.py +247 -0
- package/ai-gateway/src/skills/skill-creator/scripts/package_skill.py +136 -0
- package/ai-gateway/src/skills/skill-creator/scripts/quick_validate.py +103 -0
- package/ai-gateway/src/skills/skill-creator/scripts/run_eval.py +310 -0
- package/ai-gateway/src/skills/skill-creator/scripts/run_loop.py +328 -0
- package/ai-gateway/src/skills/skill-creator/scripts/utils.py +47 -0
- package/ai-gateway/src/skills/skill-creator/skill-creator.skill +0 -0
- package/ai-gateway/src/skills/ticket.md +36 -0
- package/ai-gateway/src/skills/vue.md +31 -0
- package/ai-gateway/src/utils/logger.js +21 -0
- package/ai-gateway/src/utils/retry.js +90 -0
- package/ai-gateway/src/utils/sessionManager.js +159 -0
- package/ai-gateway/src/utils/structuredResponse.js +144 -0
- package/ai-gateway/src/utils/toolAdapter.js +151 -0
- package/package.json +1 -1
- package//345/216/213/347/274/251/345/220/216/347/232/204/346/226/207/344/273/266.7z +0 -0
- package/skill-mcp/README.md +0 -74
- package/skill-mcp/index.ts +0 -336
- package/skill-mcp/package (1).json +0 -19
- package/skill-mcp/tsconfig.json +0 -16
- package//347/247/273/345/212/250/345/272/224/347/224/250/345/217/260/350/264/246/347/247/273/344/272/244/346/270/205/345/215/225.xlsx +0 -0
package/skill-mcp/index.ts
DELETED
|
@@ -1,336 +0,0 @@
|
|
|
1
|
-
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
-
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
3
|
-
import * as fs from "fs";
|
|
4
|
-
import * as path from "path";
|
|
5
|
-
import * as os from "os";
|
|
6
|
-
import matter from "gray-matter";
|
|
7
|
-
import { z } from "zod";
|
|
8
|
-
|
|
9
|
-
// ──────────────────────────────────────────────
|
|
10
|
-
// 路径解析:支持项目级 + 全局两个 Skills 目录
|
|
11
|
-
// ──────────────────────────────────────────────
|
|
12
|
-
|
|
13
|
-
function getSkillDirs(): string[] {
|
|
14
|
-
const dirs: string[] = [];
|
|
15
|
-
|
|
16
|
-
// 全局路径:~/.roo/skills(Linux/macOS)或 %USERPROFILE%\.roo\skills(Windows)
|
|
17
|
-
const globalDir = path.join(os.homedir(), ".roo", "skills");
|
|
18
|
-
if (fs.existsSync(globalDir)) dirs.push(globalDir);
|
|
19
|
-
|
|
20
|
-
// 项目路径:cwd()/.roo/skills
|
|
21
|
-
const projectDir = path.join(process.cwd(), ".roo", "skills");
|
|
22
|
-
if (fs.existsSync(projectDir) && projectDir !== globalDir) {
|
|
23
|
-
dirs.push(projectDir);
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
// 支持通过环境变量追加自定义路径,多个路径用分号分隔
|
|
27
|
-
if (process.env.SKILLS_EXTRA_DIRS) {
|
|
28
|
-
for (const d of process.env.SKILLS_EXTRA_DIRS.split(";")) {
|
|
29
|
-
const trimmed = d.trim();
|
|
30
|
-
if (trimmed && fs.existsSync(trimmed) && !dirs.includes(trimmed)) {
|
|
31
|
-
dirs.push(trimmed);
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
return dirs;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
// ──────────────────────────────────────────────
|
|
40
|
-
// Skill 数据结构
|
|
41
|
-
// ──────────────────────────────────────────────
|
|
42
|
-
|
|
43
|
-
interface SkillMeta {
|
|
44
|
-
name: string;
|
|
45
|
-
description: string;
|
|
46
|
-
skillDir: string; // SKILL.md 所在文件夹
|
|
47
|
-
skillFile: string; // SKILL.md 完整路径
|
|
48
|
-
source: string; // "global" | "project" | 自定义路径标签
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
// ──────────────────────────────────────────────
|
|
52
|
-
// 核心:扫描所有 Skills(用于 list / search)
|
|
53
|
-
// ──────────────────────────────────────────────
|
|
54
|
-
|
|
55
|
-
function scanSkills(): SkillMeta[] {
|
|
56
|
-
const skillDirs = getSkillDirs();
|
|
57
|
-
const skillMap = new Map<string, SkillMeta>(); // name → meta,项目级覆盖全局
|
|
58
|
-
|
|
59
|
-
for (const baseDir of skillDirs) {
|
|
60
|
-
const source = resolveSource(baseDir);
|
|
61
|
-
if (!fs.existsSync(baseDir)) continue;
|
|
62
|
-
|
|
63
|
-
for (const entry of fs.readdirSync(baseDir, { withFileTypes: true })) {
|
|
64
|
-
if (!entry.isDirectory()) continue;
|
|
65
|
-
|
|
66
|
-
const skillDir = path.join(baseDir, entry.name);
|
|
67
|
-
const skillFile = path.join(skillDir, "SKILL.md");
|
|
68
|
-
if (!fs.existsSync(skillFile)) continue;
|
|
69
|
-
|
|
70
|
-
try {
|
|
71
|
-
const { data } = matter(fs.readFileSync(skillFile, "utf-8"));
|
|
72
|
-
const name = (data.name as string | undefined)?.trim() ?? entry.name;
|
|
73
|
-
const description = (data.description as string | undefined)?.trim() ?? "";
|
|
74
|
-
// 项目级 > 全局(后扫描的覆盖先扫描的)
|
|
75
|
-
skillMap.set(name, { name, description, skillDir, skillFile, source });
|
|
76
|
-
} catch {
|
|
77
|
-
// 解析失败跳过
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
return Array.from(skillMap.values()).sort((a, b) => a.name.localeCompare(b.name));
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
// ──────────────────────────────────────────────
|
|
86
|
-
// 直接按名称查找 Skill(无需全量扫描)
|
|
87
|
-
// 优先级:project > global > custom
|
|
88
|
-
// ──────────────────────────────────────────────
|
|
89
|
-
|
|
90
|
-
function findSkillByName(skillName: string): SkillMeta | null {
|
|
91
|
-
const skillDirs = getSkillDirs();
|
|
92
|
-
|
|
93
|
-
// 倒序遍历使项目级优先(skillDirs 里项目在后)
|
|
94
|
-
for (const baseDir of [...skillDirs].reverse()) {
|
|
95
|
-
if (!fs.existsSync(baseDir)) continue;
|
|
96
|
-
|
|
97
|
-
// 先尝试以 skillName 作为目录名直接定位
|
|
98
|
-
const directDir = path.join(baseDir, skillName);
|
|
99
|
-
const directFile = path.join(directDir, "SKILL.md");
|
|
100
|
-
if (fs.existsSync(directFile)) {
|
|
101
|
-
try {
|
|
102
|
-
const { data } = matter(fs.readFileSync(directFile, "utf-8"));
|
|
103
|
-
const name = (data.name as string | undefined)?.trim() ?? skillName;
|
|
104
|
-
const description = (data.description as string | undefined)?.trim() ?? "";
|
|
105
|
-
return { name, description, skillDir: directDir, skillFile: directFile, source: resolveSource(baseDir) };
|
|
106
|
-
} catch {
|
|
107
|
-
// 继续尝试其他路径
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
// 若目录名不匹配,遍历子目录对比 frontmatter name
|
|
112
|
-
for (const entry of fs.readdirSync(baseDir, { withFileTypes: true })) {
|
|
113
|
-
if (!entry.isDirectory()) continue;
|
|
114
|
-
const skillDir = path.join(baseDir, entry.name);
|
|
115
|
-
const skillFile = path.join(skillDir, "SKILL.md");
|
|
116
|
-
if (!fs.existsSync(skillFile)) continue;
|
|
117
|
-
|
|
118
|
-
try {
|
|
119
|
-
const { data } = matter(fs.readFileSync(skillFile, "utf-8"));
|
|
120
|
-
const name = (data.name as string | undefined)?.trim() ?? entry.name;
|
|
121
|
-
if (name === skillName) {
|
|
122
|
-
const description = (data.description as string | undefined)?.trim() ?? "";
|
|
123
|
-
return { name, description, skillDir, skillFile, source: resolveSource(baseDir) };
|
|
124
|
-
}
|
|
125
|
-
} catch {
|
|
126
|
-
// 跳过
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
return null;
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
// ──────────────────────────────────────────────
|
|
135
|
-
// 工具函数
|
|
136
|
-
// ──────────────────────────────────────────────
|
|
137
|
-
|
|
138
|
-
function resolveSource(baseDir: string): string {
|
|
139
|
-
if (baseDir === path.join(os.homedir(), ".roo", "skills")) return "global";
|
|
140
|
-
if (baseDir === path.join(process.cwd(), ".roo", "skills")) return "project";
|
|
141
|
-
return "custom";
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
/** 列出所有文件(含子目录),返回相对路径列表 */
|
|
145
|
-
function listFilesRecursive(dir: string, base: string = dir): string[] {
|
|
146
|
-
const result: string[] = [];
|
|
147
|
-
if (!fs.existsSync(dir)) return result;
|
|
148
|
-
|
|
149
|
-
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
150
|
-
const full = path.join(dir, entry.name);
|
|
151
|
-
if (entry.isDirectory()) {
|
|
152
|
-
result.push(...listFilesRecursive(full, base));
|
|
153
|
-
} else {
|
|
154
|
-
result.push(path.relative(base, full));
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
return result;
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
/** 模糊匹配:检查 haystack 是否包含 needle 的所有字符(按序) */
|
|
161
|
-
function fuzzyMatch(needle: string, haystack: string): boolean {
|
|
162
|
-
needle = needle.toLowerCase();
|
|
163
|
-
haystack = haystack.toLowerCase();
|
|
164
|
-
let i = 0;
|
|
165
|
-
for (const ch of haystack) {
|
|
166
|
-
if (ch === needle[i]) i++;
|
|
167
|
-
if (i === needle.length) return true;
|
|
168
|
-
}
|
|
169
|
-
return false;
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
// ──────────────────────────────────────────────
|
|
173
|
-
// MCP Server
|
|
174
|
-
// ──────────────────────────────────────────────
|
|
175
|
-
|
|
176
|
-
const server = new McpServer({
|
|
177
|
-
name: "skills-mcp",
|
|
178
|
-
version: "1.0.0",
|
|
179
|
-
});
|
|
180
|
-
|
|
181
|
-
// ── list_skills ──
|
|
182
|
-
server.registerTool(
|
|
183
|
-
"list_skills",
|
|
184
|
-
{
|
|
185
|
-
description: "列出所有可用的 Skills(来自全局 ~/.roo/skills 和项目 .roo/skills)",
|
|
186
|
-
inputSchema: {},
|
|
187
|
-
},
|
|
188
|
-
async () => {
|
|
189
|
-
const skills = scanSkills();
|
|
190
|
-
|
|
191
|
-
if (skills.length === 0) {
|
|
192
|
-
const dirList = getSkillDirs().map((d) => ` - ${d}`).join("\n");
|
|
193
|
-
return {
|
|
194
|
-
content: [{
|
|
195
|
-
type: "text",
|
|
196
|
-
text: `未找到任何 Skill。\n\n请检查以下目录是否存在 SKILL.md 文件:\n${dirList}`,
|
|
197
|
-
}],
|
|
198
|
-
};
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
const rows = skills.map((s) => {
|
|
202
|
-
const desc = s.description.length > 80 ? s.description.slice(0, 77) + "..." : s.description;
|
|
203
|
-
return `| \`${s.name}\` | ${desc} | ${s.source} |`;
|
|
204
|
-
});
|
|
205
|
-
|
|
206
|
-
return {
|
|
207
|
-
content: [{
|
|
208
|
-
type: "text",
|
|
209
|
-
text:
|
|
210
|
-
`## 可用 Skills(共 ${skills.length} 个)\n\n` +
|
|
211
|
-
`| 名称 | 描述 | 来源 |\n|------|------|------|\n` +
|
|
212
|
-
rows.join("\n"),
|
|
213
|
-
}],
|
|
214
|
-
};
|
|
215
|
-
}
|
|
216
|
-
);
|
|
217
|
-
|
|
218
|
-
// ── read_skill ──
|
|
219
|
-
server.registerTool(
|
|
220
|
-
"read_skill",
|
|
221
|
-
{
|
|
222
|
-
description: "读取指定 Skill 的完整 SKILL.md 内容",
|
|
223
|
-
inputSchema: {
|
|
224
|
-
name: z.string().describe("Skill 名称(目录名或 frontmatter 中的 name)"),
|
|
225
|
-
},
|
|
226
|
-
},
|
|
227
|
-
async ({ name: skillName }) => {
|
|
228
|
-
const skill = findSkillByName(skillName.trim());
|
|
229
|
-
|
|
230
|
-
if (!skill) {
|
|
231
|
-
return {
|
|
232
|
-
content: [{
|
|
233
|
-
type: "text",
|
|
234
|
-
text: `未找到 Skill \`${skillName}\`。\n\n请确认名称是否正确,或使用 list_skills 查看所有可用 Skills。`,
|
|
235
|
-
}],
|
|
236
|
-
};
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
const content = fs.readFileSync(skill.skillFile, "utf-8");
|
|
240
|
-
return {
|
|
241
|
-
content: [{
|
|
242
|
-
type: "text",
|
|
243
|
-
text: `## Skill: ${skill.name}\n**来源**: ${skill.source} (${skill.skillFile})\n\n---\n\n${content}`,
|
|
244
|
-
}],
|
|
245
|
-
};
|
|
246
|
-
}
|
|
247
|
-
);
|
|
248
|
-
|
|
249
|
-
// ── search_skills ──
|
|
250
|
-
server.registerTool(
|
|
251
|
-
"search_skills",
|
|
252
|
-
{
|
|
253
|
-
description: "模糊搜索 Skills,匹配名称或描述",
|
|
254
|
-
inputSchema: {
|
|
255
|
-
query: z.string().describe("搜索关键词"),
|
|
256
|
-
},
|
|
257
|
-
},
|
|
258
|
-
async ({ query }) => {
|
|
259
|
-
const skills = scanSkills();
|
|
260
|
-
const q = query.trim();
|
|
261
|
-
|
|
262
|
-
const matched = skills.filter(
|
|
263
|
-
(s) =>
|
|
264
|
-
fuzzyMatch(q, s.name) ||
|
|
265
|
-
s.name.toLowerCase().includes(q.toLowerCase()) ||
|
|
266
|
-
s.description.toLowerCase().includes(q.toLowerCase())
|
|
267
|
-
);
|
|
268
|
-
|
|
269
|
-
if (matched.length === 0) {
|
|
270
|
-
return {
|
|
271
|
-
content: [{ type: "text", text: `未找到匹配 "${q}" 的 Skill。` }],
|
|
272
|
-
};
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
const rows = matched.map((s) => {
|
|
276
|
-
const desc = s.description.length > 100 ? s.description.slice(0, 97) + "..." : s.description;
|
|
277
|
-
return `| \`${s.name}\` | ${desc} | ${s.source} |`;
|
|
278
|
-
});
|
|
279
|
-
|
|
280
|
-
return {
|
|
281
|
-
content: [{
|
|
282
|
-
type: "text",
|
|
283
|
-
text:
|
|
284
|
-
`## 搜索结果:${matched.length} 个匹配 "${q}"\n\n` +
|
|
285
|
-
`| 名称 | 描述 | 来源 |\n|------|------|------|\n` +
|
|
286
|
-
rows.join("\n"),
|
|
287
|
-
}],
|
|
288
|
-
};
|
|
289
|
-
}
|
|
290
|
-
);
|
|
291
|
-
|
|
292
|
-
// ── list_skill_files ──
|
|
293
|
-
server.registerTool(
|
|
294
|
-
"list_skill_files",
|
|
295
|
-
{
|
|
296
|
-
description: "列出指定 Skill 目录下的所有附属文件(脚本、模板等)",
|
|
297
|
-
inputSchema: {
|
|
298
|
-
name: z.string().describe("Skill 名称"),
|
|
299
|
-
},
|
|
300
|
-
},
|
|
301
|
-
async ({ name: skillName }) => {
|
|
302
|
-
const skill = findSkillByName(skillName.trim());
|
|
303
|
-
|
|
304
|
-
if (!skill) {
|
|
305
|
-
return {
|
|
306
|
-
content: [{ type: "text", text: `未找到 Skill \`${skillName}\`。` }],
|
|
307
|
-
};
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
const files = listFilesRecursive(skill.skillDir);
|
|
311
|
-
return {
|
|
312
|
-
content: [{
|
|
313
|
-
type: "text",
|
|
314
|
-
text:
|
|
315
|
-
`## Skill \`${skill.name}\` 的附属文件\n` +
|
|
316
|
-
`**路径**: ${skill.skillDir}\n\n` +
|
|
317
|
-
(files.length === 0 ? "_(无附属文件)_" : files.map((f) => `- \`${f}\``).join("\n")),
|
|
318
|
-
}],
|
|
319
|
-
};
|
|
320
|
-
}
|
|
321
|
-
);
|
|
322
|
-
|
|
323
|
-
// ──────────────────────────────────────────────
|
|
324
|
-
// 启动
|
|
325
|
-
// ──────────────────────────────────────────────
|
|
326
|
-
|
|
327
|
-
async function main() {
|
|
328
|
-
const transport = new StdioServerTransport();
|
|
329
|
-
await server.connect(transport);
|
|
330
|
-
console.error("Skills MCP server started");
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
main().catch((err) => {
|
|
334
|
-
console.error("Fatal error:", err);
|
|
335
|
-
process.exit(1);
|
|
336
|
-
});
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "skills-mcp",
|
|
3
|
-
"version": "1.0.0",
|
|
4
|
-
"description": "MCP server for managing and reading Roo Code Skills",
|
|
5
|
-
"main": "dist/index.js",
|
|
6
|
-
"scripts": {
|
|
7
|
-
"build": "tsc",
|
|
8
|
-
"start": "node dist/index.js",
|
|
9
|
-
"dev": "ts-node src/index.ts"
|
|
10
|
-
},
|
|
11
|
-
"dependencies": {
|
|
12
|
-
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
13
|
-
"gray-matter": "^4.0.3"
|
|
14
|
-
},
|
|
15
|
-
"devDependencies": {
|
|
16
|
-
"@types/node": "^20.0.0",
|
|
17
|
-
"typescript": "^5.0.0"
|
|
18
|
-
}
|
|
19
|
-
}
|
package/skill-mcp/tsconfig.json
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"target": "ES2020",
|
|
4
|
-
"module": "commonjs",
|
|
5
|
-
"lib": ["ES2020"],
|
|
6
|
-
"outDir": "./dist",
|
|
7
|
-
"rootDir": "./src",
|
|
8
|
-
"strict": true,
|
|
9
|
-
"esModuleInterop": true,
|
|
10
|
-
"skipLibCheck": true,
|
|
11
|
-
"forceConsistentCasingInFileNames": true,
|
|
12
|
-
"resolveJsonModule": true
|
|
13
|
-
},
|
|
14
|
-
"include": ["src/**/*"],
|
|
15
|
-
"exclude": ["node_modules", "dist"]
|
|
16
|
-
}
|