vite-plugin-aipanel 1.2.0-beta.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.
Files changed (98) hide show
  1. package/README.md +72 -0
  2. package/es/client/vue-devtools-bridge.d.ts +58 -0
  3. package/es/client/vue-devtools-bridge.mjs +150 -0
  4. package/es/core/injector.d.ts +2 -0
  5. package/es/core/injector.mjs +15 -0
  6. package/es/core/mcp-chrome.d.ts +56 -0
  7. package/es/core/mcp-chrome.mjs +133 -0
  8. package/es/core/mcp-proxy.d.ts +23 -0
  9. package/es/core/mcp-proxy.mjs +212 -0
  10. package/es/core/mcp-tools.d.ts +15 -0
  11. package/es/core/mcp-tools.mjs +671 -0
  12. package/es/core/provider-loader.d.ts +19 -0
  13. package/es/core/provider-loader.mjs +30 -0
  14. package/es/core/proxy-server.d.ts +12 -0
  15. package/es/core/proxy-server.mjs +148 -0
  16. package/es/core/service.d.ts +39 -0
  17. package/es/core/service.mjs +267 -0
  18. package/es/endpoints/context.d.ts +3 -0
  19. package/es/endpoints/context.mjs +106 -0
  20. package/es/endpoints/index.d.ts +9 -0
  21. package/es/endpoints/index.mjs +30 -0
  22. package/es/endpoints/logs.d.ts +9 -0
  23. package/es/endpoints/logs.mjs +86 -0
  24. package/es/endpoints/mcp.d.ts +6 -0
  25. package/es/endpoints/mcp.mjs +610 -0
  26. package/es/endpoints/sessions.d.ts +3 -0
  27. package/es/endpoints/sessions.mjs +62 -0
  28. package/es/endpoints/sse.d.ts +3 -0
  29. package/es/endpoints/sse.mjs +44 -0
  30. package/es/endpoints/start.d.ts +3 -0
  31. package/es/endpoints/start.mjs +21 -0
  32. package/es/endpoints/types.d.ts +34 -0
  33. package/es/endpoints/types.mjs +0 -0
  34. package/es/endpoints/vue-devtools.d.ts +9 -0
  35. package/es/endpoints/vue-devtools.mjs +107 -0
  36. package/es/endpoints/warmup.d.ts +3 -0
  37. package/es/endpoints/warmup.mjs +42 -0
  38. package/es/endpoints/widget.d.ts +3 -0
  39. package/es/endpoints/widget.mjs +36 -0
  40. package/es/env.d.ts +1 -0
  41. package/es/index.d.ts +22 -0
  42. package/es/index.mjs +342 -0
  43. package/es/utils/format-bridge.d.ts +9 -0
  44. package/es/utils/format-bridge.mjs +80 -0
  45. package/es/utils/paths.d.ts +3 -0
  46. package/es/utils/paths.mjs +45 -0
  47. package/es/utils/system.d.ts +3 -0
  48. package/es/utils/system.mjs +76 -0
  49. package/lib/client/vue-devtools-bridge.cjs +150 -0
  50. package/lib/client/vue-devtools-bridge.d.ts +58 -0
  51. package/lib/client.css +2 -0
  52. package/lib/client.js +6950 -0
  53. package/lib/core/injector.cjs +34 -0
  54. package/lib/core/injector.d.ts +2 -0
  55. package/lib/core/mcp-chrome.cjs +161 -0
  56. package/lib/core/mcp-chrome.d.ts +56 -0
  57. package/lib/core/mcp-proxy.cjs +244 -0
  58. package/lib/core/mcp-proxy.d.ts +23 -0
  59. package/lib/core/mcp-tools.cjs +694 -0
  60. package/lib/core/mcp-tools.d.ts +15 -0
  61. package/lib/core/provider-loader.cjs +53 -0
  62. package/lib/core/provider-loader.d.ts +19 -0
  63. package/lib/core/proxy-server.cjs +181 -0
  64. package/lib/core/proxy-server.d.ts +12 -0
  65. package/lib/core/service.cjs +289 -0
  66. package/lib/core/service.d.ts +39 -0
  67. package/lib/endpoints/context.cjs +129 -0
  68. package/lib/endpoints/context.d.ts +3 -0
  69. package/lib/endpoints/index.cjs +58 -0
  70. package/lib/endpoints/index.d.ts +9 -0
  71. package/lib/endpoints/logs.cjs +107 -0
  72. package/lib/endpoints/logs.d.ts +9 -0
  73. package/lib/endpoints/mcp.cjs +624 -0
  74. package/lib/endpoints/mcp.d.ts +6 -0
  75. package/lib/endpoints/sessions.cjs +85 -0
  76. package/lib/endpoints/sessions.d.ts +3 -0
  77. package/lib/endpoints/sse.cjs +67 -0
  78. package/lib/endpoints/sse.d.ts +3 -0
  79. package/lib/endpoints/start.cjs +44 -0
  80. package/lib/endpoints/start.d.ts +3 -0
  81. package/lib/endpoints/types.cjs +15 -0
  82. package/lib/endpoints/types.d.ts +34 -0
  83. package/lib/endpoints/vue-devtools.cjs +132 -0
  84. package/lib/endpoints/vue-devtools.d.ts +9 -0
  85. package/lib/endpoints/warmup.cjs +65 -0
  86. package/lib/endpoints/warmup.d.ts +3 -0
  87. package/lib/endpoints/widget.cjs +69 -0
  88. package/lib/endpoints/widget.d.ts +3 -0
  89. package/lib/env.d.ts +1 -0
  90. package/lib/index.cjs +361 -0
  91. package/lib/index.d.ts +22 -0
  92. package/lib/utils/format-bridge.cjs +102 -0
  93. package/lib/utils/format-bridge.d.ts +9 -0
  94. package/lib/utils/paths.cjs +80 -0
  95. package/lib/utils/paths.d.ts +3 -0
  96. package/lib/utils/system.cjs +110 -0
  97. package/lib/utils/system.d.ts +3 -0
  98. package/package.json +68 -0
@@ -0,0 +1,624 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
+ var __getOwnPropNames = Object.getOwnPropertyNames;
4
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
5
+ var __export = (target, all) => {
6
+ for (var name in all)
7
+ __defProp(target, name, { get: all[name], enumerable: true });
8
+ };
9
+ var __copyProps = (to, from, except, desc) => {
10
+ if (from && typeof from === "object" || typeof from === "function") {
11
+ for (let key of __getOwnPropNames(from))
12
+ if (!__hasOwnProp.call(to, key) && key !== except)
13
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
14
+ }
15
+ return to;
16
+ };
17
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
18
+ var mcp_exports = {};
19
+ __export(mcp_exports, {
20
+ MCP_API_PATH: () => import_core.MCP_API_PATH,
21
+ setupMcpEndpoint: () => setupMcpEndpoint
22
+ });
23
+ module.exports = __toCommonJS(mcp_exports);
24
+ var import_core = require("@aipanel/core");
25
+ var import_node = require("@aipanel/core/node");
26
+ var import_mcp_chrome = require("../core/mcp-chrome.cjs");
27
+ var import_mcp_tools = require("../core/mcp-tools.cjs");
28
+ var import_vue_devtools = require("./vue-devtools.cjs");
29
+ var import_system = require("../utils/system.cjs");
30
+ const log = (0, import_node.createLogger)("McpEndpoint");
31
+ function setupMcpEndpoint(server, mcp, getPageContext, logFiles = []) {
32
+ const projectRoot = (0, import_system.findGitRoot)(process.cwd());
33
+ server.middlewares.use(async (req, res, next) => {
34
+ if (!req.url?.startsWith(import_core.MCP_API_PATH)) return next();
35
+ res.setHeader("Access-Control-Allow-Origin", "*");
36
+ res.setHeader("Access-Control-Allow-Methods", "GET, POST, DELETE, OPTIONS");
37
+ res.setHeader("Access-Control-Allow-Headers", "Content-Type, Mcp-Session-Id, Authorization");
38
+ res.setHeader("Access-Control-Expose-Headers", "Mcp-Session-Id");
39
+ if (req.method === "OPTIONS") {
40
+ res.writeHead(204);
41
+ res.end();
42
+ return;
43
+ }
44
+ if (req.method === "GET") {
45
+ handleGetSse(req, res, mcp);
46
+ return;
47
+ }
48
+ if (req.method === "DELETE") {
49
+ res.writeHead(200);
50
+ res.end();
51
+ return;
52
+ }
53
+ if (req.method === "POST") {
54
+ await handlePost(
55
+ req,
56
+ res,
57
+ mcp,
58
+ (0, import_mcp_chrome.getProjectOrigins)(server),
59
+ getPageContext,
60
+ logFiles,
61
+ projectRoot
62
+ );
63
+ return;
64
+ }
65
+ next();
66
+ });
67
+ }
68
+ function handleGetSse(req, res, mcp) {
69
+ res.writeHead(200, {
70
+ "Content-Type": "text/event-stream",
71
+ "Cache-Control": "no-cache",
72
+ Connection: "keep-alive",
73
+ "Mcp-Session-Id": mcp.sessionId
74
+ });
75
+ res.write(":ok\n\n");
76
+ const keepAlive = setInterval(() => res.write(":ping\n\n"), 15e3);
77
+ req.on("close", () => clearInterval(keepAlive));
78
+ }
79
+ async function handlePost(req, res, mcp, projectOrigins, getPageContext, logFiles, projectRoot) {
80
+ try {
81
+ const body = await readBody(req);
82
+ if (!body) {
83
+ res.writeHead(400);
84
+ res.end("Empty body");
85
+ return;
86
+ }
87
+ const { method, id } = tryParseRequest(body);
88
+ log.debug("MCP request", { method, body: body.substring(0, 150) });
89
+ switch (method) {
90
+ case "tools/list":
91
+ return handleToolsList(res, id, mcp.sessionId, logFiles);
92
+ case "tools/call":
93
+ return await handleToolsCall(
94
+ res,
95
+ id,
96
+ body,
97
+ mcp,
98
+ projectOrigins,
99
+ getPageContext,
100
+ logFiles,
101
+ projectRoot
102
+ );
103
+ default:
104
+ return await handleForward(res, body, mcp);
105
+ }
106
+ } catch (e) {
107
+ log.debug("MCP POST error", { error: e.message });
108
+ sendMcpJson(res, 500, {
109
+ jsonrpc: "2.0",
110
+ error: { code: -32603, message: e.message }
111
+ });
112
+ }
113
+ }
114
+ function handleToolsList(res, id, sessionId, logFiles) {
115
+ const tools = [...import_mcp_tools.CUSTOM_TOOLS, ...buildServiceLogTools(logFiles)];
116
+ sendMcpJson(res, 200, { jsonrpc: "2.0", id, result: { tools } }, sessionId);
117
+ }
118
+ function handleToolsCall(res, id, body, mcp, projectOrigins, getPageContext, logFiles, projectRoot) {
119
+ const params = tryParseParams(body);
120
+ const toolName = params?.name;
121
+ const args = params?.arguments ?? {};
122
+ if (toolName === "chrome-devtools_current_page") {
123
+ return handleGetPageContext(res, id, mcp, projectOrigins, getPageContext);
124
+ }
125
+ if (toolName?.startsWith("vue-devtools_")) {
126
+ return handleVueDevtoolsTool(res, id, mcp, projectOrigins, toolName, args);
127
+ }
128
+ if (toolName === "logs-devtools_vite_logs") {
129
+ return handleViteLogsTool(res, id, args, mcp.sessionId);
130
+ }
131
+ if (toolName && isServiceLogTool(toolName, logFiles)) {
132
+ return handleServiceLogsTool(res, id, toolName, args, logFiles, projectRoot, mcp.sessionId);
133
+ }
134
+ if (toolName?.startsWith("chrome-devtools_")) {
135
+ const mapped = toolName.slice("chrome-devtools_".length);
136
+ if (toolName === "chrome-devtools_list_pages") {
137
+ return handleListPages(res, id, mcp, projectOrigins, getPageContext);
138
+ }
139
+ if (toolName === "chrome-devtools_new_page") {
140
+ return handleNewPage(res, id, mcp, args, projectOrigins, getPageContext);
141
+ }
142
+ return handleDevTool(res, id, mcp, mapped, args, projectOrigins, toolName);
143
+ }
144
+ sendMcpError(res, id, -32601, `Tool not found: ${toolName}`, mcp.sessionId);
145
+ }
146
+ async function resolveProjectPages(mcp, projectOrigins, getPageContext) {
147
+ const listResult = await mcp.callChromeDevTool("list_pages", {});
148
+ if (listResult?.error || !listResult?.result) {
149
+ throw new Error(listResult?.error?.message ?? "\u65E0\u6CD5\u83B7\u53D6 Chrome \u9875\u9762\u5217\u8868");
150
+ }
151
+ const text = listResult?.result?.content?.[0]?.text;
152
+ const allPages = text ? (0, import_mcp_chrome.parseListPages)(text) : [];
153
+ const filtered = allPages.filter((p) => (0, import_mcp_chrome.isProjectPage)(p.url, projectOrigins));
154
+ log.debug("Chrome pages", { total: allPages.length, urls: allPages.map((p) => p.url) });
155
+ log.debug("project origins", { origins: projectOrigins });
156
+ log.debug("filtered pages", { count: filtered.length, pageIds: filtered.map((p) => p.pageId) });
157
+ let activePageId = null;
158
+ let activePageError;
159
+ if (filtered.length > 0) {
160
+ const pc = getPageContext();
161
+ const chromeSelectedPageId = allPages.find((p) => p.selected)?.pageId;
162
+ const resolved = await (0, import_mcp_chrome.resolveChromePageId)(
163
+ mcp,
164
+ pc.url,
165
+ pc.title,
166
+ projectOrigins,
167
+ pc.sessionId,
168
+ filtered,
169
+ chromeSelectedPageId
170
+ );
171
+ activePageId = resolved.ok ? resolved.pageId : null;
172
+ if (!resolved.ok) activePageError = resolved.error;
173
+ }
174
+ return { filtered, activePageId, activePageError };
175
+ }
176
+ async function confirmOpenProjectPages(mcp, projectOrigins, getPageContext) {
177
+ let pages = [];
178
+ let ok = false;
179
+ for (let attempt = 0; attempt < 3; attempt++) {
180
+ try {
181
+ ({ filtered: pages } = await resolveProjectPages(mcp, projectOrigins, getPageContext));
182
+ ok = true;
183
+ break;
184
+ } catch {
185
+ if (attempt < 2) await (0, import_core.sleep)(500);
186
+ }
187
+ }
188
+ if (!ok) return null;
189
+ if (pages.length === 0) {
190
+ await (0, import_core.sleep)(500);
191
+ try {
192
+ ({ filtered: pages } = await resolveProjectPages(mcp, projectOrigins, getPageContext));
193
+ } catch {
194
+ }
195
+ }
196
+ return pages;
197
+ }
198
+ async function handleListPages(res, id, mcp, projectOrigins, getPageContext) {
199
+ try {
200
+ const { filtered, activePageId } = await resolveProjectPages(
201
+ mcp,
202
+ projectOrigins,
203
+ getPageContext
204
+ );
205
+ if (filtered.length === 0) {
206
+ sendMcpResult(res, id, "\u6682\u65E0\u9879\u76EE\u9875\u9762\uFF0C\u8BF7\u5148\u5728\u6D4F\u89C8\u5668\u4E2D\u6253\u5F00\u672C\u5730\u5F00\u53D1\u9875\u9762", mcp.sessionId);
207
+ return;
208
+ }
209
+ const pageList = filtered.map((p) => ({
210
+ pageId: p.pageId,
211
+ url: p.url,
212
+ title: p.title,
213
+ active: activePageId != null ? p.pageId === activePageId : false,
214
+ selected: p.selected
215
+ }));
216
+ sendMcpResult(res, id, JSON.stringify(pageList, null, 2), mcp.sessionId);
217
+ } catch (e) {
218
+ log.debug("handleListPages error", { error: e.message });
219
+ sendMcpError(res, id, -32603, `MCP \u8C03\u7528\u5931\u8D25: ${e.message}`, mcp.sessionId);
220
+ }
221
+ }
222
+ async function handleGetPageContext(res, id, mcp, projectOrigins, getPageContext) {
223
+ try {
224
+ const { filtered, activePageId, activePageError } = await resolveProjectPages(
225
+ mcp,
226
+ projectOrigins,
227
+ getPageContext
228
+ );
229
+ if (filtered.length === 0) {
230
+ sendMcpResult(res, id, "\u6682\u65E0\u9879\u76EE\u9875\u9762\uFF0C\u8BF7\u5148\u5728\u6D4F\u89C8\u5668\u4E2D\u6253\u5F00\u672C\u5730\u5F00\u53D1\u9875\u9762", mcp.sessionId);
231
+ return;
232
+ }
233
+ const pc = getPageContext();
234
+ if (activePageId == null) {
235
+ sendMcpResult(
236
+ res,
237
+ id,
238
+ `\u65E0\u6CD5\u5B9A\u4F4D\u5F53\u524D\u9875\u9762\u5BF9\u5E94\u7684 pageId\uFF1A${activePageError ?? "\u672A\u5339\u914D\u5230\u5DF2\u6253\u5F00\u7684\u9875\u9762"}
239
+
240
+ \u5F53\u524D\u9875\u9762\u4E0A\u4E0B\u6587\uFF1A${pc.title} (${pc.url})
241
+
242
+ \u8BF7\u5237\u65B0\u76EE\u6807\u9875\u9762\u540E\u91CD\u8BD5\uFF1B\u6216\u4F7F\u7528 chrome-devtools_list_pages \u83B7\u53D6\u9875\u9762 ID \u540E\u76F4\u63A5\u64CD\u4F5C\u3002`,
243
+ mcp.sessionId
244
+ );
245
+ return;
246
+ }
247
+ const activePage = filtered.find((p) => p.pageId === activePageId);
248
+ sendMcpResult(
249
+ res,
250
+ id,
251
+ JSON.stringify(
252
+ {
253
+ url: activePage?.url ?? pc.url,
254
+ title: activePage?.title ?? pc.title,
255
+ pageId: activePageId
256
+ },
257
+ null,
258
+ 2
259
+ ),
260
+ mcp.sessionId
261
+ );
262
+ } catch (e) {
263
+ log.debug("handleGetPageContext error", { error: e.message });
264
+ sendMcpError(res, id, -32603, `MCP \u8C03\u7528\u5931\u8D25: ${e.message}`, mcp.sessionId);
265
+ }
266
+ }
267
+ async function handleNewPage(res, id, mcp, args, projectOrigins, getPageContext) {
268
+ try {
269
+ const url = args["url"];
270
+ if (typeof url !== "string" || url.trim().length === 0) {
271
+ sendMcpError(res, id, -32e3, "\u7F3A\u5C11 url \u53C2\u6570\uFF0C\u8BF7\u63D0\u4F9B\u8981\u6253\u5F00\u7684\u9875\u9762 URL", mcp.sessionId);
272
+ return;
273
+ }
274
+ if (!(0, import_mcp_chrome.isProjectPage)(url, projectOrigins)) {
275
+ sendMcpError(
276
+ res,
277
+ id,
278
+ -32e3,
279
+ `\u4E0D\u5141\u8BB8\u6253\u5F00\u975E\u672C\u9879\u76EE\u9875\u9762: ${url}\u3002\u4EC5\u5141\u8BB8\u6253\u5F00\u9879\u76EE\u9875\u9762 (${projectOrigins.join(", ")})`,
280
+ mcp.sessionId
281
+ );
282
+ return;
283
+ }
284
+ const projectPages = await confirmOpenProjectPages(mcp, projectOrigins, getPageContext);
285
+ if (projectPages === null) {
286
+ sendMcpError(
287
+ res,
288
+ id,
289
+ -32e3,
290
+ `\u65E0\u6CD5\u786E\u8BA4\u5F53\u524D\u9879\u76EE\u9875\u9762\u72B6\u6001\uFF0C\u4E3A\u907F\u514D\u91CD\u590D\u6253\u5F00\uFF0C\u8BF7\u786E\u8BA4 Chrome DevTools \u5DF2\u8FDE\u63A5\u540E\u91CD\u8BD5`,
291
+ mcp.sessionId
292
+ );
293
+ return;
294
+ }
295
+ if (projectPages.length > 0) {
296
+ const existing = projectPages.map((p) => `- ${p.title} (${p.url}) [pageId: ${p.pageId}]`).join("\n");
297
+ sendMcpResult(
298
+ res,
299
+ id,
300
+ `\u5F53\u524D\u9879\u76EE\u5DF2\u6709\u6253\u5F00\u7684\u9875\u9762\uFF0C\u65E0\u9700\u91CD\u590D\u6253\u5F00\u3002
301
+
302
+ \u5DF2\u6253\u5F00\u7684\u9875\u9762\uFF1A
303
+ ${existing}
304
+
305
+ \u5982\u9700\u64CD\u4F5C\u73B0\u6709\u9875\u9762\uFF0C\u8BF7\u4F7F\u7528 chrome-devtools_list_pages \u83B7\u53D6\u9875\u9762 ID\uFF0C\u518D\u914D\u5408\u5176\u4ED6 chrome-devtools_* \u5DE5\u5177\u4F7F\u7528\u3002`,
306
+ mcp.sessionId
307
+ );
308
+ return;
309
+ }
310
+ const forwardBody = JSON.stringify({
311
+ jsonrpc: "2.0",
312
+ id,
313
+ method: "tools/call",
314
+ params: { name: "new_page", arguments: { ...args, background: true } }
315
+ });
316
+ const responseText = await mcp.forward(forwardBody);
317
+ log.debug("MCP response", { tool: "new_page", response: responseText.substring(0, 100) });
318
+ sendMcpJson(res, 200, responseText, mcp.sessionId);
319
+ } catch (e) {
320
+ log.debug("handleNewPage error", { error: e.message });
321
+ sendMcpError(res, id, -32603, `MCP \u8C03\u7528\u5931\u8D25: ${e.message}`, mcp.sessionId);
322
+ }
323
+ }
324
+ async function handleDevTool(res, id, mcp, mapped, args, projectOrigins, toolName) {
325
+ try {
326
+ const pageId = args["pageId"];
327
+ if (typeof pageId !== "number") {
328
+ sendMcpError(res, id, -32e3, "\u7F3A\u5C11 pageId \u53C2\u6570\uFF0C\u8BF7\u5148\u83B7\u53D6\u9875\u9762 ID", mcp.sessionId);
329
+ return;
330
+ }
331
+ const validation = await (0, import_mcp_chrome.validatePageId)(mcp, pageId, projectOrigins);
332
+ log.debug("handleDevTool validation", {
333
+ pageId,
334
+ projectPages: validation.projectPages.length,
335
+ projectPageIds: validation.projectPages.map((p) => p.pageId),
336
+ origins: projectOrigins,
337
+ isValid: validation.valid
338
+ });
339
+ if (!validation.valid) {
340
+ sendMcpError(res, id, -32e3, validation.error, mcp.sessionId);
341
+ return;
342
+ }
343
+ if (toolName === "chrome-devtools_navigate_page" && args["type"] === "url") {
344
+ const targetUrl = args["url"];
345
+ if (typeof targetUrl === "string" && targetUrl.length > 0) {
346
+ if (!(0, import_mcp_chrome.isProjectPage)(targetUrl, projectOrigins)) {
347
+ sendMcpError(
348
+ res,
349
+ id,
350
+ -32e3,
351
+ `\u4E0D\u5141\u8BB8\u8DF3\u8F6C\u5230\u975E\u672C\u9879\u76EE\u9875\u9762: ${targetUrl}\u3002\u4EC5\u5141\u8BB8\u5BFC\u822A\u5230\u9879\u76EE\u9875\u9762 (${projectOrigins.join(", ")})`,
352
+ mcp.sessionId
353
+ );
354
+ return;
355
+ }
356
+ }
357
+ }
358
+ await mcp.callChromeDevTool("select_page", { pageId, bringToFront: false });
359
+ const forwardArgs = { ...args };
360
+ delete forwardArgs["pageId"];
361
+ const forwardBody = JSON.stringify({
362
+ jsonrpc: "2.0",
363
+ id,
364
+ method: "tools/call",
365
+ params: { name: mapped, arguments: forwardArgs }
366
+ });
367
+ const responseText = await mcp.forward(forwardBody);
368
+ log.debug("MCP response", { mapped, response: responseText.substring(0, 100) });
369
+ sendMcpJson(res, 200, responseText, mcp.sessionId);
370
+ } catch (e) {
371
+ log.debug("handleDevTool error", { error: e.message, mapped });
372
+ sendMcpError(res, id, -32603, `MCP \u8C03\u7528\u5931\u8D25: ${e.message}`, mcp.sessionId);
373
+ }
374
+ }
375
+ const VUE_DEVTOOLS_TOOL_ACTIONS = {
376
+ "vue-devtools_get_apps": import_core.VUE_DEVTOOLS_ACTIONS.GET_APPS,
377
+ "vue-devtools_set_active_app": import_core.VUE_DEVTOOLS_ACTIONS.TOGGLE_APP,
378
+ "vue-devtools_get_component_tree": import_core.VUE_DEVTOOLS_ACTIONS.GET_COMPONENT_TREE,
379
+ "vue-devtools_get_component_state": import_core.VUE_DEVTOOLS_ACTIONS.GET_COMPONENT_STATE,
380
+ "vue-devtools_get_component_render_code": import_core.VUE_DEVTOOLS_ACTIONS.GET_COMPONENT_RENDER_CODE,
381
+ "vue-devtools_get_current_route": import_core.VUE_DEVTOOLS_ACTIONS.GET_ROUTER_INFO,
382
+ "vue-devtools_get_routes": import_core.VUE_DEVTOOLS_ACTIONS.GET_ROUTER_INFO
383
+ };
384
+ async function handleVueDevtoolsTool(res, id, mcp, projectOrigins, toolName, args) {
385
+ try {
386
+ const action = VUE_DEVTOOLS_TOOL_ACTIONS[toolName];
387
+ if (!action) {
388
+ sendMcpError(res, id, -32601, `Tool not found: ${toolName}`, mcp.sessionId);
389
+ return;
390
+ }
391
+ const result = await (0, import_vue_devtools.executeAction)(action, args, mcp, projectOrigins);
392
+ switch (toolName) {
393
+ case "vue-devtools_set_active_app":
394
+ sendMcpResult(res, id, `\u5DF2\u5207\u6362\u5230\u5E94\u7528 ${args["appId"]}`, mcp.sessionId);
395
+ return;
396
+ case "vue-devtools_get_current_route":
397
+ case "vue-devtools_get_routes": {
398
+ const parsed = typeof result === "string" ? parseJsonSafe(result) : result;
399
+ const data = parsed ?? {};
400
+ const value = toolName === "vue-devtools_get_current_route" ? data.currentRoute ?? null : data.routes ?? null;
401
+ sendMcpResult(res, id, JSON.stringify(value), mcp.sessionId);
402
+ return;
403
+ }
404
+ case "vue-devtools_get_component_render_code":
405
+ sendMcpResult(
406
+ res,
407
+ id,
408
+ typeof result === "string" ? result : JSON.stringify(result),
409
+ mcp.sessionId
410
+ );
411
+ return;
412
+ default:
413
+ sendMcpResult(res, id, JSON.stringify(result), mcp.sessionId);
414
+ return;
415
+ }
416
+ } catch (e) {
417
+ log.debug("handleVueDevtoolsTool error", { error: e.message });
418
+ sendMcpError(res, id, -32603, `Vue DevTools \u8C03\u7528\u5931\u8D25: ${e.message}`, mcp.sessionId);
419
+ }
420
+ }
421
+ function parseJsonSafe(text) {
422
+ try {
423
+ return JSON.parse(text);
424
+ } catch {
425
+ return text;
426
+ }
427
+ }
428
+ function handleViteLogsTool(res, id, args, sessionId) {
429
+ const { level, limit, source } = args;
430
+ const buffer = (0, import_node.getProcessLogBuffer)();
431
+ const logs = buffer.getLogs({
432
+ level: parseProcessLevelFilter(level),
433
+ limit: typeof limit === "number" && limit >= 1 ? limit : 50,
434
+ source: typeof source === "string" && source ? source : void 0
435
+ });
436
+ if (logs.length === 0) {
437
+ sendMcpResult(
438
+ res,
439
+ id,
440
+ `\u5F53\u524D\u6CA1\u6709\u7B26\u5408\u6761\u4EF6\u7684\u65E5\u5FD7\uFF08\u7F13\u51B2\u533A\u5171 ${buffer.size()} \u6761\uFF09\u3002
441
+
442
+ \u5EFA\u8BAE\uFF1A
443
+ - \u4E0D\u6307\u5B9A\u53C2\u6570\u83B7\u53D6\u6240\u6709\u65E5\u5FD7
444
+ - \u4F7F\u7528 level=error,warn \u83B7\u53D6\u9519\u8BEF\u548C\u8B66\u544A`,
445
+ sessionId
446
+ );
447
+ return;
448
+ }
449
+ const formattedLogs = logs.map((entry) => {
450
+ const time = new Date(entry.timestamp).toLocaleTimeString();
451
+ const levelIcon = entry.level === "error" ? "\u274C" : entry.level === "warn" ? "\u26A0\uFE0F" : entry.level === "info" ? "\u2139\uFE0F" : "";
452
+ return `${time} ${levelIcon} ${entry.message}`;
453
+ }).join("\n");
454
+ sendMcpResult(
455
+ res,
456
+ id,
457
+ `Vite \u5F00\u53D1\u670D\u52A1\u5668\u65E5\u5FD7\uFF08${logs.length}/${buffer.size()} \u6761\uFF09\uFF1A
458
+
459
+ ${formattedLogs}`,
460
+ sessionId
461
+ );
462
+ }
463
+ function parseProcessLevelFilter(level) {
464
+ if (typeof level !== "string" || !level.trim()) return void 0;
465
+ const levels = level.split(",").map((l) => l.trim()).filter(Boolean);
466
+ return levels.length ? levels : void 0;
467
+ }
468
+ function buildServiceLogTools(logFiles) {
469
+ return logFiles.map((cfg) => ({
470
+ name: `logs-devtools_${cfg.name}_logs`,
471
+ description: `\u83B7\u53D6 ${cfg.name} \u7684\u65E5\u5FD7\u3002
472
+
473
+ **\u4F55\u65F6\u4F7F\u7528\u6B64\u5DE5\u5177**\uFF1A
474
+ ${cfg.description}
475
+
476
+ **\u65E5\u5FD7\u5185\u5BB9**\uFF1A
477
+ - \u6765\u81EA\u65E5\u5FD7\u6587\u4EF6 ${cfg.path} \u7684\u5B9E\u65F6\u65E5\u5FD7
478
+ - \u9ED8\u8BA4\u8FD4\u56DE\u6700\u8FD1 200 \u884C\u65E5\u5FD7`,
479
+ inputSchema: {
480
+ type: "object",
481
+ properties: {
482
+ level: {
483
+ type: "string",
484
+ description: "\u65E5\u5FD7\u7EA7\u522B\u8FC7\u6EE4\uFF1Aerror(\u9519\u8BEF)\u3001warn(\u8B66\u544A)\u3001info(\u4FE1\u606F)\u3002\u591A\u4E2A\u7528\u9017\u53F7\u5206\u9694\uFF0C\u5982 'error,warn'"
485
+ },
486
+ limit: {
487
+ type: "integer",
488
+ minimum: 1,
489
+ maximum: 200,
490
+ default: 50,
491
+ description: "\u8FD4\u56DE\u6761\u6570\uFF0C\u9ED8\u8BA4 50\uFF0C\u6700\u5927 200"
492
+ }
493
+ }
494
+ }
495
+ }));
496
+ }
497
+ function isServiceLogTool(toolName, logFiles) {
498
+ return logFiles.some((cfg) => `logs-devtools_${cfg.name}_logs` === toolName);
499
+ }
500
+ async function handleServiceLogsTool(res, id, toolName, args, logFiles, projectRoot, sessionId) {
501
+ try {
502
+ const cfg = logFiles.find((c) => `logs-devtools_${c.name}_logs` === toolName);
503
+ if (!cfg) {
504
+ sendMcpError(res, id, -32601, `Tool not found: ${toolName}`, sessionId);
505
+ return;
506
+ }
507
+ const { level, limit } = args;
508
+ const requestedLimit = typeof limit === "number" ? limit : 50;
509
+ const entries = await (0, import_node.readLogFileTail)({
510
+ name: cfg.name,
511
+ filePath: cfg.path,
512
+ projectRoot,
513
+ lines: Math.max(requestedLimit * 3, 500),
514
+ level: parseFileLevelFilter(level),
515
+ limit: requestedLimit
516
+ });
517
+ if (entries.length === 0) {
518
+ sendMcpResult(
519
+ res,
520
+ id,
521
+ `\u5F53\u524D\u6CA1\u6709\u7B26\u5408\u6761\u4EF6\u7684\u65E5\u5FD7\u3002
522
+
523
+ \u5EFA\u8BAE\uFF1A
524
+ - \u4E0D\u6307\u5B9A\u53C2\u6570\u83B7\u53D6\u6240\u6709\u65E5\u5FD7
525
+ - \u4F7F\u7528 level=error,warn \u83B7\u53D6\u9519\u8BEF\u548C\u8B66\u544A`,
526
+ sessionId
527
+ );
528
+ return;
529
+ }
530
+ const formattedLogs = entries.map((entry) => {
531
+ const levelIcon = entry.level === "error" ? "\u274C" : entry.level === "warn" ? "\u26A0\uFE0F" : "\u2139\uFE0F";
532
+ return `${levelIcon} ${entry.message}`;
533
+ }).join("\n");
534
+ sendMcpResult(
535
+ res,
536
+ id,
537
+ `${cfg.name} \u65E5\u5FD7\uFF08${entries.length} \u6761\uFF09\uFF1A
538
+
539
+ ${formattedLogs}`,
540
+ sessionId
541
+ );
542
+ } catch (e) {
543
+ log.debug("handleServiceLogsTool error", { error: e.message });
544
+ sendMcpError(res, id, -32603, `\u8BFB\u53D6\u65E5\u5FD7\u5931\u8D25: ${e.message}`, sessionId);
545
+ }
546
+ }
547
+ function parseFileLevelFilter(level) {
548
+ if (typeof level !== "string" || !level.trim()) return void 0;
549
+ const levels = level.split(",").map((l) => l.trim()).filter(Boolean);
550
+ return levels.length ? levels : void 0;
551
+ }
552
+ async function handleForward(res, body, mcp) {
553
+ try {
554
+ const responseText = await mcp.forward(body);
555
+ sendMcpJson(res, 200, responseText, mcp.sessionId);
556
+ } catch (e) {
557
+ log.debug("handleForward error", { error: e.message });
558
+ sendMcpError(res, null, -32603, `MCP \u8C03\u7528\u5931\u8D25: ${e.message}`, mcp.sessionId);
559
+ }
560
+ }
561
+ function sendMcpResult(res, id, text, sessionId) {
562
+ sendMcpJson(
563
+ res,
564
+ 200,
565
+ {
566
+ jsonrpc: "2.0",
567
+ id,
568
+ result: { content: [{ type: "text", text }] }
569
+ },
570
+ sessionId
571
+ );
572
+ }
573
+ function sendMcpError(res, id, code, message, sessionId) {
574
+ sendMcpJson(
575
+ res,
576
+ 200,
577
+ {
578
+ jsonrpc: "2.0",
579
+ id,
580
+ error: { code, message }
581
+ },
582
+ sessionId
583
+ );
584
+ }
585
+ function sendMcpJson(res, statusCode, body, sessionId) {
586
+ const headers = { "Content-Type": "application/json" };
587
+ if (sessionId) headers["Mcp-Session-Id"] = sessionId;
588
+ res.writeHead(statusCode, headers);
589
+ res.end(typeof body === "string" ? body : JSON.stringify(body));
590
+ }
591
+ function readBody(req, maxSize = 1024 * 1024) {
592
+ return new Promise((resolve, reject) => {
593
+ let body = "";
594
+ req.on("data", (chunk) => {
595
+ body += chunk.toString();
596
+ if (body.length > maxSize) {
597
+ req.destroy();
598
+ reject(new Error("Request body too large"));
599
+ }
600
+ });
601
+ req.on("end", () => resolve(body));
602
+ req.on("error", reject);
603
+ });
604
+ }
605
+ function tryParseRequest(body) {
606
+ try {
607
+ const data = JSON.parse(body);
608
+ return { method: data.method || "unknown", id: data.id ?? null };
609
+ } catch {
610
+ return { method: "unknown", id: null };
611
+ }
612
+ }
613
+ function tryParseParams(body) {
614
+ try {
615
+ return JSON.parse(body).params ?? null;
616
+ } catch {
617
+ return null;
618
+ }
619
+ }
620
+ // Annotate the CommonJS export names for ESM import in node:
621
+ 0 && (module.exports = {
622
+ MCP_API_PATH,
623
+ setupMcpEndpoint
624
+ });
@@ -0,0 +1,6 @@
1
+ import type { ViteDevServer } from "vite";
2
+ import type { LogFileConfig, PageContext } from "@aipanel/core";
3
+ import { MCP_API_PATH } from "@aipanel/core";
4
+ import { McpProxy } from "../core/mcp-proxy";
5
+ export { MCP_API_PATH };
6
+ export declare function setupMcpEndpoint(server: ViteDevServer, mcp: McpProxy, getPageContext: () => PageContext, logFiles?: LogFileConfig[]): void;