vite-plugin-aipanel 1.2.0 → 1.2.1
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 +1 -1
- package/es/core/mcp-proxy.mjs +52 -9
- package/lib/core/mcp-proxy.cjs +52 -9
- package/package.json +6 -6
package/README.md
CHANGED
|
@@ -36,7 +36,7 @@ Vite 插件会自动启动 AIPanel Web 服务并创建当前项目的 AI 会话
|
|
|
36
36
|
|
|
37
37
|
### 4. 安装浏览器扩展
|
|
38
38
|
|
|
39
|
-
1. [下载扩展包](https://github.com/code-farmer-i/vite-plugin-aipanel/raw/main/packages/extension/
|
|
39
|
+
1. [下载扩展包](https://github.com/code-farmer-i/vite-plugin-aipanel/raw/main/packages/extension/aipanel-assistant.zip)
|
|
40
40
|
2. 打开 Chrome,地址栏输入 `chrome://extensions/`
|
|
41
41
|
3. 打开右上角**「开发者模式」**开关
|
|
42
42
|
4. 解压下载的 `.zip`,点击**「加载已解压的扩展程序」**,选择解压后的文件夹
|
package/es/core/mcp-proxy.mjs
CHANGED
|
@@ -17,7 +17,7 @@ var __privateWrapper = (obj, member, setter, getter) => ({
|
|
|
17
17
|
return __privateGet(obj, member, getter);
|
|
18
18
|
}
|
|
19
19
|
});
|
|
20
|
-
var _proc, _rl, _messageId, _internalIdBase, _pending, _args, _startPromise, _idleTimer, _idleTimeout, _McpProxy_instances, doStart_fn, resetIdleTimer_fn;
|
|
20
|
+
var _proc, _rl, _messageId, _internalIdBase, _pending, _args, _startPromise, _lastExit, _stderrTail, _idleTimer, _idleTimeout, _McpProxy_instances, doStart_fn, formatNotAvailable_fn, resetIdleTimer_fn;
|
|
21
21
|
import { spawn } from "node:child_process";
|
|
22
22
|
import { createInterface } from "node:readline";
|
|
23
23
|
import crypto from "node:crypto";
|
|
@@ -44,6 +44,10 @@ class McpProxy {
|
|
|
44
44
|
__privateAdd(this, _pending, /* @__PURE__ */ new Map());
|
|
45
45
|
__privateAdd(this, _args);
|
|
46
46
|
__privateAdd(this, _startPromise, null);
|
|
47
|
+
/** 最近一次进程退出信息,用于生成精确错误(无退出记录时为 null) */
|
|
48
|
+
__privateAdd(this, _lastExit, null);
|
|
49
|
+
/** 捕获的 stderr 最近若干行,进程异常退出时作为诊断信息 */
|
|
50
|
+
__privateAdd(this, _stderrTail, []);
|
|
47
51
|
__privateAdd(this, _idleTimer, null);
|
|
48
52
|
__privateAdd(this, _idleTimeout);
|
|
49
53
|
__publicField(this, "sessionId");
|
|
@@ -61,14 +65,19 @@ class McpProxy {
|
|
|
61
65
|
async start() {
|
|
62
66
|
if (this.isRunning) return;
|
|
63
67
|
if (__privateGet(this, _startPromise)) return __privateGet(this, _startPromise);
|
|
64
|
-
|
|
65
|
-
|
|
68
|
+
const p = __privateMethod(this, _McpProxy_instances, doStart_fn).call(this);
|
|
69
|
+
__privateSet(this, _startPromise, p);
|
|
70
|
+
try {
|
|
71
|
+
await p;
|
|
72
|
+
} finally {
|
|
73
|
+
__privateSet(this, _startPromise, null);
|
|
74
|
+
}
|
|
66
75
|
}
|
|
67
76
|
/** 转发原始 JSON-RPC 请求,保留客户端 ID */
|
|
68
77
|
async forward(rawRequest) {
|
|
69
78
|
await this.start();
|
|
70
79
|
if (!__privateGet(this, _proc) || !__privateGet(this, _proc).stdin) {
|
|
71
|
-
throw new Error(
|
|
80
|
+
throw new Error(__privateMethod(this, _McpProxy_instances, formatNotAvailable_fn).call(this));
|
|
72
81
|
}
|
|
73
82
|
__privateMethod(this, _McpProxy_instances, resetIdleTimer_fn).call(this);
|
|
74
83
|
let msg;
|
|
@@ -93,7 +102,7 @@ class McpProxy {
|
|
|
93
102
|
async call(method, params = {}) {
|
|
94
103
|
await this.start();
|
|
95
104
|
if (!__privateGet(this, _proc) || !__privateGet(this, _proc).stdin) {
|
|
96
|
-
throw new Error(
|
|
105
|
+
throw new Error(__privateMethod(this, _McpProxy_instances, formatNotAvailable_fn).call(this));
|
|
97
106
|
}
|
|
98
107
|
__privateMethod(this, _McpProxy_instances, resetIdleTimer_fn).call(this);
|
|
99
108
|
const id = __privateGet(this, _internalIdBase) + ++__privateWrapper(this, _messageId)._;
|
|
@@ -141,6 +150,8 @@ _internalIdBase = new WeakMap();
|
|
|
141
150
|
_pending = new WeakMap();
|
|
142
151
|
_args = new WeakMap();
|
|
143
152
|
_startPromise = new WeakMap();
|
|
153
|
+
_lastExit = new WeakMap();
|
|
154
|
+
_stderrTail = new WeakMap();
|
|
144
155
|
_idleTimer = new WeakMap();
|
|
145
156
|
_idleTimeout = new WeakMap();
|
|
146
157
|
_McpProxy_instances = new WeakSet();
|
|
@@ -148,6 +159,8 @@ doStart_fn = async function() {
|
|
|
148
159
|
log.debug("Starting MCP process", { args: __privateGet(this, _args) });
|
|
149
160
|
try {
|
|
150
161
|
const binPath = resolveChromeDevToolsMcpBin();
|
|
162
|
+
__privateSet(this, _lastExit, null);
|
|
163
|
+
__privateSet(this, _stderrTail, []);
|
|
151
164
|
__privateSet(this, _proc, spawn(process.execPath, [binPath, ...__privateGet(this, _args)], {
|
|
152
165
|
stdio: ["pipe", "pipe", "pipe"]
|
|
153
166
|
}));
|
|
@@ -179,26 +192,56 @@ doStart_fn = async function() {
|
|
|
179
192
|
__privateGet(this, _proc).stderr?.on("data", (d) => {
|
|
180
193
|
const text = d.toString().trim();
|
|
181
194
|
if (!text || /No handler registered for issue code \w+/i.test(text)) return;
|
|
195
|
+
__privateGet(this, _stderrTail).push(...text.split("\n"));
|
|
196
|
+
if (__privateGet(this, _stderrTail).length > 20) __privateGet(this, _stderrTail).splice(0, __privateGet(this, _stderrTail).length - 20);
|
|
182
197
|
log.debug("[MCP stderr]", { text: text.substring(0, 200) });
|
|
183
198
|
});
|
|
184
|
-
__privateGet(this, _proc).on("close", (code) => {
|
|
185
|
-
|
|
199
|
+
__privateGet(this, _proc).on("close", (code, signal) => {
|
|
200
|
+
const exitDesc = `code ${code ?? "null"}${signal ? ` (signal ${signal})` : ""}`;
|
|
201
|
+
const abnormalExit = code !== null && code !== 0 || signal !== null && signal !== "SIGTERM";
|
|
202
|
+
if (abnormalExit) {
|
|
203
|
+
log.warn("MCP process exited abnormally", {
|
|
204
|
+
code,
|
|
205
|
+
signal,
|
|
206
|
+
stderrTail: __privateGet(this, _stderrTail).join("\n").slice(0, 500)
|
|
207
|
+
});
|
|
208
|
+
} else {
|
|
209
|
+
log.debug("MCP process closed", { code, signal });
|
|
210
|
+
}
|
|
211
|
+
__privateSet(this, _lastExit, { code, signal, stderrTail: __privateGet(this, _stderrTail).join("\n") });
|
|
186
212
|
for (const resolve of __privateGet(this, _pending).values()) {
|
|
187
|
-
resolve({ error: { code: -32e3, message: `MCP process exited with
|
|
213
|
+
resolve({ error: { code: -32e3, message: `MCP process exited with ${exitDesc}` } });
|
|
188
214
|
}
|
|
189
215
|
__privateGet(this, _pending).clear();
|
|
190
216
|
__privateSet(this, _proc, null);
|
|
191
217
|
__privateSet(this, _rl, null);
|
|
192
218
|
__privateSet(this, _startPromise, null);
|
|
193
219
|
});
|
|
194
|
-
await this.call("initialize", {
|
|
220
|
+
const initResult = await this.call("initialize", {
|
|
195
221
|
protocolVersion: "2024-11-05",
|
|
196
222
|
capabilities: {},
|
|
197
223
|
clientInfo: { name: "vite-plugin-aipanel", version: "1.0.0" }
|
|
198
224
|
});
|
|
225
|
+
if (!__privateGet(this, _proc)) {
|
|
226
|
+
throw new Error(__privateMethod(this, _McpProxy_instances, formatNotAvailable_fn).call(this));
|
|
227
|
+
}
|
|
228
|
+
if (initResult?.error) {
|
|
229
|
+
throw new Error(
|
|
230
|
+
`MCP initialize failed: ${initResult.error.message ?? JSON.stringify(initResult.error)}`
|
|
231
|
+
);
|
|
232
|
+
}
|
|
199
233
|
log.debug("MCP proxy ready");
|
|
200
234
|
__privateSet(this, _startPromise, null);
|
|
201
235
|
};
|
|
236
|
+
/** 生成 "MCP process not available" 的精确错误信息(包含最近一次退出原因与 stderr) */
|
|
237
|
+
formatNotAvailable_fn = function() {
|
|
238
|
+
const exit = __privateGet(this, _lastExit);
|
|
239
|
+
if (!exit) return "MCP process not available";
|
|
240
|
+
const exitDesc = `code ${exit.code ?? "null"}${exit.signal ? ` (signal ${exit.signal})` : ""}`;
|
|
241
|
+
const tail = exit.stderrTail ? `
|
|
242
|
+
stderr: ${exit.stderrTail}` : "";
|
|
243
|
+
return `MCP process not available (last exit ${exitDesc})${tail}`;
|
|
244
|
+
};
|
|
202
245
|
resetIdleTimer_fn = function() {
|
|
203
246
|
if (__privateGet(this, _idleTimeout) <= 0) return;
|
|
204
247
|
if (__privateGet(this, _idleTimer)) clearTimeout(__privateGet(this, _idleTimer));
|
package/lib/core/mcp-proxy.cjs
CHANGED
|
@@ -53,7 +53,7 @@ var import_node_readline = require("node:readline");
|
|
|
53
53
|
var import_node_crypto = __toESM(require("node:crypto"));
|
|
54
54
|
var import_node_path = __toESM(require("node:path"));
|
|
55
55
|
var import_node = require("@aipanel/core/node");
|
|
56
|
-
var _proc, _rl, _messageId, _internalIdBase, _pending, _args, _startPromise, _idleTimer, _idleTimeout, _McpProxy_instances, doStart_fn, resetIdleTimer_fn;
|
|
56
|
+
var _proc, _rl, _messageId, _internalIdBase, _pending, _args, _startPromise, _lastExit, _stderrTail, _idleTimer, _idleTimeout, _McpProxy_instances, doStart_fn, formatNotAvailable_fn, resetIdleTimer_fn;
|
|
57
57
|
const log = (0, import_node.createLogger)("McpProxy");
|
|
58
58
|
function resolveChromeDevToolsMcpBin() {
|
|
59
59
|
const pluginDir = (0, import_node.resolvePackageDir)("vite-plugin-aipanel");
|
|
@@ -75,6 +75,10 @@ class McpProxy {
|
|
|
75
75
|
__privateAdd(this, _pending, /* @__PURE__ */ new Map());
|
|
76
76
|
__privateAdd(this, _args);
|
|
77
77
|
__privateAdd(this, _startPromise, null);
|
|
78
|
+
/** 最近一次进程退出信息,用于生成精确错误(无退出记录时为 null) */
|
|
79
|
+
__privateAdd(this, _lastExit, null);
|
|
80
|
+
/** 捕获的 stderr 最近若干行,进程异常退出时作为诊断信息 */
|
|
81
|
+
__privateAdd(this, _stderrTail, []);
|
|
78
82
|
__privateAdd(this, _idleTimer, null);
|
|
79
83
|
__privateAdd(this, _idleTimeout);
|
|
80
84
|
__publicField(this, "sessionId");
|
|
@@ -92,14 +96,19 @@ class McpProxy {
|
|
|
92
96
|
async start() {
|
|
93
97
|
if (this.isRunning) return;
|
|
94
98
|
if (__privateGet(this, _startPromise)) return __privateGet(this, _startPromise);
|
|
95
|
-
|
|
96
|
-
|
|
99
|
+
const p = __privateMethod(this, _McpProxy_instances, doStart_fn).call(this);
|
|
100
|
+
__privateSet(this, _startPromise, p);
|
|
101
|
+
try {
|
|
102
|
+
await p;
|
|
103
|
+
} finally {
|
|
104
|
+
__privateSet(this, _startPromise, null);
|
|
105
|
+
}
|
|
97
106
|
}
|
|
98
107
|
/** 转发原始 JSON-RPC 请求,保留客户端 ID */
|
|
99
108
|
async forward(rawRequest) {
|
|
100
109
|
await this.start();
|
|
101
110
|
if (!__privateGet(this, _proc) || !__privateGet(this, _proc).stdin) {
|
|
102
|
-
throw new Error(
|
|
111
|
+
throw new Error(__privateMethod(this, _McpProxy_instances, formatNotAvailable_fn).call(this));
|
|
103
112
|
}
|
|
104
113
|
__privateMethod(this, _McpProxy_instances, resetIdleTimer_fn).call(this);
|
|
105
114
|
let msg;
|
|
@@ -124,7 +133,7 @@ class McpProxy {
|
|
|
124
133
|
async call(method, params = {}) {
|
|
125
134
|
await this.start();
|
|
126
135
|
if (!__privateGet(this, _proc) || !__privateGet(this, _proc).stdin) {
|
|
127
|
-
throw new Error(
|
|
136
|
+
throw new Error(__privateMethod(this, _McpProxy_instances, formatNotAvailable_fn).call(this));
|
|
128
137
|
}
|
|
129
138
|
__privateMethod(this, _McpProxy_instances, resetIdleTimer_fn).call(this);
|
|
130
139
|
const id = __privateGet(this, _internalIdBase) + ++__privateWrapper(this, _messageId)._;
|
|
@@ -172,6 +181,8 @@ _internalIdBase = new WeakMap();
|
|
|
172
181
|
_pending = new WeakMap();
|
|
173
182
|
_args = new WeakMap();
|
|
174
183
|
_startPromise = new WeakMap();
|
|
184
|
+
_lastExit = new WeakMap();
|
|
185
|
+
_stderrTail = new WeakMap();
|
|
175
186
|
_idleTimer = new WeakMap();
|
|
176
187
|
_idleTimeout = new WeakMap();
|
|
177
188
|
_McpProxy_instances = new WeakSet();
|
|
@@ -179,6 +190,8 @@ doStart_fn = async function() {
|
|
|
179
190
|
log.debug("Starting MCP process", { args: __privateGet(this, _args) });
|
|
180
191
|
try {
|
|
181
192
|
const binPath = resolveChromeDevToolsMcpBin();
|
|
193
|
+
__privateSet(this, _lastExit, null);
|
|
194
|
+
__privateSet(this, _stderrTail, []);
|
|
182
195
|
__privateSet(this, _proc, (0, import_node_child_process.spawn)(process.execPath, [binPath, ...__privateGet(this, _args)], {
|
|
183
196
|
stdio: ["pipe", "pipe", "pipe"]
|
|
184
197
|
}));
|
|
@@ -210,26 +223,56 @@ doStart_fn = async function() {
|
|
|
210
223
|
__privateGet(this, _proc).stderr?.on("data", (d) => {
|
|
211
224
|
const text = d.toString().trim();
|
|
212
225
|
if (!text || /No handler registered for issue code \w+/i.test(text)) return;
|
|
226
|
+
__privateGet(this, _stderrTail).push(...text.split("\n"));
|
|
227
|
+
if (__privateGet(this, _stderrTail).length > 20) __privateGet(this, _stderrTail).splice(0, __privateGet(this, _stderrTail).length - 20);
|
|
213
228
|
log.debug("[MCP stderr]", { text: text.substring(0, 200) });
|
|
214
229
|
});
|
|
215
|
-
__privateGet(this, _proc).on("close", (code) => {
|
|
216
|
-
|
|
230
|
+
__privateGet(this, _proc).on("close", (code, signal) => {
|
|
231
|
+
const exitDesc = `code ${code ?? "null"}${signal ? ` (signal ${signal})` : ""}`;
|
|
232
|
+
const abnormalExit = code !== null && code !== 0 || signal !== null && signal !== "SIGTERM";
|
|
233
|
+
if (abnormalExit) {
|
|
234
|
+
log.warn("MCP process exited abnormally", {
|
|
235
|
+
code,
|
|
236
|
+
signal,
|
|
237
|
+
stderrTail: __privateGet(this, _stderrTail).join("\n").slice(0, 500)
|
|
238
|
+
});
|
|
239
|
+
} else {
|
|
240
|
+
log.debug("MCP process closed", { code, signal });
|
|
241
|
+
}
|
|
242
|
+
__privateSet(this, _lastExit, { code, signal, stderrTail: __privateGet(this, _stderrTail).join("\n") });
|
|
217
243
|
for (const resolve of __privateGet(this, _pending).values()) {
|
|
218
|
-
resolve({ error: { code: -32e3, message: `MCP process exited with
|
|
244
|
+
resolve({ error: { code: -32e3, message: `MCP process exited with ${exitDesc}` } });
|
|
219
245
|
}
|
|
220
246
|
__privateGet(this, _pending).clear();
|
|
221
247
|
__privateSet(this, _proc, null);
|
|
222
248
|
__privateSet(this, _rl, null);
|
|
223
249
|
__privateSet(this, _startPromise, null);
|
|
224
250
|
});
|
|
225
|
-
await this.call("initialize", {
|
|
251
|
+
const initResult = await this.call("initialize", {
|
|
226
252
|
protocolVersion: "2024-11-05",
|
|
227
253
|
capabilities: {},
|
|
228
254
|
clientInfo: { name: "vite-plugin-aipanel", version: "1.0.0" }
|
|
229
255
|
});
|
|
256
|
+
if (!__privateGet(this, _proc)) {
|
|
257
|
+
throw new Error(__privateMethod(this, _McpProxy_instances, formatNotAvailable_fn).call(this));
|
|
258
|
+
}
|
|
259
|
+
if (initResult?.error) {
|
|
260
|
+
throw new Error(
|
|
261
|
+
`MCP initialize failed: ${initResult.error.message ?? JSON.stringify(initResult.error)}`
|
|
262
|
+
);
|
|
263
|
+
}
|
|
230
264
|
log.debug("MCP proxy ready");
|
|
231
265
|
__privateSet(this, _startPromise, null);
|
|
232
266
|
};
|
|
267
|
+
/** 生成 "MCP process not available" 的精确错误信息(包含最近一次退出原因与 stderr) */
|
|
268
|
+
formatNotAvailable_fn = function() {
|
|
269
|
+
const exit = __privateGet(this, _lastExit);
|
|
270
|
+
if (!exit) return "MCP process not available";
|
|
271
|
+
const exitDesc = `code ${exit.code ?? "null"}${exit.signal ? ` (signal ${exit.signal})` : ""}`;
|
|
272
|
+
const tail = exit.stderrTail ? `
|
|
273
|
+
stderr: ${exit.stderrTail}` : "";
|
|
274
|
+
return `MCP process not available (last exit ${exitDesc})${tail}`;
|
|
275
|
+
};
|
|
233
276
|
resetIdleTimer_fn = function() {
|
|
234
277
|
if (__privateGet(this, _idleTimeout) <= 0) return;
|
|
235
278
|
if (__privateGet(this, _idleTimer)) clearTimeout(__privateGet(this, _idleTimer));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vite-plugin-aipanel",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.1",
|
|
4
4
|
"description": "Embed OpenCode Web UI in your Vite dev server for real-time code modification and preview",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.cjs",
|
|
@@ -37,16 +37,16 @@
|
|
|
37
37
|
"dependencies": {
|
|
38
38
|
"@vue/devtools-kit": "^8.0.0",
|
|
39
39
|
"@vue/language-server": "^3.3.7",
|
|
40
|
-
"chrome-devtools-mcp": "1.
|
|
40
|
+
"chrome-devtools-mcp": "^1.8.0",
|
|
41
41
|
"execa": "^9.6.1",
|
|
42
42
|
"typescript-language-server": "^5.3.0",
|
|
43
43
|
"unplugin-vue-inspector": "^3.0.0",
|
|
44
|
-
"@aipanel/
|
|
45
|
-
"@aipanel/
|
|
44
|
+
"@aipanel/core": "1.2.1",
|
|
45
|
+
"@aipanel/provider-opencode": "1.2.1"
|
|
46
46
|
},
|
|
47
47
|
"peerDependencies": {
|
|
48
48
|
"vite": ">=5.0.0",
|
|
49
|
-
"@aipanel/provider-deepseek": "1.2.
|
|
49
|
+
"@aipanel/provider-deepseek": "1.2.1"
|
|
50
50
|
},
|
|
51
51
|
"peerDependenciesMeta": {
|
|
52
52
|
"@aipanel/provider-deepseek": {
|
|
@@ -55,7 +55,7 @@
|
|
|
55
55
|
},
|
|
56
56
|
"devDependencies": {
|
|
57
57
|
"sharp": "^0.34.5",
|
|
58
|
-
"@aipanel/client": "1.2.
|
|
58
|
+
"@aipanel/client": "1.2.1"
|
|
59
59
|
},
|
|
60
60
|
"scripts": {
|
|
61
61
|
"build": "pagoda-cli build && vite build -c vite.client.config.ts",
|