vite-plugin-opencode-assistant 1.0.15 → 1.0.17
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/client/App.vue.d.ts +6 -0
- package/es/client/App.vue.js +317 -0
- package/es/client/components/ChromeWarmupError-sfc.css +1 -0
- package/es/client/components/ChromeWarmupError.vue.d.ts +11 -0
- package/es/client/components/ChromeWarmupError.vue.js +196 -0
- package/es/client/components/LoadingContent.vue.d.ts +5 -0
- package/es/client/components/LoadingContent.vue.js +39 -0
- package/es/client/composables/useContext.d.ts +8 -0
- package/es/client/composables/useContext.js +63 -0
- package/es/client/composables/useHotkey.d.ts +12 -0
- package/es/client/composables/useHotkey.js +41 -0
- package/es/client/composables/useSSE.d.ts +20 -0
- package/es/client/composables/useSSE.js +61 -0
- package/es/client/composables/useSelectedElements.d.ts +19 -0
- package/es/client/composables/useSelectedElements.js +43 -0
- package/es/client/composables/useServiceStatus.d.ts +13 -0
- package/es/client/composables/useServiceStatus.js +53 -0
- package/es/client/composables/useSessions.d.ts +26 -0
- package/es/client/composables/useSessions.js +127 -0
- package/es/client/composables/useTheme.d.ts +12 -0
- package/es/client/composables/useTheme.js +42 -0
- package/es/client/index.d.ts +1 -1
- package/es/client/index.js +5 -675
- package/es/client/styles.css +1 -0
- package/es/core/api.d.ts +18 -6
- package/es/core/api.js +345 -89
- package/es/core/proxy-server.js +266 -2
- package/es/core/service.d.ts +9 -2
- package/es/core/service.js +35 -31
- package/es/endpoints/index.js +1 -1
- package/es/endpoints/sse.js +0 -3
- package/es/endpoints/start.d.ts +1 -2
- package/es/endpoints/start.js +2 -2
- package/es/endpoints/types.d.ts +5 -2
- package/es/endpoints/warmup.js +15 -3
- package/es/index.js +8 -12
- package/es/utils/system.d.ts +1 -0
- package/es/utils/system.js +28 -0
- package/lib/client/App.vue.d.ts +6 -0
- package/lib/client/App.vue.js +344 -0
- package/lib/client/components/ChromeWarmupError-sfc.css +1 -0
- package/lib/client/components/ChromeWarmupError.vue.d.ts +11 -0
- package/lib/client/components/ChromeWarmupError.vue.js +215 -0
- package/lib/client/components/LoadingContent.vue.d.ts +5 -0
- package/lib/client/components/LoadingContent.vue.js +58 -0
- package/lib/client/composables/useContext.d.ts +8 -0
- package/lib/client/composables/useContext.js +86 -0
- package/lib/client/composables/useHotkey.d.ts +12 -0
- package/lib/client/composables/useHotkey.js +66 -0
- package/lib/client/composables/useSSE.d.ts +20 -0
- package/lib/client/composables/useSSE.js +84 -0
- package/lib/client/composables/useSelectedElements.d.ts +19 -0
- package/lib/client/composables/useSelectedElements.js +66 -0
- package/lib/client/composables/useServiceStatus.d.ts +13 -0
- package/lib/client/composables/useServiceStatus.js +76 -0
- package/lib/client/composables/useSessions.d.ts +26 -0
- package/lib/client/composables/useSessions.js +148 -0
- package/lib/client/composables/useTheme.d.ts +12 -0
- package/lib/client/composables/useTheme.js +65 -0
- package/lib/client/index.d.ts +1 -1
- package/lib/client/index.js +22 -667
- package/lib/client/styles.css +1 -0
- package/lib/client.js +3280 -3109
- package/lib/core/api.d.ts +18 -6
- package/lib/core/api.js +342 -94
- package/lib/core/proxy-server.js +266 -2
- package/lib/core/service.d.ts +9 -2
- package/lib/core/service.js +31 -30
- package/lib/endpoints/index.js +1 -1
- package/lib/endpoints/sse.js +0 -3
- package/lib/endpoints/start.d.ts +1 -2
- package/lib/endpoints/start.js +2 -2
- package/lib/endpoints/types.d.ts +5 -2
- package/lib/endpoints/warmup.js +15 -3
- package/lib/index.js +8 -12
- package/lib/style.css +1 -1
- package/lib/utils/system.d.ts +1 -0
- package/lib/utils/system.js +29 -0
- package/package.json +4 -4
package/lib/core/proxy-server.js
CHANGED
|
@@ -128,13 +128,268 @@ function generateBridgeScript(options) {
|
|
|
128
128
|
if (event.data && event.data.type === "OPENCODE_SET_THEME") {
|
|
129
129
|
setTheme(event.data.theme);
|
|
130
130
|
}
|
|
131
|
+
|
|
132
|
+
if (event.data && event.data.type === "OPENCODE_INSERT_FILE_PART") {
|
|
133
|
+
insertFilePart(event.data.element);
|
|
134
|
+
}
|
|
131
135
|
});
|
|
132
136
|
|
|
137
|
+
// === \u4FDD\u5B58\u8F93\u5165\u6846\u5149\u6807\u4F4D\u7F6E ===
|
|
138
|
+
let savedRange = null;
|
|
139
|
+
|
|
140
|
+
function setupPromptInputListener() {
|
|
141
|
+
const promptInput = document.querySelector('[data-component="prompt-input"]');
|
|
142
|
+
if (!promptInput) return;
|
|
143
|
+
|
|
144
|
+
promptInput.addEventListener('blur', function() {
|
|
145
|
+
const selection = window.getSelection();
|
|
146
|
+
if (selection && selection.rangeCount > 0) {
|
|
147
|
+
const range = selection.getRangeAt(0);
|
|
148
|
+
if (promptInput.contains(range.commonAncestorContainer)) {
|
|
149
|
+
savedRange = range.cloneRange();
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
promptInput.addEventListener('focus', function() {
|
|
155
|
+
savedRange = null;
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// === \u63D2\u5165 File Part \u5230\u8F93\u5165\u6846 ===
|
|
160
|
+
function insertFilePart(element) {
|
|
161
|
+
const promptInput = document.querySelector('[data-component="prompt-input"]');
|
|
162
|
+
if (!promptInput) {
|
|
163
|
+
console.warn('[OpenCode Bridge] Prompt input not found');
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
const { filePath, line, column, description, innerText, previewPageUrl, previewPageTitle } = element;
|
|
168
|
+
|
|
169
|
+
const selector = description || 'element';
|
|
170
|
+
let textPreview = '';
|
|
171
|
+
if (innerText && innerText.trim()) {
|
|
172
|
+
const trimmed = innerText.trim();
|
|
173
|
+
textPreview = trimmed.length > 5 ? trimmed.substring(0, 5) + '...' : trimmed;
|
|
174
|
+
}
|
|
175
|
+
const displayText = '@' + selector + (textPreview ? '(' + textPreview + ')' : '');
|
|
176
|
+
|
|
177
|
+
const jsonStr = JSON.stringify({
|
|
178
|
+
pageContext: {
|
|
179
|
+
url: previewPageUrl || '',
|
|
180
|
+
title: previewPageTitle || '',
|
|
181
|
+
},
|
|
182
|
+
nodeContext: {
|
|
183
|
+
filePath,
|
|
184
|
+
line,
|
|
185
|
+
column,
|
|
186
|
+
description,
|
|
187
|
+
innerText: innerText ? innerText.substring(0, 500) : ''
|
|
188
|
+
}
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
const span = document.createElement('span');
|
|
192
|
+
span.setAttribute('data-type', 'file');
|
|
193
|
+
span.setAttribute('data-path', jsonStr);
|
|
194
|
+
span.setAttribute('contenteditable', 'false');
|
|
195
|
+
|
|
196
|
+
span.textContent = displayText;
|
|
197
|
+
|
|
198
|
+
if (savedRange) {
|
|
199
|
+
const range = savedRange;
|
|
200
|
+
range.collapse(false);
|
|
201
|
+
range.insertNode(span);
|
|
202
|
+
|
|
203
|
+
const space = document.createTextNode('\\u00A0');
|
|
204
|
+
span.parentNode.insertBefore(space, span.nextSibling);
|
|
205
|
+
|
|
206
|
+
const newRange = document.createRange();
|
|
207
|
+
newRange.setStartAfter(space);
|
|
208
|
+
newRange.collapse(true);
|
|
209
|
+
|
|
210
|
+
promptInput.focus();
|
|
211
|
+
|
|
212
|
+
const selection = window.getSelection();
|
|
213
|
+
if (selection) {
|
|
214
|
+
selection.removeAllRanges();
|
|
215
|
+
selection.addRange(newRange);
|
|
216
|
+
}
|
|
217
|
+
savedRange = null;
|
|
218
|
+
|
|
219
|
+
promptInput.dispatchEvent(new Event('input', { bubbles: true }));
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
const selection = window.getSelection();
|
|
224
|
+
if (selection && selection.rangeCount > 0) {
|
|
225
|
+
const range = selection.getRangeAt(0);
|
|
226
|
+
|
|
227
|
+
if (promptInput.contains(range.commonAncestorContainer)) {
|
|
228
|
+
range.collapse(false);
|
|
229
|
+
range.insertNode(span);
|
|
230
|
+
|
|
231
|
+
const space = document.createTextNode('\\u00A0');
|
|
232
|
+
span.parentNode.insertBefore(space, span.nextSibling);
|
|
233
|
+
|
|
234
|
+
const newRange = document.createRange();
|
|
235
|
+
newRange.setStartAfter(space);
|
|
236
|
+
newRange.collapse(true);
|
|
237
|
+
selection.removeAllRanges();
|
|
238
|
+
selection.addRange(newRange);
|
|
239
|
+
|
|
240
|
+
promptInput.dispatchEvent(new Event('input', { bubbles: true }));
|
|
241
|
+
return;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
promptInput.appendChild(span);
|
|
246
|
+
const space = document.createTextNode('\\u00A0');
|
|
247
|
+
promptInput.appendChild(space);
|
|
248
|
+
|
|
249
|
+
const newRange = document.createRange();
|
|
250
|
+
newRange.setStartAfter(space);
|
|
251
|
+
newRange.collapse(true);
|
|
252
|
+
const newSelection = window.getSelection();
|
|
253
|
+
if (newSelection) {
|
|
254
|
+
newSelection.removeAllRanges();
|
|
255
|
+
newSelection.addRange(newRange);
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
promptInput.dispatchEvent(new Event('input', { bubbles: true }));
|
|
259
|
+
promptInput.focus();
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
// === \u601D\u8003\u72B6\u6001\u76D1\u542C (\u5B8C\u5168\u590D\u523B OpenCode Web \u5B9E\u73B0) ===
|
|
263
|
+
// OpenCode Web \u6838\u5FC3\u903B\u8F91:
|
|
264
|
+
// working = !!pending() || sessionStatus().type !== "idle"
|
|
265
|
+
// pending = \u6700\u540E\u4E00\u6761\u672A\u5B8C\u6210\u7684 assistant \u6D88\u606F (time.completed \u4E0D\u662F\u6570\u5B57)
|
|
266
|
+
// sessionStatus = sync.data.session_status[sessionID]
|
|
267
|
+
|
|
268
|
+
let eventSource = null;
|
|
269
|
+
const sessionStatus = {};
|
|
270
|
+
const pendingMessages = {};
|
|
271
|
+
|
|
272
|
+
function getCurrentSessionID() {
|
|
273
|
+
const match = window.location.pathname.match(/\\/session\\/([^\\/]+)/);
|
|
274
|
+
return match ? match[1] : null;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
function isPending(message) {
|
|
278
|
+
return message.role === 'assistant' && typeof message.time?.completed !== 'number';
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
function updateThinkingState(sessionID) {
|
|
282
|
+
const status = sessionStatus[sessionID];
|
|
283
|
+
const pending = pendingMessages[sessionID];
|
|
284
|
+
|
|
285
|
+
const isThinking = !!pending || (status && status.type !== 'idle');
|
|
286
|
+
|
|
287
|
+
if (window.parent !== window) {
|
|
288
|
+
window.parent.postMessage({
|
|
289
|
+
type: 'OPENCODE_THINKING_STATE',
|
|
290
|
+
thinking: isThinking,
|
|
291
|
+
sessionID: sessionID,
|
|
292
|
+
statusType: status?.type || 'idle',
|
|
293
|
+
hasPending: !!pending
|
|
294
|
+
}, '*');
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
function handleEvent(payload) {
|
|
299
|
+
const type = payload.type;
|
|
300
|
+
const props = payload.properties;
|
|
301
|
+
|
|
302
|
+
switch (type) {
|
|
303
|
+
case 'session.status': {
|
|
304
|
+
const sessionID = props.sessionID;
|
|
305
|
+
sessionStatus[sessionID] = props.status;
|
|
306
|
+
updateThinkingState(sessionID);
|
|
307
|
+
break;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
case 'message.updated': {
|
|
311
|
+
const info = props.info;
|
|
312
|
+
if (!info || !info.sessionID) break;
|
|
313
|
+
const sessionID = info.sessionID;
|
|
314
|
+
|
|
315
|
+
if (info.role === 'assistant') {
|
|
316
|
+
if (isPending(info)) {
|
|
317
|
+
pendingMessages[sessionID] = info;
|
|
318
|
+
} else {
|
|
319
|
+
delete pendingMessages[sessionID];
|
|
320
|
+
}
|
|
321
|
+
updateThinkingState(sessionID);
|
|
322
|
+
}
|
|
323
|
+
break;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
case 'message.part.delta': {
|
|
327
|
+
const sessionID = props.sessionID;
|
|
328
|
+
if (sessionID && !pendingMessages[sessionID]) {
|
|
329
|
+
pendingMessages[sessionID] = { role: 'assistant', time: {} };
|
|
330
|
+
updateThinkingState(sessionID);
|
|
331
|
+
}
|
|
332
|
+
break;
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
function setupThinkingListener() {
|
|
338
|
+
if (eventSource) {
|
|
339
|
+
eventSource.close();
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
eventSource = new EventSource('/global/event');
|
|
343
|
+
|
|
344
|
+
eventSource.onmessage = function(event) {
|
|
345
|
+
try {
|
|
346
|
+
const data = JSON.parse(event.data);
|
|
347
|
+
const payload = data.payload;
|
|
348
|
+
if (!payload) return;
|
|
349
|
+
handleEvent(payload);
|
|
350
|
+
} catch (e) {
|
|
351
|
+
// ignore parse errors
|
|
352
|
+
}
|
|
353
|
+
};
|
|
354
|
+
|
|
355
|
+
eventSource.onerror = function(err) {
|
|
356
|
+
console.warn('[OpenCode Bridge] SSE connection error, retrying in 3s...');
|
|
357
|
+
eventSource.close();
|
|
358
|
+
setTimeout(setupThinkingListener, 3000);
|
|
359
|
+
};
|
|
360
|
+
|
|
361
|
+
console.log('[OpenCode Bridge] SSE listener setup complete');
|
|
362
|
+
}
|
|
363
|
+
|
|
133
364
|
// === \u5C31\u7EEA\u901A\u77E5 ===
|
|
134
|
-
|
|
365
|
+
function init() {
|
|
135
366
|
if (window.parent !== window) {
|
|
136
367
|
window.parent.postMessage({ type: "OPENCODE_READY" }, "*");
|
|
137
368
|
}
|
|
369
|
+
setupThinkingListener();
|
|
370
|
+
setupPromptInputListener();
|
|
371
|
+
|
|
372
|
+
const observer = new MutationObserver(function(mutations) {
|
|
373
|
+
const promptInput = document.querySelector('[data-component="prompt-input"]');
|
|
374
|
+
if (promptInput && !promptInput._opencodeListenerAttached) {
|
|
375
|
+
setupPromptInputListener();
|
|
376
|
+
promptInput._opencodeListenerAttached = true;
|
|
377
|
+
}
|
|
378
|
+
});
|
|
379
|
+
observer.observe(document.body, { childList: true, subtree: true });
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
if (document.readyState === 'loading') {
|
|
383
|
+
document.addEventListener('DOMContentLoaded', init);
|
|
384
|
+
} else {
|
|
385
|
+
init();
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
window.addEventListener('beforeunload', function() {
|
|
389
|
+
if (eventSource) {
|
|
390
|
+
eventSource.close();
|
|
391
|
+
eventSource = null;
|
|
392
|
+
}
|
|
138
393
|
});
|
|
139
394
|
})();
|
|
140
395
|
`;
|
|
@@ -162,7 +417,8 @@ function startProxyServer(targetUrl, port, options = {}) {
|
|
|
162
417
|
headers: __spreadProps(__spreadValues({}, req.headers), {
|
|
163
418
|
host: target.host,
|
|
164
419
|
"accept-encoding": "identity"
|
|
165
|
-
})
|
|
420
|
+
}),
|
|
421
|
+
timeout: 0
|
|
166
422
|
};
|
|
167
423
|
const proxyReq = import_http.default.request(requestOptions, (proxyRes) => {
|
|
168
424
|
var _a;
|
|
@@ -208,11 +464,19 @@ function startProxyServer(targetUrl, port, options = {}) {
|
|
|
208
464
|
res.writeHead(502);
|
|
209
465
|
res.end("Proxy error");
|
|
210
466
|
});
|
|
467
|
+
proxyReq.on("socket", (socket) => {
|
|
468
|
+
socket.setTimeout(0);
|
|
469
|
+
});
|
|
470
|
+
req.on("socket", (socket) => {
|
|
471
|
+
socket.setTimeout(0);
|
|
472
|
+
});
|
|
211
473
|
req.pipe(proxyReq);
|
|
212
474
|
});
|
|
213
475
|
server.on("error", (err) => {
|
|
214
476
|
reject(err);
|
|
215
477
|
});
|
|
478
|
+
server.timeout = 0;
|
|
479
|
+
server.keepAliveTimeout = 0;
|
|
216
480
|
server.listen(port, () => {
|
|
217
481
|
const address = server.address();
|
|
218
482
|
const actualPort = typeof address === "object" && address ? address.port : port;
|
package/lib/core/service.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { ResultPromise } from "execa";
|
|
2
2
|
import type http from "http";
|
|
3
3
|
import type { OpenCodeOptions, ServiceStartupTask } from "@vite-plugin-opencode-assistant/shared";
|
|
4
|
+
import { ChromeMcpWarmupErrorType } from "@vite-plugin-opencode-assistant/shared";
|
|
4
5
|
import type { OpenCodeAPI } from "./api.js";
|
|
5
6
|
export declare class OpenCodeService {
|
|
6
7
|
private config;
|
|
@@ -13,16 +14,22 @@ export declare class OpenCodeService {
|
|
|
13
14
|
actualProxyPort: number;
|
|
14
15
|
isStarted: boolean;
|
|
15
16
|
private startPromise;
|
|
16
|
-
sessionUrl: string | null;
|
|
17
17
|
private proxyServer;
|
|
18
18
|
chromeMcpWarmupFailed: boolean;
|
|
19
|
+
chromeMcpWarmupErrorType: ChromeMcpWarmupErrorType | null;
|
|
20
|
+
chromeMcpWarmupErrorMessage: string | null;
|
|
19
21
|
currentTask: {
|
|
20
22
|
task: ServiceStartupTask;
|
|
21
23
|
data?: Record<string, unknown>;
|
|
22
24
|
} | null;
|
|
25
|
+
workspaceRoot: string | null;
|
|
23
26
|
constructor(config: Required<OpenCodeOptions>, api: OpenCodeAPI, sseClients: Set<http.ServerResponse>, onPortAllocated: (port: number) => void, onProxyPortAllocated: (port: number) => void);
|
|
24
27
|
private sendTaskUpdate;
|
|
25
28
|
start(corsOrigins?: string[], contextApiUrl?: string, viteOrigin?: string): Promise<void>;
|
|
26
|
-
retryWarmupChromeMcp(viteOrigin?: string): Promise<
|
|
29
|
+
retryWarmupChromeMcp(viteOrigin?: string): Promise<{
|
|
30
|
+
success: boolean;
|
|
31
|
+
errorType?: string;
|
|
32
|
+
errorMessage?: string;
|
|
33
|
+
}>;
|
|
27
34
|
stop(): Promise<void>;
|
|
28
35
|
}
|
package/lib/core/service.js
CHANGED
|
@@ -72,10 +72,12 @@ class OpenCodeService {
|
|
|
72
72
|
__publicField(this, "actualProxyPort");
|
|
73
73
|
__publicField(this, "isStarted", false);
|
|
74
74
|
__publicField(this, "startPromise", null);
|
|
75
|
-
__publicField(this, "sessionUrl", null);
|
|
76
75
|
__publicField(this, "proxyServer", null);
|
|
77
76
|
__publicField(this, "chromeMcpWarmupFailed", false);
|
|
77
|
+
__publicField(this, "chromeMcpWarmupErrorType", null);
|
|
78
|
+
__publicField(this, "chromeMcpWarmupErrorMessage", null);
|
|
78
79
|
__publicField(this, "currentTask", null);
|
|
80
|
+
__publicField(this, "workspaceRoot", null);
|
|
79
81
|
var _a;
|
|
80
82
|
this.actualWebPort = config.webPort;
|
|
81
83
|
this.actualProxyPort = (_a = config.proxyPort) != null ? _a : import_shared.DEFAULT_PROXY_PORT;
|
|
@@ -149,8 +151,10 @@ Please install OpenCode first:
|
|
|
149
151
|
log.debug(`Using port ${this.actualWebPort}`);
|
|
150
152
|
}
|
|
151
153
|
timer.checkpoint("Port allocated");
|
|
154
|
+
this.workspaceRoot = (0, import_system.findGitRoot)(process.cwd());
|
|
155
|
+
log.info(`Using workspace root: ${this.workspaceRoot}`);
|
|
152
156
|
this.sendTaskUpdate("preparing_runtime");
|
|
153
|
-
const configDir = (0, import_opencode.prepareOpenCodeRuntime)(
|
|
157
|
+
const configDir = (0, import_opencode.prepareOpenCodeRuntime)(this.workspaceRoot);
|
|
154
158
|
timer.checkpoint("Plugin setup complete");
|
|
155
159
|
this.sendTaskUpdate("starting_web");
|
|
156
160
|
log.debug("Starting OpenCode Web process...", {
|
|
@@ -162,7 +166,7 @@ Please install OpenCode first:
|
|
|
162
166
|
port: this.actualWebPort,
|
|
163
167
|
hostname: this.config.hostname,
|
|
164
168
|
serverUrl: "",
|
|
165
|
-
cwd:
|
|
169
|
+
cwd: this.workspaceRoot,
|
|
166
170
|
configDir,
|
|
167
171
|
corsOrigins,
|
|
168
172
|
contextApiUrl
|
|
@@ -235,39 +239,30 @@ Please install OpenCode first:
|
|
|
235
239
|
this.sendTaskUpdate("warming_up_chrome");
|
|
236
240
|
let warmupFailed = false;
|
|
237
241
|
try {
|
|
238
|
-
yield this.api.warmupChromeMcp(viteOrigin);
|
|
242
|
+
yield this.api.warmupChromeMcp(this.workspaceRoot, viteOrigin);
|
|
239
243
|
timer.checkpoint("Chrome MCP warmup complete");
|
|
240
244
|
} catch (e) {
|
|
241
245
|
log.warn("Chrome MCP warmup failed", { error: e });
|
|
242
246
|
this.chromeMcpWarmupFailed = true;
|
|
243
247
|
warmupFailed = true;
|
|
248
|
+
if (e instanceof import_shared.ChromeMcpWarmupError) {
|
|
249
|
+
this.chromeMcpWarmupErrorType = e.type;
|
|
250
|
+
this.chromeMcpWarmupErrorMessage = e.message;
|
|
251
|
+
} else {
|
|
252
|
+
this.chromeMcpWarmupErrorType = import_shared.ChromeMcpWarmupErrorType.UNKNOWN;
|
|
253
|
+
this.chromeMcpWarmupErrorMessage = e instanceof Error ? e.message : String(e);
|
|
254
|
+
}
|
|
244
255
|
}
|
|
245
256
|
this.sendTaskUpdate("creating_session");
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
} catch (e) {
|
|
252
|
-
log.warn("Failed to get/create session", { error: e });
|
|
253
|
-
sessionFailed = true;
|
|
254
|
-
}
|
|
255
|
-
if (sessionFailed) {
|
|
256
|
-
this.sendTaskUpdate("session_creation_failed");
|
|
257
|
-
this.isStarted = false;
|
|
258
|
-
this.startPromise = null;
|
|
259
|
-
} else if (warmupFailed) {
|
|
260
|
-
this.sendTaskUpdate("chrome_mcp_failed", { sessionUrl: this.sessionUrl });
|
|
261
|
-
this.isStarted = true;
|
|
262
|
-
} else {
|
|
263
|
-
this.sendTaskUpdate("ready", { sessionUrl: this.sessionUrl });
|
|
264
|
-
}
|
|
265
|
-
if (!sessionFailed) {
|
|
257
|
+
if (warmupFailed) {
|
|
258
|
+
this.sendTaskUpdate("chrome_mcp_failed", {
|
|
259
|
+
errorType: this.chromeMcpWarmupErrorType,
|
|
260
|
+
errorMessage: this.chromeMcpWarmupErrorMessage
|
|
261
|
+
});
|
|
266
262
|
this.isStarted = true;
|
|
267
263
|
} else {
|
|
268
|
-
this.
|
|
264
|
+
this.sendTaskUpdate("ready");
|
|
269
265
|
}
|
|
270
|
-
log.debug(`OpenCode services started successfully: ${this.sessionUrl || webUrl}`);
|
|
271
266
|
timer.end("\u2713 Services started successfully");
|
|
272
267
|
}))();
|
|
273
268
|
return this.startPromise;
|
|
@@ -275,12 +270,18 @@ Please install OpenCode first:
|
|
|
275
270
|
}
|
|
276
271
|
retryWarmupChromeMcp(viteOrigin) {
|
|
277
272
|
return __async(this, null, function* () {
|
|
278
|
-
const
|
|
279
|
-
if (success) {
|
|
273
|
+
const result = yield this.api.retryWarmupChromeMcp(this.workspaceRoot, viteOrigin);
|
|
274
|
+
if (result.success) {
|
|
280
275
|
this.chromeMcpWarmupFailed = false;
|
|
281
|
-
this.sendTaskUpdate("ready"
|
|
276
|
+
this.sendTaskUpdate("ready");
|
|
277
|
+
return { success: true };
|
|
282
278
|
}
|
|
283
|
-
|
|
279
|
+
const error = result.error;
|
|
280
|
+
return {
|
|
281
|
+
success: false,
|
|
282
|
+
errorType: error == null ? void 0 : error.type,
|
|
283
|
+
errorMessage: (error == null ? void 0 : error.message) || "Unknown error"
|
|
284
|
+
};
|
|
284
285
|
});
|
|
285
286
|
}
|
|
286
287
|
stop() {
|
package/lib/endpoints/index.js
CHANGED
|
@@ -31,7 +31,7 @@ __reExport(endpoints_exports, require("./types.js"), module.exports);
|
|
|
31
31
|
function setupMiddlewares(server, ctx) {
|
|
32
32
|
(0, import_widget.setupWidgetEndpoints)(server, ctx);
|
|
33
33
|
(0, import_context.setupContextEndpoint)(server, ctx);
|
|
34
|
-
(0, import_start.setupStartEndpoint)(server
|
|
34
|
+
(0, import_start.setupStartEndpoint)(server);
|
|
35
35
|
(0, import_sse.setupSseEndpoint)(server, ctx);
|
|
36
36
|
(0, import_sessions.setupSessionsEndpoint)(server, ctx);
|
|
37
37
|
(0, import_warmup.setupWarmupEndpoint)(server, ctx);
|
package/lib/endpoints/sse.js
CHANGED
package/lib/endpoints/start.d.ts
CHANGED
package/lib/endpoints/start.js
CHANGED
|
@@ -42,13 +42,13 @@ __export(start_exports, {
|
|
|
42
42
|
module.exports = __toCommonJS(start_exports);
|
|
43
43
|
var import_shared = require("@vite-plugin-opencode-assistant/shared");
|
|
44
44
|
var import_shared2 = require("@vite-plugin-opencode-assistant/shared");
|
|
45
|
-
function setupStartEndpoint(server
|
|
45
|
+
function setupStartEndpoint(server) {
|
|
46
46
|
server.middlewares.use(import_shared.START_API_PATH, (_req, res) => __async(null, null, function* () {
|
|
47
47
|
const reqCtx = new import_shared2.RequestContext("GET", import_shared.START_API_PATH);
|
|
48
48
|
res.setHeader("Content-Type", "application/json");
|
|
49
49
|
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
50
50
|
res.writeHead(200);
|
|
51
|
-
res.end(JSON.stringify({ success: true
|
|
51
|
+
res.end(JSON.stringify({ success: true }));
|
|
52
52
|
reqCtx.end(200);
|
|
53
53
|
}));
|
|
54
54
|
}
|
package/lib/endpoints/types.d.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import type { PageContext, SessionInfo, ServiceStartupTask } from "@vite-plugin-opencode-assistant/shared";
|
|
2
2
|
import type http from "http";
|
|
3
3
|
export interface EndpointContext {
|
|
4
|
-
get sessionUrl(): string | null;
|
|
5
4
|
get webUrl(): string | null;
|
|
6
5
|
get sseClients(): Set<http.ServerResponse>;
|
|
7
6
|
get pageContext(): PageContext;
|
|
@@ -16,5 +15,9 @@ export interface EndpointContext {
|
|
|
16
15
|
deleteSession: (id: string) => Promise<void>;
|
|
17
16
|
resolveWidgetPath: () => string;
|
|
18
17
|
resolveWidgetStylePath: () => string;
|
|
19
|
-
retryWarmupChromeMcp: () => Promise<
|
|
18
|
+
retryWarmupChromeMcp: () => Promise<{
|
|
19
|
+
success: boolean;
|
|
20
|
+
errorType?: string;
|
|
21
|
+
errorMessage?: string;
|
|
22
|
+
}>;
|
|
20
23
|
}
|
package/lib/endpoints/warmup.js
CHANGED
|
@@ -50,15 +50,27 @@ function setupWarmupEndpoint(server, ctx) {
|
|
|
50
50
|
return;
|
|
51
51
|
}
|
|
52
52
|
try {
|
|
53
|
-
const
|
|
53
|
+
const result = yield ctx.retryWarmupChromeMcp();
|
|
54
54
|
res.setHeader("Content-Type", "application/json");
|
|
55
55
|
res.writeHead(200);
|
|
56
|
-
|
|
56
|
+
if (result.success) {
|
|
57
|
+
res.end(JSON.stringify({ success: true }));
|
|
58
|
+
} else {
|
|
59
|
+
res.end(JSON.stringify({
|
|
60
|
+
success: false,
|
|
61
|
+
errorType: result.errorType,
|
|
62
|
+
error: result.errorMessage
|
|
63
|
+
}));
|
|
64
|
+
}
|
|
57
65
|
} catch (e) {
|
|
58
66
|
log.error("Failed to retry warmup", { error: e });
|
|
59
67
|
res.setHeader("Content-Type", "application/json");
|
|
60
68
|
res.writeHead(500);
|
|
61
|
-
res.end(JSON.stringify({
|
|
69
|
+
res.end(JSON.stringify({
|
|
70
|
+
success: false,
|
|
71
|
+
errorType: "UNKNOWN",
|
|
72
|
+
error: String(e)
|
|
73
|
+
}));
|
|
62
74
|
}
|
|
63
75
|
}));
|
|
64
76
|
}
|
package/lib/index.js
CHANGED
|
@@ -92,7 +92,12 @@ function createOpenCodePlugin(options = {}) {
|
|
|
92
92
|
let actualProxyPort = (_a = config.proxyPort) != null ? _a : import_shared.DEFAULT_PROXY_PORT;
|
|
93
93
|
let pageContext = { url: "", title: "" };
|
|
94
94
|
const sseClients = /* @__PURE__ */ new Set();
|
|
95
|
-
const api = new import_api.OpenCodeAPI(
|
|
95
|
+
const api = new import_api.OpenCodeAPI(
|
|
96
|
+
config.hostname,
|
|
97
|
+
() => actualWebPort,
|
|
98
|
+
() => actualProxyPort,
|
|
99
|
+
config.warmupChromeMcp
|
|
100
|
+
);
|
|
96
101
|
const service = new import_service.OpenCodeService(
|
|
97
102
|
config,
|
|
98
103
|
api,
|
|
@@ -117,9 +122,6 @@ function createOpenCodePlugin(options = {}) {
|
|
|
117
122
|
let viteOrigin = "";
|
|
118
123
|
const getViteOrigin = () => viteOrigin;
|
|
119
124
|
(0, import_endpoints.setupMiddlewares)(server, {
|
|
120
|
-
get sessionUrl() {
|
|
121
|
-
return service.sessionUrl;
|
|
122
|
-
},
|
|
123
125
|
get webUrl() {
|
|
124
126
|
return actualWebPort ? `http://${config.hostname}:${actualWebPort}` : null;
|
|
125
127
|
},
|
|
@@ -138,8 +140,8 @@ function createOpenCodePlugin(options = {}) {
|
|
|
138
140
|
get currentTask() {
|
|
139
141
|
return service.currentTask;
|
|
140
142
|
},
|
|
141
|
-
getSessions: () => api.getSessions(),
|
|
142
|
-
createSession: () => api.createSession(),
|
|
143
|
+
getSessions: () => api.getSessions(service.workspaceRoot),
|
|
144
|
+
createSession: () => api.createSession(service.workspaceRoot),
|
|
143
145
|
deleteSession: (id) => api.deleteSession(id),
|
|
144
146
|
resolveWidgetPath: import_paths.resolveWidgetPath,
|
|
145
147
|
resolveWidgetStylePath: import_paths.resolveWidgetStylePath,
|
|
@@ -195,15 +197,9 @@ function createOpenCodePlugin(options = {}) {
|
|
|
195
197
|
transformIndexHtml(html) {
|
|
196
198
|
const timer = log.timer("transformIndexHtml");
|
|
197
199
|
const widget = (0, import_injector.injectWidget)({
|
|
198
|
-
webUrl: `http://${config.hostname}:${actualWebPort}`,
|
|
199
|
-
proxyUrl: `http://${config.hostname}:${actualProxyPort}`,
|
|
200
|
-
serverUrl: `http://${config.hostname}:${actualWebPort}`,
|
|
201
200
|
position: config.position,
|
|
202
201
|
theme: config.theme,
|
|
203
202
|
open: config.open,
|
|
204
|
-
autoReload: config.autoReload,
|
|
205
|
-
cwd: process.cwd(),
|
|
206
|
-
// 不再注入 sessionUrl,客户端完全依赖 SSE 状态同步
|
|
207
203
|
hotkey: config.hotkey
|
|
208
204
|
});
|
|
209
205
|
timer.end();
|