@reus-able/frontend-helper-mcp 1.1.1 → 1.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js
CHANGED
|
@@ -1,115 +1,115 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { McpServer as
|
|
3
|
-
import { StdioServerTransport as
|
|
4
|
-
import
|
|
2
|
+
import { McpServer as F } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
3
|
+
import { StdioServerTransport as x } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
4
|
+
import m from "fs/promises";
|
|
5
5
|
import a from "path";
|
|
6
|
-
import { fileURLToPath as
|
|
7
|
-
import { ListPromptsRequestSchema as
|
|
8
|
-
import
|
|
9
|
-
function
|
|
6
|
+
import { fileURLToPath as f } from "url";
|
|
7
|
+
import { ListPromptsRequestSchema as $, GetPromptRequestSchema as P, ListResourcesRequestSchema as E, ReadResourceRequestSchema as L, ListToolsRequestSchema as M, CallToolRequestSchema as T } from "@modelcontextprotocol/sdk/types.js";
|
|
8
|
+
import C from "fs";
|
|
9
|
+
function _(e) {
|
|
10
10
|
try {
|
|
11
|
-
return
|
|
11
|
+
return C.statSync(e).isDirectory();
|
|
12
12
|
} catch {
|
|
13
13
|
return !1;
|
|
14
14
|
}
|
|
15
15
|
}
|
|
16
|
-
function
|
|
16
|
+
function p(e, n, s = 8) {
|
|
17
17
|
let r = e;
|
|
18
|
-
for (let
|
|
19
|
-
const
|
|
20
|
-
if (
|
|
18
|
+
for (let t = 0; t <= s; t++) {
|
|
19
|
+
const o = a.resolve(r, n);
|
|
20
|
+
if (_(o)) return o;
|
|
21
21
|
const i = a.dirname(r);
|
|
22
22
|
if (i === r) break;
|
|
23
23
|
r = i;
|
|
24
24
|
}
|
|
25
25
|
}
|
|
26
|
-
function
|
|
26
|
+
function k() {
|
|
27
27
|
const e = process.env.MCP_COMMAND_PROMPTS_DIR ?? process.env.MCP_PROMPTS_DIR;
|
|
28
28
|
if (e) return e;
|
|
29
|
-
const
|
|
30
|
-
|
|
29
|
+
const n = a.dirname(f(import.meta.url)), s = p(
|
|
30
|
+
n,
|
|
31
31
|
"resources/command-prompts"
|
|
32
32
|
);
|
|
33
|
-
if (
|
|
34
|
-
const r =
|
|
33
|
+
if (s) return s;
|
|
34
|
+
const r = p(
|
|
35
35
|
process.cwd(),
|
|
36
36
|
"resources/command-prompts"
|
|
37
37
|
);
|
|
38
38
|
return r || a.resolve(process.cwd(), "resources/command-prompts");
|
|
39
39
|
}
|
|
40
|
-
function
|
|
40
|
+
function h() {
|
|
41
41
|
const e = process.env.MCP_SKILLS_DIR;
|
|
42
42
|
if (e) return e;
|
|
43
|
-
const
|
|
44
|
-
if (
|
|
45
|
-
const r =
|
|
43
|
+
const n = a.dirname(f(import.meta.url)), s = p(n, "resources/skills");
|
|
44
|
+
if (s) return s;
|
|
45
|
+
const r = p(process.cwd(), "resources/skills");
|
|
46
46
|
return r || a.resolve(process.cwd(), "resources/skills");
|
|
47
47
|
}
|
|
48
|
-
async function
|
|
48
|
+
async function w(e) {
|
|
49
49
|
try {
|
|
50
|
-
return await
|
|
51
|
-
(
|
|
50
|
+
return await m.access(e), (await m.readdir(e)).filter(
|
|
51
|
+
(s) => [".txt", ".md", ".json"].includes(a.extname(s).toLowerCase())
|
|
52
52
|
);
|
|
53
|
-
} catch (
|
|
54
|
-
return console.error(`Error accessing prompts directory ${e}:`,
|
|
53
|
+
} catch (n) {
|
|
54
|
+
return console.error(`Error accessing prompts directory ${e}:`, n), [];
|
|
55
55
|
}
|
|
56
56
|
}
|
|
57
57
|
function D(e) {
|
|
58
58
|
return !(!e || e.includes("..") || e.includes("/") || e.includes("\\"));
|
|
59
59
|
}
|
|
60
|
-
function
|
|
61
|
-
const
|
|
62
|
-
if (!
|
|
63
|
-
const
|
|
64
|
-
for (const r of
|
|
60
|
+
function N(e) {
|
|
61
|
+
const n = e.match(/^---\s*\n([\s\S]*?)\n---\s*\n/);
|
|
62
|
+
if (!n) return {};
|
|
63
|
+
const s = {};
|
|
64
|
+
for (const r of n[1].split(`
|
|
65
65
|
`)) {
|
|
66
|
-
const
|
|
67
|
-
if (!
|
|
68
|
-
const
|
|
69
|
-
if (!
|
|
70
|
-
const i =
|
|
71
|
-
i === "name" && (
|
|
66
|
+
const t = r.trim();
|
|
67
|
+
if (!t) continue;
|
|
68
|
+
const o = t.match(/^([A-Za-z0-9_-]+):\s*(.*)\s*$/);
|
|
69
|
+
if (!o) continue;
|
|
70
|
+
const i = o[1], c = o[2];
|
|
71
|
+
i === "name" && (s.name = c), i === "description" && (s.description = c);
|
|
72
72
|
}
|
|
73
|
-
return
|
|
73
|
+
return s;
|
|
74
74
|
}
|
|
75
|
-
async function
|
|
75
|
+
async function v(e) {
|
|
76
76
|
try {
|
|
77
|
-
await
|
|
78
|
-
const
|
|
79
|
-
for (const
|
|
80
|
-
const
|
|
77
|
+
await m.access(e);
|
|
78
|
+
const s = (await m.readdir(e, { withFileTypes: !0 })).filter((t) => t.isDirectory()).map((t) => t.name), r = [];
|
|
79
|
+
for (const t of s) {
|
|
80
|
+
const o = a.join(e, t, "SKILL.md");
|
|
81
81
|
try {
|
|
82
|
-
const i = await
|
|
82
|
+
const i = await m.readFile(o, "utf-8"), c = N(i);
|
|
83
83
|
r.push({
|
|
84
|
-
dirName:
|
|
85
|
-
name:
|
|
86
|
-
description:
|
|
87
|
-
filePath:
|
|
84
|
+
dirName: t,
|
|
85
|
+
name: c.name,
|
|
86
|
+
description: c.description,
|
|
87
|
+
filePath: o
|
|
88
88
|
});
|
|
89
89
|
} catch {
|
|
90
90
|
continue;
|
|
91
91
|
}
|
|
92
92
|
}
|
|
93
|
-
return r.sort((
|
|
94
|
-
} catch (
|
|
95
|
-
return console.error(`Error accessing skills directory ${e}:`,
|
|
93
|
+
return r.sort((t, o) => t.dirName.localeCompare(o.dirName)), r;
|
|
94
|
+
} catch (n) {
|
|
95
|
+
return console.error(`Error accessing skills directory ${e}:`, n), [];
|
|
96
96
|
}
|
|
97
97
|
}
|
|
98
|
-
async function
|
|
99
|
-
if (!D(
|
|
100
|
-
const r = (await
|
|
98
|
+
async function I(e, n) {
|
|
99
|
+
if (!D(n)) return;
|
|
100
|
+
const r = (await v(e)).find((o) => o.dirName === n || o.name === n);
|
|
101
101
|
if (!r) return;
|
|
102
|
-
const
|
|
103
|
-
return { entry: r, markdown:
|
|
102
|
+
const t = await m.readFile(r.filePath, "utf-8");
|
|
103
|
+
return { entry: r, markdown: t };
|
|
104
104
|
}
|
|
105
|
-
async function
|
|
106
|
-
return (await
|
|
105
|
+
async function S(e, n) {
|
|
106
|
+
return (await w(e)).find((r) => a.parse(r).name === n);
|
|
107
107
|
}
|
|
108
|
-
function
|
|
109
|
-
const
|
|
110
|
-
return
|
|
108
|
+
function y(e) {
|
|
109
|
+
const n = a.extname(e).toLowerCase();
|
|
110
|
+
return n === ".md" ? "text/markdown" : n === ".json" ? "application/json" : "text/plain";
|
|
111
111
|
}
|
|
112
|
-
const
|
|
112
|
+
const R = {
|
|
113
113
|
"code-refactor": {
|
|
114
114
|
name: "代码重构",
|
|
115
115
|
description: "对代码进行结构调整,不改变功能逻辑"
|
|
@@ -126,26 +126,35 @@ const S = {
|
|
|
126
126
|
name: "安装技能",
|
|
127
127
|
description: "安装mcp中定义的技能"
|
|
128
128
|
}
|
|
129
|
+
}, j = {
|
|
130
|
+
"vue-components": {
|
|
131
|
+
name: "Vue组件编写规范",
|
|
132
|
+
description: "对于Vue组件的编写规范"
|
|
133
|
+
},
|
|
134
|
+
"vue-hooks": {
|
|
135
|
+
name: "Vue钩子函数编写规范",
|
|
136
|
+
description: "对于Vue组件中的钩子函数的编写规范"
|
|
137
|
+
}
|
|
129
138
|
};
|
|
130
|
-
function
|
|
131
|
-
const
|
|
132
|
-
e.server.setRequestHandler(
|
|
139
|
+
function q(e) {
|
|
140
|
+
const n = k();
|
|
141
|
+
e.server.setRequestHandler($, async () => {
|
|
133
142
|
try {
|
|
134
|
-
return { prompts: (await
|
|
135
|
-
const
|
|
143
|
+
return { prompts: (await w(n)).map((t) => {
|
|
144
|
+
const o = a.parse(t).name;
|
|
136
145
|
return {
|
|
137
|
-
name:
|
|
138
|
-
description:
|
|
146
|
+
name: o,
|
|
147
|
+
description: R[o]?.description || `Content of ${t}`
|
|
139
148
|
};
|
|
140
149
|
}) };
|
|
141
|
-
} catch (
|
|
142
|
-
return console.error("Error listing prompts:",
|
|
150
|
+
} catch (s) {
|
|
151
|
+
return console.error("Error listing prompts:", s), { prompts: [] };
|
|
143
152
|
}
|
|
144
|
-
}), e.server.setRequestHandler(
|
|
145
|
-
const r =
|
|
153
|
+
}), e.server.setRequestHandler(P, async (s) => {
|
|
154
|
+
const r = s.params.name;
|
|
146
155
|
try {
|
|
147
|
-
const
|
|
148
|
-
if (!
|
|
156
|
+
const t = await S(n, r);
|
|
157
|
+
if (!t)
|
|
149
158
|
throw new Error(`Prompt not found: ${r}`);
|
|
150
159
|
return {
|
|
151
160
|
messages: [
|
|
@@ -153,58 +162,104 @@ function j(e) {
|
|
|
153
162
|
role: "user",
|
|
154
163
|
content: {
|
|
155
164
|
type: "text",
|
|
156
|
-
text: await
|
|
165
|
+
text: await m.readFile(a.join(n, t), "utf-8")
|
|
157
166
|
}
|
|
158
167
|
}
|
|
159
168
|
]
|
|
160
169
|
};
|
|
161
|
-
} catch (
|
|
162
|
-
throw new Error(`Failed to load prompt ${r}: ${
|
|
170
|
+
} catch (t) {
|
|
171
|
+
throw new Error(`Failed to load prompt ${r}: ${t}`);
|
|
163
172
|
}
|
|
164
173
|
});
|
|
165
174
|
}
|
|
166
175
|
function H(e) {
|
|
167
|
-
const
|
|
168
|
-
e.server.setRequestHandler(
|
|
176
|
+
const n = k(), s = h();
|
|
177
|
+
e.server.setRequestHandler(E, async () => {
|
|
169
178
|
try {
|
|
170
|
-
|
|
171
|
-
const
|
|
179
|
+
const t = (await w(n)).map((i) => {
|
|
180
|
+
const c = a.parse(i).name, l = y(i);
|
|
172
181
|
return {
|
|
173
|
-
uri: `prompt://${
|
|
174
|
-
name:
|
|
175
|
-
mimeType:
|
|
176
|
-
description:
|
|
182
|
+
uri: `prompt://${c}`,
|
|
183
|
+
name: c,
|
|
184
|
+
mimeType: l,
|
|
185
|
+
description: R[c]?.description || `Content of ${i}`
|
|
177
186
|
};
|
|
178
|
-
})
|
|
179
|
-
|
|
180
|
-
|
|
187
|
+
});
|
|
188
|
+
let o = [];
|
|
189
|
+
try {
|
|
190
|
+
o = (await m.readdir(s, { withFileTypes: !0 })).filter((c) => c.isDirectory()).map((c) => {
|
|
191
|
+
const l = c.name;
|
|
192
|
+
return {
|
|
193
|
+
uri: `skill://skill-${l}`,
|
|
194
|
+
name: l,
|
|
195
|
+
mimeType: "text/markdown",
|
|
196
|
+
description: j[l]?.description || `Skill ${l}`
|
|
197
|
+
};
|
|
198
|
+
});
|
|
199
|
+
} catch (i) {
|
|
200
|
+
console.error("Error listing skills:", i);
|
|
201
|
+
}
|
|
202
|
+
return { resources: [...t, ...o] };
|
|
203
|
+
} catch (r) {
|
|
204
|
+
return console.error("Error listing resources:", r), { resources: [] };
|
|
181
205
|
}
|
|
182
206
|
}), e.server.setRequestHandler(
|
|
183
|
-
|
|
184
|
-
async (
|
|
185
|
-
const
|
|
207
|
+
L,
|
|
208
|
+
async (r) => {
|
|
209
|
+
const t = r.params.uri;
|
|
186
210
|
try {
|
|
187
|
-
const
|
|
188
|
-
if (
|
|
189
|
-
throw new Error(`
|
|
190
|
-
const i =
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
211
|
+
const o = t.indexOf("://");
|
|
212
|
+
if (o === -1)
|
|
213
|
+
throw new Error(`Invalid URI format: ${t}`);
|
|
214
|
+
const i = t.substring(0, o), c = t.substring(o + 3);
|
|
215
|
+
switch (i) {
|
|
216
|
+
case "skill": {
|
|
217
|
+
const l = a.join(s, c.replace("skill-", ""), "SKILL.md");
|
|
218
|
+
try {
|
|
219
|
+
await m.access(l);
|
|
220
|
+
} catch {
|
|
221
|
+
throw new Error(`Resource not found: ${t}`);
|
|
197
222
|
}
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
223
|
+
const u = await m.readFile(l, "utf-8");
|
|
224
|
+
return {
|
|
225
|
+
contents: [
|
|
226
|
+
{
|
|
227
|
+
uri: t,
|
|
228
|
+
mimeType: "text/markdown",
|
|
229
|
+
text: u
|
|
230
|
+
}
|
|
231
|
+
]
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
case "prompt": {
|
|
235
|
+
const l = await S(n, c);
|
|
236
|
+
if (!l)
|
|
237
|
+
throw new Error(`Resource not found: ${t}`);
|
|
238
|
+
const u = await m.readFile(
|
|
239
|
+
a.join(n, l),
|
|
240
|
+
"utf-8"
|
|
241
|
+
), d = y(l);
|
|
242
|
+
return {
|
|
243
|
+
contents: [
|
|
244
|
+
{
|
|
245
|
+
uri: t,
|
|
246
|
+
mimeType: d,
|
|
247
|
+
text: u
|
|
248
|
+
}
|
|
249
|
+
]
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
default:
|
|
253
|
+
throw new Error(`Unsupported resource protocol: ${i}`);
|
|
254
|
+
}
|
|
255
|
+
} catch (o) {
|
|
256
|
+
throw new Error(`Failed to read resource ${t}: ${o}`);
|
|
202
257
|
}
|
|
203
258
|
}
|
|
204
259
|
);
|
|
205
260
|
}
|
|
206
|
-
function
|
|
207
|
-
const
|
|
261
|
+
function O(e) {
|
|
262
|
+
const n = h(), s = {
|
|
208
263
|
name: "get_skill",
|
|
209
264
|
description: "按名称获取 resources/skills 下的 SKILL.md 内容",
|
|
210
265
|
inputSchema: {
|
|
@@ -219,10 +274,10 @@ function I(e) {
|
|
|
219
274
|
},
|
|
220
275
|
annotations: { readOnlyHint: !0, idempotentHint: !0 }
|
|
221
276
|
};
|
|
222
|
-
e.server.setRequestHandler(
|
|
277
|
+
e.server.setRequestHandler(M, async () => ({ tools: [s] })), e.server.setRequestHandler(T, async (r) => {
|
|
223
278
|
if (r.params.name === "get_skill") {
|
|
224
|
-
const
|
|
225
|
-
if (!
|
|
279
|
+
const t = r.params.arguments, o = t && typeof t == "object" && typeof t.name == "string" ? t.name : void 0;
|
|
280
|
+
if (!o)
|
|
226
281
|
return {
|
|
227
282
|
content: [
|
|
228
283
|
{
|
|
@@ -233,21 +288,21 @@ function I(e) {
|
|
|
233
288
|
isError: !0
|
|
234
289
|
};
|
|
235
290
|
try {
|
|
236
|
-
const i = await
|
|
291
|
+
const i = await I(n, o);
|
|
237
292
|
if (!i) {
|
|
238
|
-
const
|
|
239
|
-
const
|
|
240
|
-
return `- ${
|
|
293
|
+
const l = (await v(n)).map((u) => {
|
|
294
|
+
const d = [u.dirName, u.name].filter(Boolean).join(", "), g = u.description ? ` - ${u.description}` : "";
|
|
295
|
+
return `- ${d}${g}`;
|
|
241
296
|
}).join(`
|
|
242
297
|
`);
|
|
243
298
|
return {
|
|
244
299
|
content: [
|
|
245
300
|
{
|
|
246
301
|
type: "text",
|
|
247
|
-
text: `Skill not found: ${
|
|
302
|
+
text: `Skill not found: ${o}
|
|
248
303
|
|
|
249
304
|
Available skills:
|
|
250
|
-
` + (
|
|
305
|
+
` + (l || "- (none)")
|
|
251
306
|
}
|
|
252
307
|
],
|
|
253
308
|
isError: !0
|
|
@@ -284,11 +339,11 @@ Available skills:
|
|
|
284
339
|
};
|
|
285
340
|
});
|
|
286
341
|
}
|
|
287
|
-
async function
|
|
288
|
-
const e = a.dirname(
|
|
342
|
+
async function b() {
|
|
343
|
+
const e = a.dirname(f(import.meta.url)), n = a.resolve(e, "../package.json"), s = JSON.parse(await m.readFile(n, "utf-8")), r = new F(
|
|
289
344
|
{
|
|
290
|
-
name:
|
|
291
|
-
version:
|
|
345
|
+
name: s.name,
|
|
346
|
+
version: s.version
|
|
292
347
|
},
|
|
293
348
|
{
|
|
294
349
|
capabilities: {
|
|
@@ -298,13 +353,13 @@ async function O() {
|
|
|
298
353
|
}
|
|
299
354
|
}
|
|
300
355
|
);
|
|
301
|
-
return
|
|
356
|
+
return q(r), H(r), O(r), r;
|
|
302
357
|
}
|
|
303
|
-
async function
|
|
358
|
+
async function K() {
|
|
304
359
|
console.error("Starting MCP server serving...");
|
|
305
|
-
const e = await
|
|
306
|
-
await e.connect(
|
|
360
|
+
const e = await b(), n = new x();
|
|
361
|
+
await e.connect(n);
|
|
307
362
|
}
|
|
308
|
-
|
|
363
|
+
K().catch((e) => {
|
|
309
364
|
console.error("Fatal error:", e), process.exit(1);
|
|
310
365
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
## 组件结构重构
|
|
2
|
-
|
|
2
|
+
你需要帮助用户进行组件结构重构
|
|
3
3
|
|
|
4
|
+
### 1. 确认组件重构要求
|
|
5
|
+
|
|
6
|
+
首先,查看是否存在 `skill-vue-components` 资源。
|
|
7
|
+
**如果有,则按照该资源的要求进行组件结构重构。**
|
|
8
|
+
|
|
9
|
+
**否则,遵循以下要求:**
|
|
10
|
+
```
|
|
4
11
|
1. 视图层与逻辑层分离,即SFC中只负责视图渲染,逻辑抽离到hook中。
|
|
5
12
|
1.1. 完善定义组件的常量、类型,将props,emit等类型也提取出来。
|
|
6
13
|
1.2. 组件中的主要逻辑需要放在对应的useXXX.ts文件中,入参为组件的props,并导出useXXX hook。
|
|
@@ -18,5 +25,15 @@
|
|
|
18
25
|
** 不要设计逻辑的变更 **
|
|
19
26
|
** 不要修改类名或者html结构 **
|
|
20
27
|
** 注意不要破坏变量的响应式 **
|
|
28
|
+
```
|
|
21
29
|
|
|
22
|
-
|
|
30
|
+
### 2. 列出重构计划
|
|
31
|
+
根据以上要求,列出组件结构重构的计划。
|
|
32
|
+
计划大纲如下:
|
|
33
|
+
1. 重构基准
|
|
34
|
+
如果存在 `/helper/vue-components` 资源则输出 `/helper/vue-components`;
|
|
35
|
+
否则输出 `备用组件结构重构规范`
|
|
36
|
+
2. 当前组件分析
|
|
37
|
+
3. 重构改动点以及修改后的文件结构
|
|
38
|
+
4. 注意事项
|
|
39
|
+
5. 实施步骤
|