vite-plugin-aipanel 1.2.8 → 1.2.10
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/es/core/chrome-project.d.ts +15 -0
- package/es/core/chrome-project.mjs +13 -0
- package/es/core/mcp-chrome.d.ts +12 -8
- package/es/core/mcp-chrome.mjs +52 -10
- package/es/core/mcp-proxy.d.ts +21 -1
- package/es/core/mcp-proxy.mjs +83 -12
- package/es/core/mcp-tools.d.ts +51 -3
- package/es/core/mcp-tools.mjs +109 -659
- package/es/core/official-meta.d.ts +9 -0
- package/es/core/official-meta.mjs +62 -0
- package/es/core/official-tools.d.ts +7 -0
- package/es/core/official-tools.mjs +54 -0
- package/es/core/proxy-server.mjs +16 -13
- package/es/core/service.mjs +4 -5
- package/es/endpoints/context.mjs +2 -2
- package/es/endpoints/host-events.mjs +1 -2
- package/es/endpoints/index.d.ts +2 -2
- package/es/endpoints/index.mjs +2 -2
- package/es/endpoints/mcp.d.ts +2 -2
- package/es/endpoints/mcp.mjs +116 -87
- package/es/endpoints/sse.mjs +3 -3
- package/es/endpoints/vue-devtools.d.ts +5 -2
- package/es/endpoints/vue-devtools.mjs +3 -4
- package/es/index.mjs +29 -6
- package/lib/client.js +2380 -2369
- package/lib/core/chrome-project.cjs +36 -0
- package/lib/core/chrome-project.d.ts +15 -0
- package/lib/core/mcp-chrome.cjs +64 -10
- package/lib/core/mcp-chrome.d.ts +12 -8
- package/lib/core/mcp-proxy.cjs +87 -13
- package/lib/core/mcp-proxy.d.ts +21 -1
- package/lib/core/mcp-tools.cjs +124 -660
- package/lib/core/mcp-tools.d.ts +51 -3
- package/lib/core/official-meta.cjs +85 -0
- package/lib/core/official-meta.d.ts +9 -0
- package/lib/core/official-tools.cjs +70 -0
- package/lib/core/official-tools.d.ts +7 -0
- package/lib/core/proxy-server.cjs +16 -13
- package/lib/core/service.cjs +4 -5
- package/lib/endpoints/context.cjs +1 -1
- package/lib/endpoints/host-events.cjs +0 -1
- package/lib/endpoints/index.cjs +2 -2
- package/lib/endpoints/index.d.ts +2 -2
- package/lib/endpoints/mcp.cjs +114 -85
- package/lib/endpoints/mcp.d.ts +2 -2
- package/lib/endpoints/sse.cjs +2 -2
- package/lib/endpoints/vue-devtools.cjs +4 -5
- package/lib/endpoints/vue-devtools.d.ts +5 -2
- package/lib/index.cjs +29 -7
- package/package.json +10 -7
- package/es/utils/format-bridge.d.ts +0 -9
- package/es/utils/format-bridge.mjs +0 -80
- package/es/utils/system.d.ts +0 -3
- package/es/utils/system.mjs +0 -76
- package/lib/utils/format-bridge.cjs +0 -102
- package/lib/utils/format-bridge.d.ts +0 -9
- package/lib/utils/system.cjs +0 -110
- package/lib/utils/system.d.ts +0 -3
|
@@ -0,0 +1,36 @@
|
|
|
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 chrome_project_exports = {};
|
|
19
|
+
__export(chrome_project_exports, {
|
|
20
|
+
resolveProjectScope: () => resolveProjectScope
|
|
21
|
+
});
|
|
22
|
+
module.exports = __toCommonJS(chrome_project_exports);
|
|
23
|
+
var import_mcp_chrome = require("./mcp-chrome.cjs");
|
|
24
|
+
function resolveProjectScope(server, project) {
|
|
25
|
+
const auto = (0, import_mcp_chrome.getProjectOrigins)(server);
|
|
26
|
+
const operationsOrigins = [.../* @__PURE__ */ new Set([...auto, ...project?.allowOrigins ?? []])];
|
|
27
|
+
return {
|
|
28
|
+
origins: auto,
|
|
29
|
+
operationsOrigins,
|
|
30
|
+
includeExtensions: project?.includeExtensionPages === true
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
34
|
+
0 && (module.exports = {
|
|
35
|
+
resolveProjectScope
|
|
36
|
+
});
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 项目边界策略解析:在请求时把 chromeMcp.project 与 vite 自动 origins 合并为一份体。
|
|
3
|
+
* 所有边界判定(页面归属 / 导航目标 / 扩展页)均只读此解析结果,单一来源。
|
|
4
|
+
*/
|
|
5
|
+
import type { ViteDevServer } from "vite";
|
|
6
|
+
import type { ChromeProjectOptions } from "@aipanel/core";
|
|
7
|
+
export interface ProjectScope {
|
|
8
|
+
/** 项目页 origins(自动,“项目页全局一个”分类 + vue-devtools 桥可用范围) */
|
|
9
|
+
origins: string[];
|
|
10
|
+
/** 可操作范围 = 项目页 ∪ allowOrigins:chrome 页面级 list/current/pageId 校验、navigate/new 目标用 */
|
|
11
|
+
operationsOrigins: string[];
|
|
12
|
+
/** 是否允许 chrome-extension:// 页面纳入可操作范围 */
|
|
13
|
+
includeExtensions: boolean;
|
|
14
|
+
}
|
|
15
|
+
export declare function resolveProjectScope(server: ViteDevServer, project?: ChromeProjectOptions): ProjectScope;
|
package/lib/core/mcp-chrome.cjs
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
var __create = Object.create;
|
|
1
2
|
var __defProp = Object.defineProperty;
|
|
2
3
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
4
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
4
6
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
7
|
var __export = (target, all) => {
|
|
6
8
|
for (var name in all)
|
|
@@ -14,17 +16,28 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
14
16
|
}
|
|
15
17
|
return to;
|
|
16
18
|
};
|
|
19
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
20
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
21
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
22
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
23
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
24
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
25
|
+
mod
|
|
26
|
+
));
|
|
17
27
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
18
28
|
var mcp_chrome_exports = {};
|
|
19
29
|
__export(mcp_chrome_exports, {
|
|
20
30
|
extractEvalValue: () => extractEvalValue,
|
|
21
31
|
getProjectOrigins: () => getProjectOrigins,
|
|
32
|
+
isOriginEntryMatch: () => isOriginEntryMatch,
|
|
33
|
+
isPageAllowed: () => isPageAllowed,
|
|
22
34
|
isProjectPage: () => isProjectPage,
|
|
23
35
|
parseListPages: () => parseListPages,
|
|
24
36
|
resolveChromePageId: () => resolveChromePageId,
|
|
25
37
|
validatePageId: () => validatePageId
|
|
26
38
|
});
|
|
27
39
|
module.exports = __toCommonJS(mcp_chrome_exports);
|
|
40
|
+
var import_picomatch = __toESM(require("picomatch"));
|
|
28
41
|
var import_node = require("@aipanel/core/node");
|
|
29
42
|
const log = (0, import_node.createLogger)("McpChrome");
|
|
30
43
|
function getProjectOrigins(server) {
|
|
@@ -34,8 +47,45 @@ function getProjectOrigins(server) {
|
|
|
34
47
|
log.debug("project origins", { origins });
|
|
35
48
|
return origins;
|
|
36
49
|
}
|
|
50
|
+
const entryMatcherCache = /* @__PURE__ */ new Map();
|
|
51
|
+
function parseRegexEntry(entry) {
|
|
52
|
+
if (!entry.startsWith("/")) return void 0;
|
|
53
|
+
const lastSlash = entry.lastIndexOf("/");
|
|
54
|
+
if (lastSlash <= 0) return void 0;
|
|
55
|
+
const source = entry.slice(1, lastSlash);
|
|
56
|
+
const flags = entry.slice(lastSlash + 1);
|
|
57
|
+
if (!/^[a-z]*$/.test(flags)) return void 0;
|
|
58
|
+
try {
|
|
59
|
+
return { kind: "regex", re: new RegExp(source, flags) };
|
|
60
|
+
} catch {
|
|
61
|
+
return void 0;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
function compileEntryMatcher(entry) {
|
|
65
|
+
const cached = entryMatcherCache.get(entry);
|
|
66
|
+
if (cached) return cached;
|
|
67
|
+
let compiled = { kind: "prefix" };
|
|
68
|
+
const regexMatcher = parseRegexEntry(entry);
|
|
69
|
+
if (regexMatcher) {
|
|
70
|
+
compiled = regexMatcher;
|
|
71
|
+
} else if (import_picomatch.default.scan(entry).isGlob) {
|
|
72
|
+
compiled = { kind: "glob", match: (0, import_picomatch.default)(entry) };
|
|
73
|
+
}
|
|
74
|
+
entryMatcherCache.set(entry, compiled);
|
|
75
|
+
return compiled;
|
|
76
|
+
}
|
|
77
|
+
function isOriginEntryMatch(url, entry) {
|
|
78
|
+
const matcher = compileEntryMatcher(entry);
|
|
79
|
+
if (matcher.kind === "regex") return matcher.re.test(url);
|
|
80
|
+
if (matcher.kind === "glob") return matcher.match(url);
|
|
81
|
+
return url.startsWith(entry);
|
|
82
|
+
}
|
|
37
83
|
function isProjectPage(url, origins) {
|
|
38
|
-
return origins.some((
|
|
84
|
+
return origins.some((entry) => isOriginEntryMatch(url, entry));
|
|
85
|
+
}
|
|
86
|
+
function isPageAllowed(url, origins, includeExtensions) {
|
|
87
|
+
if (origins.some((entry) => isOriginEntryMatch(url, entry))) return true;
|
|
88
|
+
return includeExtensions && url.startsWith("chrome-extension://");
|
|
39
89
|
}
|
|
40
90
|
function parseListPages(text) {
|
|
41
91
|
const pages = [];
|
|
@@ -66,29 +116,31 @@ function extractEvalValue(text) {
|
|
|
66
116
|
return jsonStr.trim();
|
|
67
117
|
}
|
|
68
118
|
}
|
|
69
|
-
async function validatePageId(mcp, pageId,
|
|
119
|
+
async function validatePageId(mcp, pageId, operationsOrigins, includeExtensions = false) {
|
|
70
120
|
const listResult = await mcp.callChromeDevTool("list_pages", {});
|
|
71
121
|
if (listResult?.error || !listResult?.result) {
|
|
72
122
|
return {
|
|
73
123
|
valid: false,
|
|
74
124
|
error: listResult?.error?.message ?? "\u65E0\u6CD5\u83B7\u53D6 Chrome \u9875\u9762\u5217\u8868\uFF0C\u8BF7\u786E\u8BA4 Chrome DevTools \u5DF2\u8FDE\u63A5",
|
|
75
|
-
|
|
125
|
+
allowedPages: []
|
|
76
126
|
};
|
|
77
127
|
}
|
|
78
128
|
const text = listResult?.result?.content?.[0]?.text;
|
|
79
129
|
const allPages = text ? parseListPages(text) : [];
|
|
80
|
-
const
|
|
81
|
-
|
|
130
|
+
const allowedPages = allPages.filter(
|
|
131
|
+
(p) => isPageAllowed(p.url, operationsOrigins, includeExtensions)
|
|
132
|
+
);
|
|
133
|
+
const isValid = allowedPages.some((p) => p.pageId === pageId);
|
|
82
134
|
if (!isValid) {
|
|
83
135
|
return {
|
|
84
136
|
valid: false,
|
|
85
|
-
error: `pageId ${pageId} \
|
|
86
|
-
|
|
137
|
+
error: `pageId ${pageId} \u4E0D\u5728\u53EF\u64CD\u4F5C\u8303\u56F4\uFF08\u9879\u76EE\u9875\u6216 allowOrigins \u767D\u540D\u5355\u9875\uFF09\uFF0C\u8BF7\u5148\u7528 list_pages \u83B7\u53D6\u6709\u6548\u9875\u9762 ID`,
|
|
138
|
+
allowedPages
|
|
87
139
|
};
|
|
88
140
|
}
|
|
89
|
-
return { valid: true,
|
|
141
|
+
return { valid: true, allowedPages };
|
|
90
142
|
}
|
|
91
|
-
async function resolveChromePageId(mcp, url, title,
|
|
143
|
+
async function resolveChromePageId(mcp, url, title, operationsOrigins, sessionId, pages, chromeSelectedPageId) {
|
|
92
144
|
if (!mcp || !mcp.isRunning) {
|
|
93
145
|
const reason = !mcp ? "MCP \u6A21\u5757\u672A\u521D\u59CB\u5316" : "Chrome DevTools MCP \u8FDB\u7A0B\u672A\u542F\u52A8";
|
|
94
146
|
log.debug(`resolveChromePageId: ${reason}`);
|
|
@@ -106,7 +158,7 @@ async function resolveChromePageId(mcp, url, title, projectOrigins, sessionId, p
|
|
|
106
158
|
}
|
|
107
159
|
const allPages = parseListPages(text);
|
|
108
160
|
chromeSelectedPageId = allPages.find((p) => p.selected)?.pageId;
|
|
109
|
-
pages = allPages.filter((p) => isProjectPage(p.url,
|
|
161
|
+
pages = allPages.filter((p) => isProjectPage(p.url, operationsOrigins));
|
|
110
162
|
}
|
|
111
163
|
log.debug("resolveChromePageId: list_pages result", {
|
|
112
164
|
pages: pages.map((p) => ({ id: p.pageId, url: p.url, title: p.title.substring(0, 40) })),
|
|
@@ -154,6 +206,8 @@ async function resolveChromePageId(mcp, url, title, projectOrigins, sessionId, p
|
|
|
154
206
|
0 && (module.exports = {
|
|
155
207
|
extractEvalValue,
|
|
156
208
|
getProjectOrigins,
|
|
209
|
+
isOriginEntryMatch,
|
|
210
|
+
isPageAllowed,
|
|
157
211
|
isProjectPage,
|
|
158
212
|
parseListPages,
|
|
159
213
|
resolveChromePageId,
|
package/lib/core/mcp-chrome.d.ts
CHANGED
|
@@ -7,8 +7,12 @@ import type { ViteDevServer } from "vite";
|
|
|
7
7
|
import type { McpProxy } from "./mcp-proxy";
|
|
8
8
|
/** 从 Vite 服务器解析的所有 URL 中提取项目 origin 列表 */
|
|
9
9
|
export declare function getProjectOrigins(server: ViteDevServer): string[];
|
|
10
|
-
/** 判断页面 URL
|
|
10
|
+
/** 判断页面 URL 是否命中某个范围条目(allowOrigins 三种写法,见模块注释) */
|
|
11
|
+
export declare function isOriginEntryMatch(url: string, entry: string): boolean;
|
|
12
|
+
/** 判断页面 URL 是否命中某组范围条目(可为精确 origin / 通配符 / 正则) */
|
|
11
13
|
export declare function isProjectPage(url: string, origins: string[]): boolean;
|
|
14
|
+
/** 判断页面 URL 是否属于可操作范围(范围条目,或启用时的扩展页) */
|
|
15
|
+
export declare function isPageAllowed(url: string, origins: string[], includeExtensions: boolean): boolean;
|
|
12
16
|
export interface PageInfo {
|
|
13
17
|
pageId: number;
|
|
14
18
|
url: string;
|
|
@@ -28,18 +32,18 @@ type PageIdResult = {
|
|
|
28
32
|
error: string;
|
|
29
33
|
};
|
|
30
34
|
/**
|
|
31
|
-
* 校验 pageId
|
|
35
|
+
* 校验 pageId 是否属于可操作范围(项目页 ∪ allowOrigins)
|
|
32
36
|
*
|
|
33
|
-
* 调用 list_pages →
|
|
37
|
+
* 调用 list_pages → 过滤允许页面 → 检查 pageId 是否在范围内。
|
|
34
38
|
* 供 MCP 代理层和 Vue DevTools 端点共用。
|
|
35
39
|
*/
|
|
36
|
-
export declare function validatePageId(mcp: McpProxy, pageId: number,
|
|
40
|
+
export declare function validatePageId(mcp: McpProxy, pageId: number, operationsOrigins: string[], includeExtensions?: boolean): Promise<{
|
|
37
41
|
valid: true;
|
|
38
|
-
|
|
42
|
+
allowedPages: PageInfo[];
|
|
39
43
|
} | {
|
|
40
44
|
valid: false;
|
|
41
45
|
error: string;
|
|
42
|
-
|
|
46
|
+
allowedPages: PageInfo[];
|
|
43
47
|
}>;
|
|
44
48
|
/**
|
|
45
49
|
* 通过 MCP 解析当前页面对应的 Chrome DevTools pageId
|
|
@@ -50,7 +54,7 @@ export declare function validatePageId(mcp: McpProxy, pageId: number, projectOri
|
|
|
50
54
|
*
|
|
51
55
|
* 失败时返回具体原因,由调用方透传给 Agent。
|
|
52
56
|
*/
|
|
53
|
-
export declare function resolveChromePageId(mcp: McpProxy | undefined, url: string, title: string,
|
|
54
|
-
/** Chrome 当前选中的 pageId
|
|
57
|
+
export declare function resolveChromePageId(mcp: McpProxy | undefined, url: string, title: string, operationsOrigins: string[], sessionId?: string, pages?: PageInfo[],
|
|
58
|
+
/** Chrome 当前选中的 pageId(调用方传入,避免过滤后丢失范围外页面信息) */
|
|
55
59
|
chromeSelectedPageId?: number): Promise<PageIdResult>;
|
|
56
60
|
export {};
|
package/lib/core/mcp-proxy.cjs
CHANGED
|
@@ -45,7 +45,10 @@ var __privateWrapper = (obj, member, setter, getter) => ({
|
|
|
45
45
|
});
|
|
46
46
|
var mcp_proxy_exports = {};
|
|
47
47
|
__export(mcp_proxy_exports, {
|
|
48
|
-
|
|
48
|
+
CORE_MCP_ARGS: () => CORE_MCP_ARGS,
|
|
49
|
+
McpProxy: () => McpProxy,
|
|
50
|
+
classifyUserMcpArgs: () => classifyUserMcpArgs,
|
|
51
|
+
filterUserMcpArgs: () => filterUserMcpArgs
|
|
49
52
|
});
|
|
50
53
|
module.exports = __toCommonJS(mcp_proxy_exports);
|
|
51
54
|
var import_node_child_process = require("node:child_process");
|
|
@@ -53,8 +56,71 @@ var import_node_readline = require("node:readline");
|
|
|
53
56
|
var import_node_crypto = __toESM(require("node:crypto"));
|
|
54
57
|
var import_node_path = __toESM(require("node:path"));
|
|
55
58
|
var import_node = require("@aipanel/core/node");
|
|
56
|
-
var _proc, _rl, _messageId, _internalIdBase, _pending, _args, _startPromise, _lastExit, _stderrTail, _idleTimer, _idleTimeout, _McpProxy_instances, doStart_fn, formatNotAvailable_fn, resetIdleTimer_fn;
|
|
59
|
+
var _proc, _rl, _messageId, _internalIdBase, _pending, _args, _env, _startPromise, _lastExit, _stderrTail, _idleTimer, _idleTimeout, _McpProxy_instances, doStart_fn, formatNotAvailable_fn, resetIdleTimer_fn;
|
|
57
60
|
const log = (0, import_node.createLogger)("McpProxy");
|
|
61
|
+
const CORE_MCP_ARGS = [
|
|
62
|
+
"--auto-connect",
|
|
63
|
+
"--no-usage-statistics",
|
|
64
|
+
"--no-performance-crux",
|
|
65
|
+
// chrome-devtools-mcp >=1.8.0 默认开启 pageIdRouting(要求每个页面级工具都传 pageId)。
|
|
66
|
+
// 代理层已自行校验 pageId 并用 select_page 选中目标页面后再转发,故显式关闭,
|
|
67
|
+
// 避免底层工具 schema 强制必填 pageId 导致转发时的参数校验失败。
|
|
68
|
+
"--no-page-id-routing",
|
|
69
|
+
// 客户端未协商 roots,官方默认把文件工具限制在 OS 临时目录;
|
|
70
|
+
// 为保持 upload_file “不限制项目目录”的设计,显式允许任意路径
|
|
71
|
+
// (工具层仍受白名单 + pageId 归属约束)。
|
|
72
|
+
"--allow-unrestricted-paths"
|
|
73
|
+
];
|
|
74
|
+
const PROTECTED_FLAGS = /* @__PURE__ */ new Set([
|
|
75
|
+
"auto-connect",
|
|
76
|
+
"usage-statistics",
|
|
77
|
+
"performance-crux",
|
|
78
|
+
"page-id-routing"
|
|
79
|
+
]);
|
|
80
|
+
const MANAGED_FLAGS = /* @__PURE__ */ new Set([
|
|
81
|
+
"slim",
|
|
82
|
+
"category-extensions",
|
|
83
|
+
"category-pwa",
|
|
84
|
+
"category-experimental-third-party",
|
|
85
|
+
"category-experimental-webmcp",
|
|
86
|
+
"category-performance",
|
|
87
|
+
"category-network",
|
|
88
|
+
"category-emulation",
|
|
89
|
+
"experimental-vision",
|
|
90
|
+
"experimental-interop-tools",
|
|
91
|
+
"experimental-memory",
|
|
92
|
+
"experimental-screencast",
|
|
93
|
+
"experimental-structured-content",
|
|
94
|
+
"experimental-include-all-pages",
|
|
95
|
+
"allow-unrestricted-paths"
|
|
96
|
+
]);
|
|
97
|
+
function canonicalFlagName(arg) {
|
|
98
|
+
let flag = arg.trim();
|
|
99
|
+
if (!flag.startsWith("-")) return null;
|
|
100
|
+
flag = flag.replace(/^--?/, "").split("=")[0] ?? "";
|
|
101
|
+
if (flag.startsWith("no-")) flag = flag.slice(3);
|
|
102
|
+
return flag || null;
|
|
103
|
+
}
|
|
104
|
+
function classifyUserMcpArgs(userArgs) {
|
|
105
|
+
const kept = [];
|
|
106
|
+
const dropped = [];
|
|
107
|
+
for (const arg of userArgs) {
|
|
108
|
+
const name = canonicalFlagName(arg);
|
|
109
|
+
if (name === null) {
|
|
110
|
+
kept.push(arg);
|
|
111
|
+
} else if (PROTECTED_FLAGS.has(name)) {
|
|
112
|
+
dropped.push({ arg, kind: "protected" });
|
|
113
|
+
} else if (MANAGED_FLAGS.has(name)) {
|
|
114
|
+
dropped.push({ arg, kind: "managed" });
|
|
115
|
+
} else {
|
|
116
|
+
kept.push(arg);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
return { kept, dropped };
|
|
120
|
+
}
|
|
121
|
+
function filterUserMcpArgs(userArgs) {
|
|
122
|
+
return classifyUserMcpArgs(userArgs).kept;
|
|
123
|
+
}
|
|
58
124
|
function resolveChromeDevToolsMcpBin() {
|
|
59
125
|
const pluginDir = (0, import_node.resolvePackageDir)("vite-plugin-aipanel");
|
|
60
126
|
const require2 = (0, import_node.createPackageRequire)(pluginDir);
|
|
@@ -74,6 +140,7 @@ class McpProxy {
|
|
|
74
140
|
__privateAdd(this, _internalIdBase, 1e6);
|
|
75
141
|
__privateAdd(this, _pending, /* @__PURE__ */ new Map());
|
|
76
142
|
__privateAdd(this, _args);
|
|
143
|
+
__privateAdd(this, _env);
|
|
77
144
|
__privateAdd(this, _startPromise, null);
|
|
78
145
|
/** 最近一次进程退出信息,用于生成精确错误(无退出记录时为 null) */
|
|
79
146
|
__privateAdd(this, _lastExit, null);
|
|
@@ -82,15 +149,17 @@ class McpProxy {
|
|
|
82
149
|
__privateAdd(this, _idleTimer, null);
|
|
83
150
|
__privateAdd(this, _idleTimeout);
|
|
84
151
|
__publicField(this, "sessionId");
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
]
|
|
152
|
+
const userArgs = options.userArgs ?? [];
|
|
153
|
+
const { kept, dropped } = classifyUserMcpArgs(userArgs);
|
|
154
|
+
if (dropped.length > 0) {
|
|
155
|
+
log.warn(
|
|
156
|
+
"chrome MCP \u7528\u6237\u53C2\u6570\u4E0E\u53D7\u4FDD\u62A4/\u7B56\u7565\u63A5\u7BA1 flag \u51B2\u7A81\uFF0C\u5DF2\u5FFD\u7565\uFF1B\u8BF7\u7528 chromeMcp.project \u914D\u7F6E\u5BF9\u5E94\u884C\u4E3A",
|
|
157
|
+
{ dropped }
|
|
158
|
+
);
|
|
159
|
+
}
|
|
160
|
+
const managedArgs = options.managedArgs ?? [];
|
|
161
|
+
__privateSet(this, _args, [...kept, ...managedArgs, ...CORE_MCP_ARGS]);
|
|
162
|
+
__privateSet(this, _env, options.env);
|
|
94
163
|
__privateSet(this, _idleTimeout, options.idleTimeout ?? 0);
|
|
95
164
|
this.sessionId = import_node_crypto.default.randomUUID();
|
|
96
165
|
}
|
|
@@ -184,6 +253,7 @@ _messageId = new WeakMap();
|
|
|
184
253
|
_internalIdBase = new WeakMap();
|
|
185
254
|
_pending = new WeakMap();
|
|
186
255
|
_args = new WeakMap();
|
|
256
|
+
_env = new WeakMap();
|
|
187
257
|
_startPromise = new WeakMap();
|
|
188
258
|
_lastExit = new WeakMap();
|
|
189
259
|
_stderrTail = new WeakMap();
|
|
@@ -197,7 +267,8 @@ doStart_fn = async function() {
|
|
|
197
267
|
__privateSet(this, _lastExit, null);
|
|
198
268
|
__privateSet(this, _stderrTail, []);
|
|
199
269
|
__privateSet(this, _proc, (0, import_node_child_process.spawn)(process.execPath, [binPath, ...__privateGet(this, _args)], {
|
|
200
|
-
stdio: ["pipe", "pipe", "pipe"]
|
|
270
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
271
|
+
env: { ...process.env, ...__privateGet(this, _env) }
|
|
201
272
|
}));
|
|
202
273
|
log.debug("Using local chrome-devtools-mcp");
|
|
203
274
|
} catch {
|
|
@@ -287,5 +358,8 @@ resetIdleTimer_fn = function() {
|
|
|
287
358
|
};
|
|
288
359
|
// Annotate the CommonJS export names for ESM import in node:
|
|
289
360
|
0 && (module.exports = {
|
|
290
|
-
|
|
361
|
+
CORE_MCP_ARGS,
|
|
362
|
+
McpProxy,
|
|
363
|
+
classifyUserMcpArgs,
|
|
364
|
+
filterUserMcpArgs
|
|
291
365
|
});
|
package/lib/core/mcp-proxy.d.ts
CHANGED
|
@@ -1,5 +1,25 @@
|
|
|
1
|
+
/** chrome-devtools-mcp 的核心受保护参数(用户不可覆盖;始终最后注入确保生效) */
|
|
2
|
+
export declare const CORE_MCP_ARGS: readonly ["--auto-connect", "--no-usage-statistics", "--no-performance-crux", "--no-page-id-routing", "--allow-unrestricted-paths"];
|
|
3
|
+
/** 过滤用户透传参数:剔除与核心受保护 flag 冲突的项,其余原样保留 */
|
|
4
|
+
export type McpArgDropKind = "protected" | "managed";
|
|
5
|
+
export interface McpArgDrop {
|
|
6
|
+
arg: string;
|
|
7
|
+
kind: McpArgDropKind;
|
|
8
|
+
}
|
|
9
|
+
/** 分类用户透传参数:保留可透传项,列出被剔除项及原因 */
|
|
10
|
+
export declare function classifyUserMcpArgs(userArgs: readonly string[]): {
|
|
11
|
+
kept: string[];
|
|
12
|
+
dropped: McpArgDrop[];
|
|
13
|
+
};
|
|
14
|
+
/** 过滤用户透传参数:剔除与核心受保护/策略接管 flag 冲突的项 */
|
|
15
|
+
export declare function filterUserMcpArgs(userArgs: readonly string[]): string[];
|
|
1
16
|
export interface McpProxyOptions {
|
|
2
|
-
|
|
17
|
+
/** 用户透传的额外 CLI 参数(追加;与核心受保护项冲突的会被剔除) */
|
|
18
|
+
userArgs?: string[];
|
|
19
|
+
/** 策略控制的内部注入参数(不经用户过滤,在用户参数之后、核心参数之前注入) */
|
|
20
|
+
managedArgs?: string[];
|
|
21
|
+
/** 用户透传的额外环境变量(合并到 process.env 之上) */
|
|
22
|
+
env?: Record<string, string>;
|
|
3
23
|
idleTimeout?: number;
|
|
4
24
|
}
|
|
5
25
|
export declare class McpProxy {
|