vite-plugin-opencode-assistant 1.0.12 → 1.0.14
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/index.js +424 -84
- package/es/core/api.d.ts +1 -0
- package/es/core/api.js +97 -15
- package/es/core/service.d.ts +8 -1
- package/es/core/service.js +84 -16
- package/es/endpoints/index.js +2 -0
- package/es/endpoints/sse.js +14 -5
- package/es/endpoints/types.d.ts +7 -1
- package/es/endpoints/warmup.d.ts +3 -0
- package/es/endpoints/warmup.js +45 -0
- package/es/index.js +12 -3
- package/lib/client/index.js +420 -83
- package/lib/client.js +3005 -2707
- package/lib/core/api.d.ts +1 -0
- package/lib/core/api.js +97 -15
- package/lib/core/service.d.ts +8 -1
- package/lib/core/service.js +83 -16
- package/lib/endpoints/index.js +2 -0
- package/lib/endpoints/sse.js +14 -5
- package/lib/endpoints/types.d.ts +7 -1
- package/lib/endpoints/warmup.d.ts +3 -0
- package/lib/endpoints/warmup.js +68 -0
- package/lib/index.js +12 -3
- package/lib/style.css +1 -1
- package/package.json +5 -5
package/lib/client/index.js
CHANGED
|
@@ -41,6 +41,24 @@ var import_vue = require("vue");
|
|
|
41
41
|
var import_components = require("@vite-plugin-opencode-assistant/components");
|
|
42
42
|
var import_style = require("@vite-plugin-opencode-assistant/components/style.css");
|
|
43
43
|
var import_shared = require("@vite-plugin-opencode-assistant/shared");
|
|
44
|
+
function parseHotkey(hotkeyStr) {
|
|
45
|
+
if (!hotkeyStr) return { ctrl: true, shift: false, alt: false, key: "k" };
|
|
46
|
+
const parts = hotkeyStr.toLowerCase().split("+");
|
|
47
|
+
const key = parts.pop();
|
|
48
|
+
return {
|
|
49
|
+
ctrl: parts.includes("ctrl") || parts.includes("cmd") || parts.includes("meta"),
|
|
50
|
+
shift: parts.includes("shift"),
|
|
51
|
+
alt: parts.includes("alt"),
|
|
52
|
+
key: key || "k"
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
function matchHotkey(e, hotkeyConfig) {
|
|
56
|
+
const ctrlMatch = hotkeyConfig.ctrl ? e.ctrlKey || e.metaKey : !(e.ctrlKey || e.metaKey);
|
|
57
|
+
const shiftMatch = hotkeyConfig.shift ? e.shiftKey : !e.shiftKey;
|
|
58
|
+
const altMatch = hotkeyConfig.alt ? e.altKey : !e.altKey;
|
|
59
|
+
const keyMatch = e.key.toLowerCase() === hotkeyConfig.key.toLowerCase();
|
|
60
|
+
return ctrlMatch && shiftMatch && altMatch && keyMatch;
|
|
61
|
+
}
|
|
44
62
|
function utf8ToBase64(str) {
|
|
45
63
|
const bytes = new TextEncoder().encode(str);
|
|
46
64
|
const binString = Array.from(bytes, (byte) => String.fromCodePoint(byte)).join("");
|
|
@@ -83,13 +101,40 @@ const App = {
|
|
|
83
101
|
const sessions = (0, import_vue.ref)([]);
|
|
84
102
|
const selectedElements = (0, import_vue.ref)([]);
|
|
85
103
|
const widgetRef = (0, import_vue.ref)(null);
|
|
104
|
+
const chromeMcpFailed = (0, import_vue.ref)(false);
|
|
105
|
+
const currentTask = (0, import_vue.ref)("");
|
|
106
|
+
const serviceStatus = (0, import_vue.ref)("idle");
|
|
107
|
+
const loadingText = (0, import_vue.computed)(() => {
|
|
108
|
+
if (iframeLoading.value) return "\u52A0\u8F7D\u4E2D...";
|
|
109
|
+
if (!currentTask.value) return "\u52A0\u8F7D\u4E2D...";
|
|
110
|
+
return import_shared.SERVICE_STARTUP_TASKS[currentTask.value] || "\u52A0\u8F7D\u4E2D...";
|
|
111
|
+
});
|
|
112
|
+
const retryingWarmup = (0, import_vue.ref)(false);
|
|
113
|
+
const retryWarmup = () => __async(null, null, function* () {
|
|
114
|
+
retryingWarmup.value = true;
|
|
115
|
+
try {
|
|
116
|
+
const res = yield fetch("/__opencode_warmup__", { method: "POST" });
|
|
117
|
+
const data = yield res.json();
|
|
118
|
+
if (data.success) {
|
|
119
|
+
chromeMcpFailed.value = false;
|
|
120
|
+
serviceStatus.value = "ready";
|
|
121
|
+
showNotification("Chrome DevTools MCP \u8FDE\u63A5\u6210\u529F");
|
|
122
|
+
} else {
|
|
123
|
+
showNotification(data.error || "\u91CD\u8BD5\u5931\u8D25\uFF0C\u8BF7\u786E\u8BA4 Chrome \u8FDC\u7A0B\u8C03\u8BD5\u5DF2\u5F00\u542F");
|
|
124
|
+
}
|
|
125
|
+
} catch (e) {
|
|
126
|
+
console.error("[OpenCode] Retry warmup failed:", e);
|
|
127
|
+
showNotification("\u91CD\u8BD5\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u518D\u8BD5");
|
|
128
|
+
} finally {
|
|
129
|
+
retryingWarmup.value = false;
|
|
130
|
+
}
|
|
131
|
+
});
|
|
86
132
|
const {
|
|
87
133
|
position = "bottom-right",
|
|
88
134
|
theme: initialTheme = "auto",
|
|
89
135
|
open: autoOpen = false,
|
|
90
|
-
sessionUrl
|
|
136
|
+
// sessionUrl 不再从配置读取,完全依赖 SSE 状态同步
|
|
91
137
|
proxyUrl: configProxyUrl = "",
|
|
92
|
-
lazy = false,
|
|
93
138
|
hotkey = "ctrl+k",
|
|
94
139
|
cwd = ""
|
|
95
140
|
} = config;
|
|
@@ -97,18 +142,16 @@ const App = {
|
|
|
97
142
|
proxyUrl = configProxyUrl;
|
|
98
143
|
}
|
|
99
144
|
const theme = (0, import_vue.ref)(initialTheme);
|
|
100
|
-
const
|
|
101
|
-
const
|
|
102
|
-
|
|
145
|
+
const showSessionListSkeleton = (0, import_vue.computed)(() => serviceStatus.value === "starting");
|
|
146
|
+
const iframeLoading = (0, import_vue.ref)(false);
|
|
147
|
+
const computedLoading = (0, import_vue.computed)(() => {
|
|
148
|
+
return serviceStatus.value === "starting" || iframeLoading.value;
|
|
149
|
+
});
|
|
103
150
|
const extractSessionId = (url) => {
|
|
104
151
|
if (!url) return null;
|
|
105
152
|
const match = url.match(/\/session\/([^/?]+)/);
|
|
106
153
|
return match ? match[1] : null;
|
|
107
154
|
};
|
|
108
|
-
currentSessionId.value = extractSessionId(initialSessionUrl);
|
|
109
|
-
if (servicesStarted && initialSessionUrl) {
|
|
110
|
-
iframeSrc.value = toProxyUrl(initialSessionUrl);
|
|
111
|
-
}
|
|
112
155
|
try {
|
|
113
156
|
const stored = sessionStorage.getItem("__opencode_selected_elements__");
|
|
114
157
|
if (stored) {
|
|
@@ -182,38 +225,96 @@ const App = {
|
|
|
182
225
|
const selectSession = (session) => {
|
|
183
226
|
if (currentSessionId.value === session.id) return;
|
|
184
227
|
currentSessionId.value = session.id;
|
|
185
|
-
|
|
228
|
+
iframeLoading.value = true;
|
|
186
229
|
iframeSrc.value = `${proxyUrl}/${utf8ToBase64(cwd)}/session/${session.id}`;
|
|
187
|
-
setTimeout(() => {
|
|
188
|
-
loading.value = false;
|
|
189
|
-
}, 500);
|
|
190
230
|
};
|
|
191
231
|
let sseConnection = null;
|
|
232
|
+
let sseRetryCount = 0;
|
|
233
|
+
const MAX_SSE_RETRIES = 10;
|
|
234
|
+
const SSE_RETRY_DELAY = 1e3;
|
|
192
235
|
const setupSSE = () => {
|
|
193
|
-
if (
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
236
|
+
if (sseConnection) return;
|
|
237
|
+
try {
|
|
238
|
+
sseConnection = new EventSource("/__opencode_events__");
|
|
239
|
+
sseConnection.onmessage = (event) => {
|
|
240
|
+
try {
|
|
241
|
+
const data = JSON.parse(event.data);
|
|
242
|
+
if (data.type === "CONNECTED") {
|
|
243
|
+
updateContext(true);
|
|
244
|
+
sseRetryCount = 0;
|
|
245
|
+
} else if (data.type === "STATUS_SYNC") {
|
|
246
|
+
if (data.isStarted !== void 0) {
|
|
247
|
+
if (data.isStarted && serviceStatus.value === "idle") {
|
|
248
|
+
serviceStatus.value = "starting";
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
if (data.task) {
|
|
252
|
+
currentTask.value = data.task;
|
|
253
|
+
if (data.task === "ready") {
|
|
254
|
+
serviceStatus.value = "ready";
|
|
255
|
+
chromeMcpFailed.value = false;
|
|
256
|
+
if (data.sessionUrl && !iframeSrc.value) {
|
|
257
|
+
iframeSrc.value = toProxyUrl(data.sessionUrl);
|
|
258
|
+
currentSessionId.value = extractSessionId(data.sessionUrl);
|
|
259
|
+
}
|
|
260
|
+
} else if (data.task === "chrome_mcp_failed") {
|
|
261
|
+
serviceStatus.value = "partial";
|
|
262
|
+
chromeMcpFailed.value = true;
|
|
263
|
+
} else if (data.task === "session_creation_failed" || data.task === "opencode_not_installed" || data.task === "web_start_timeout") {
|
|
264
|
+
serviceStatus.value = "failed";
|
|
265
|
+
} else if (serviceStatus.value === "idle") {
|
|
266
|
+
serviceStatus.value = "starting";
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
if (serviceStatus.value !== "idle") {
|
|
270
|
+
loadSessions();
|
|
271
|
+
}
|
|
272
|
+
} else if (data.type === "TASK_UPDATE") {
|
|
273
|
+
currentTask.value = data.task;
|
|
274
|
+
if (data.task === "ready") {
|
|
275
|
+
serviceStatus.value = "ready";
|
|
276
|
+
chromeMcpFailed.value = false;
|
|
277
|
+
if (data.sessionUrl && !iframeSrc.value) {
|
|
278
|
+
iframeSrc.value = toProxyUrl(data.sessionUrl);
|
|
279
|
+
currentSessionId.value = extractSessionId(data.sessionUrl);
|
|
280
|
+
}
|
|
281
|
+
} else if (data.task === "chrome_mcp_failed") {
|
|
282
|
+
serviceStatus.value = "partial";
|
|
283
|
+
chromeMcpFailed.value = true;
|
|
284
|
+
} else if (data.task === "session_creation_failed" || data.task === "opencode_not_installed" || data.task === "web_start_timeout") {
|
|
285
|
+
serviceStatus.value = "failed";
|
|
286
|
+
} else if (serviceStatus.value === "idle") {
|
|
287
|
+
serviceStatus.value = "starting";
|
|
288
|
+
}
|
|
289
|
+
} else if (data.type === "CLEAR_ELEMENTS") {
|
|
290
|
+
selectedElements.value = [];
|
|
204
291
|
}
|
|
205
|
-
|
|
206
|
-
}
|
|
207
|
-
|
|
292
|
+
} catch (e) {
|
|
293
|
+
}
|
|
294
|
+
};
|
|
295
|
+
sseConnection.onerror = () => {
|
|
296
|
+
sseConnection == null ? void 0 : sseConnection.close();
|
|
297
|
+
sseConnection = null;
|
|
298
|
+
if (serviceStatus.value === "ready" || serviceStatus.value === "partial") {
|
|
299
|
+
serviceStatus.value = "starting";
|
|
208
300
|
}
|
|
209
|
-
|
|
301
|
+
if (sseRetryCount < MAX_SSE_RETRIES) {
|
|
302
|
+
sseRetryCount++;
|
|
303
|
+
setTimeout(setupSSE, SSE_RETRY_DELAY * sseRetryCount);
|
|
304
|
+
}
|
|
305
|
+
};
|
|
306
|
+
} catch (e) {
|
|
307
|
+
sseConnection = null;
|
|
308
|
+
if (sseRetryCount < MAX_SSE_RETRIES) {
|
|
309
|
+
sseRetryCount++;
|
|
310
|
+
setTimeout(setupSSE, SSE_RETRY_DELAY * sseRetryCount);
|
|
210
311
|
}
|
|
211
|
-
}
|
|
312
|
+
}
|
|
212
313
|
};
|
|
213
314
|
let currentPageUrl = "";
|
|
214
315
|
let currentPageTitle = "";
|
|
215
316
|
const updateContext = (force = false) => {
|
|
216
|
-
if (
|
|
317
|
+
if (serviceStatus.value === "idle") return;
|
|
217
318
|
const newUrl = window.location.href;
|
|
218
319
|
const newTitle = document.title;
|
|
219
320
|
if (force || newUrl !== currentPageUrl || newTitle !== currentPageTitle) {
|
|
@@ -232,17 +333,12 @@ const App = {
|
|
|
232
333
|
}
|
|
233
334
|
};
|
|
234
335
|
const ensureServicesStarted = () => __async(null, null, function* () {
|
|
235
|
-
if (
|
|
336
|
+
if (serviceStatus.value !== "idle") return true;
|
|
236
337
|
try {
|
|
237
338
|
const res = yield fetch("/__opencode_start__");
|
|
238
339
|
const data = yield res.json();
|
|
239
340
|
if (data.success) {
|
|
240
|
-
|
|
241
|
-
if (data.sessionUrl) {
|
|
242
|
-
iframeSrc.value = toProxyUrl(data.sessionUrl);
|
|
243
|
-
currentSessionId.value = extractSessionId(data.sessionUrl);
|
|
244
|
-
isWaitingForSession.value = false;
|
|
245
|
-
}
|
|
341
|
+
serviceStatus.value = "starting";
|
|
246
342
|
setupSSE();
|
|
247
343
|
return true;
|
|
248
344
|
}
|
|
@@ -250,38 +346,62 @@ const App = {
|
|
|
250
346
|
}
|
|
251
347
|
return false;
|
|
252
348
|
});
|
|
349
|
+
const mainHotkey = parseHotkey(hotkey);
|
|
350
|
+
const selectHotkey = parseHotkey("ctrl+p");
|
|
253
351
|
(0, import_vue.onMounted)(() => {
|
|
254
|
-
if (
|
|
352
|
+
if (serviceStatus.value !== "idle") {
|
|
255
353
|
loadSessions();
|
|
256
354
|
setupSSE();
|
|
257
355
|
updateContext(true);
|
|
258
356
|
}
|
|
259
|
-
if (autoOpen &&
|
|
357
|
+
if (autoOpen && serviceStatus.value !== "idle") {
|
|
260
358
|
setTimeout(() => {
|
|
261
359
|
open.value = true;
|
|
262
360
|
}, 1e3);
|
|
263
361
|
}
|
|
264
362
|
const originalPushState = history.pushState;
|
|
265
363
|
const originalReplaceState = history.replaceState;
|
|
364
|
+
const scheduleContextUpdate = () => {
|
|
365
|
+
requestAnimationFrame(() => updateContext());
|
|
366
|
+
};
|
|
266
367
|
history.pushState = function(...args) {
|
|
267
368
|
originalPushState.apply(this, args);
|
|
268
|
-
|
|
369
|
+
scheduleContextUpdate();
|
|
269
370
|
};
|
|
270
371
|
history.replaceState = function(...args) {
|
|
271
372
|
originalReplaceState.apply(this, args);
|
|
272
|
-
|
|
373
|
+
scheduleContextUpdate();
|
|
273
374
|
};
|
|
274
|
-
window.addEventListener("popstate",
|
|
275
|
-
window.addEventListener("hashchange",
|
|
375
|
+
window.addEventListener("popstate", scheduleContextUpdate);
|
|
376
|
+
window.addEventListener("hashchange", scheduleContextUpdate);
|
|
276
377
|
const titleObserver = new MutationObserver(() => {
|
|
277
378
|
if (document.title !== currentPageTitle) updateContext();
|
|
278
379
|
});
|
|
279
380
|
if (document.head) {
|
|
280
381
|
titleObserver.observe(document.head, { childList: true, subtree: true });
|
|
281
382
|
}
|
|
383
|
+
const handleKeydown = (e) => {
|
|
384
|
+
if (matchHotkey(e, mainHotkey)) {
|
|
385
|
+
e.preventDefault();
|
|
386
|
+
handleToggle(!open.value);
|
|
387
|
+
}
|
|
388
|
+
if (matchHotkey(e, selectHotkey)) {
|
|
389
|
+
e.preventDefault();
|
|
390
|
+
const win = window;
|
|
391
|
+
if (win.__VUE_INSPECTOR__) {
|
|
392
|
+
selectMode.value = !selectMode.value;
|
|
393
|
+
} else {
|
|
394
|
+
showNotification("Vue Inspector \u672A\u52A0\u8F7D\uFF0C\u65E0\u6CD5\u4F7F\u7528\u5143\u7D20\u9009\u62E9\u529F\u80FD");
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
};
|
|
398
|
+
document.addEventListener("keydown", handleKeydown);
|
|
399
|
+
return () => {
|
|
400
|
+
document.removeEventListener("keydown", handleKeydown);
|
|
401
|
+
};
|
|
282
402
|
});
|
|
283
403
|
const handleToggle = (val) => __async(null, null, function* () {
|
|
284
|
-
if (
|
|
404
|
+
if (serviceStatus.value === "idle" && val) {
|
|
285
405
|
loading.value = true;
|
|
286
406
|
const started = yield ensureServicesStarted();
|
|
287
407
|
loading.value = false;
|
|
@@ -292,6 +412,9 @@ const App = {
|
|
|
292
412
|
}
|
|
293
413
|
open.value = val;
|
|
294
414
|
if (val) updateContext();
|
|
415
|
+
if (val) {
|
|
416
|
+
iframeLoading.value = false;
|
|
417
|
+
}
|
|
295
418
|
});
|
|
296
419
|
const handleSelectNode = (element) => {
|
|
297
420
|
const exists = selectedElements.value.some(
|
|
@@ -311,45 +434,116 @@ const App = {
|
|
|
311
434
|
showNotification("\u5DF2\u6E05\u9664\u6240\u6709\u9009\u4E2D\u5143\u7D20");
|
|
312
435
|
};
|
|
313
436
|
return () => {
|
|
314
|
-
return (0, import_vue.h)(
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
437
|
+
return (0, import_vue.h)(
|
|
438
|
+
import_components.OpenCodeWidget,
|
|
439
|
+
{
|
|
440
|
+
ref: widgetRef,
|
|
441
|
+
position,
|
|
442
|
+
theme: theme.value,
|
|
443
|
+
open: open.value,
|
|
444
|
+
selectMode: selectMode.value,
|
|
445
|
+
sessionListCollapsed: sessionListCollapsed.value,
|
|
446
|
+
frameLoading: computedLoading.value,
|
|
447
|
+
loadingSessionList: loadingSessionList.value,
|
|
448
|
+
showSessionListSkeleton: showSessionListSkeleton.value,
|
|
449
|
+
showError: chromeMcpFailed.value,
|
|
450
|
+
iframeSrc: iframeSrc.value,
|
|
451
|
+
currentSessionId: currentSessionId.value,
|
|
452
|
+
sessions: sessions.value,
|
|
453
|
+
sessionKey: "id",
|
|
454
|
+
selectedElements: selectedElements.value,
|
|
455
|
+
hotkeyLabel: hotkey,
|
|
456
|
+
"onUpdate:open": handleToggle,
|
|
457
|
+
"onUpdate:selectMode": (val) => {
|
|
458
|
+
selectMode.value = val;
|
|
459
|
+
if (!val && !open.value) {
|
|
460
|
+
open.value = true;
|
|
461
|
+
}
|
|
462
|
+
},
|
|
463
|
+
"onUpdate:sessionListCollapsed": (val) => {
|
|
464
|
+
sessionListCollapsed.value = val;
|
|
465
|
+
},
|
|
466
|
+
"onUpdate:theme": (val) => {
|
|
467
|
+
theme.value = val;
|
|
468
|
+
},
|
|
469
|
+
"onToggle-theme": (val) => {
|
|
470
|
+
theme.value = val;
|
|
471
|
+
},
|
|
472
|
+
"onCreate-session": createSession,
|
|
473
|
+
"onDelete-session": deleteSession,
|
|
474
|
+
"onSelect-session": selectSession,
|
|
475
|
+
"onClick-selected-node": handleSelectNode,
|
|
476
|
+
"onClear-selected-nodes": handleClearSelected,
|
|
477
|
+
"onRemove-selected-node": ({ index }) => {
|
|
478
|
+
selectedElements.value.splice(index, 1);
|
|
479
|
+
updateContext(true);
|
|
480
|
+
},
|
|
481
|
+
"onEmpty-action": createSession,
|
|
482
|
+
"onFrame-loaded": () => {
|
|
483
|
+
iframeLoading.value = false;
|
|
484
|
+
}
|
|
350
485
|
},
|
|
351
|
-
|
|
352
|
-
|
|
486
|
+
{
|
|
487
|
+
loading: () => (0, import_vue.h)("div", { class: "opencode-custom-loading" }, [
|
|
488
|
+
(0, import_vue.h)("div", { class: "opencode-loading-spinner" }),
|
|
489
|
+
(0, import_vue.h)("div", { class: "opencode-loading-text" }, loadingText.value)
|
|
490
|
+
]),
|
|
491
|
+
error: () => chromeMcpFailed.value ? (0, import_vue.h)("div", { class: "opencode-chrome-warmup-failed" }, [
|
|
492
|
+
(0, import_vue.h)("div", { class: "opencode-chrome-warmup-failed-icon" }, [
|
|
493
|
+
(0, import_vue.h)(
|
|
494
|
+
"svg",
|
|
495
|
+
{
|
|
496
|
+
viewBox: "0 0 24 24",
|
|
497
|
+
width: "48",
|
|
498
|
+
height: "48",
|
|
499
|
+
fill: "none",
|
|
500
|
+
stroke: "currentColor",
|
|
501
|
+
strokeWidth: "1.5"
|
|
502
|
+
},
|
|
503
|
+
[
|
|
504
|
+
(0, import_vue.h)("path", {
|
|
505
|
+
strokeLinecap: "round",
|
|
506
|
+
strokeLinejoin: "round",
|
|
507
|
+
d: "M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126zM12 15.75h.007v.008H12v-.008z"
|
|
508
|
+
})
|
|
509
|
+
]
|
|
510
|
+
)
|
|
511
|
+
]),
|
|
512
|
+
(0, import_vue.h)(
|
|
513
|
+
"div",
|
|
514
|
+
{ class: "opencode-chrome-warmup-failed-title" },
|
|
515
|
+
"Chrome DevTools MCP \u8FDE\u63A5\u5931\u8D25"
|
|
516
|
+
),
|
|
517
|
+
(0, import_vue.h)("div", { class: "opencode-chrome-warmup-failed-text" }, [
|
|
518
|
+
(0, import_vue.h)("p", {}, "\u8BF7\u6309\u4EE5\u4E0B\u6B65\u9AA4\u5F00\u542F Chrome \u8FDC\u7A0B\u8C03\u8BD5\uFF1A"),
|
|
519
|
+
(0, import_vue.h)("ol", { class: "opencode-chrome-warmup-steps" }, [
|
|
520
|
+
(0, import_vue.h)("li", {}, [
|
|
521
|
+
"\u5728 Chrome \u5730\u5740\u680F\u8F93\u5165 ",
|
|
522
|
+
(0, import_vue.h)(
|
|
523
|
+
"code",
|
|
524
|
+
{ class: "opencode-chrome-warmup-code" },
|
|
525
|
+
"chrome://inspect/#remote-debugging"
|
|
526
|
+
)
|
|
527
|
+
]),
|
|
528
|
+
(0, import_vue.h)("li", {}, "\u52FE\u9009 'Allow remote debugging for this browser instance' \u9009\u9879"),
|
|
529
|
+
(0, import_vue.h)("li", {}, "\u91CD\u65B0\u542F\u52A8\u6D4F\u89C8\u5668"),
|
|
530
|
+
(0, import_vue.h)("li", {}, "\u5B8C\u6210\u540E\u70B9\u51FB\u4E0B\u65B9\u6309\u94AE\u91CD\u8BD5")
|
|
531
|
+
])
|
|
532
|
+
]),
|
|
533
|
+
(0, import_vue.h)("div", { class: "opencode-chrome-warmup-failed-actions" }, [
|
|
534
|
+
(0, import_vue.h)(
|
|
535
|
+
"button",
|
|
536
|
+
{
|
|
537
|
+
class: "opencode-chrome-warmup-failed-btn primary",
|
|
538
|
+
disabled: retryingWarmup.value,
|
|
539
|
+
onClick: retryWarmup
|
|
540
|
+
},
|
|
541
|
+
retryingWarmup.value ? "\u8FDE\u63A5\u4E2D..." : "\u91CD\u8BD5\u8FDE\u63A5"
|
|
542
|
+
)
|
|
543
|
+
])
|
|
544
|
+
]) : null
|
|
545
|
+
}
|
|
546
|
+
);
|
|
353
547
|
};
|
|
354
548
|
}
|
|
355
549
|
};
|
|
@@ -358,5 +552,148 @@ if (!window[INIT_MARKER]) {
|
|
|
358
552
|
window[INIT_MARKER] = true;
|
|
359
553
|
const container = document.createElement("div");
|
|
360
554
|
document.body.appendChild(container);
|
|
361
|
-
(0, import_vue.createApp)(App)
|
|
555
|
+
const app = (0, import_vue.createApp)(App);
|
|
556
|
+
app.mount(container);
|
|
557
|
+
window.__OPENCODE_CLEANUP__ = () => {
|
|
558
|
+
app.unmount();
|
|
559
|
+
container.remove();
|
|
560
|
+
window[INIT_MARKER] = false;
|
|
561
|
+
};
|
|
562
|
+
}
|
|
563
|
+
const style = document.createElement("style");
|
|
564
|
+
style.textContent = `
|
|
565
|
+
.opencode-custom-loading {
|
|
566
|
+
display: flex;
|
|
567
|
+
flex-direction: column;
|
|
568
|
+
align-items: center;
|
|
569
|
+
justify-content: center;
|
|
570
|
+
padding: 20px;
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
.opencode-loading-spinner {
|
|
574
|
+
width: 32px;
|
|
575
|
+
height: 32px;
|
|
576
|
+
border: 3px solid var(--oc-border);
|
|
577
|
+
border-top-color: var(--oc-primary);
|
|
578
|
+
border-radius: 50%;
|
|
579
|
+
animation: opencode-spin 0.8s linear infinite;
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
@keyframes opencode-spin {
|
|
583
|
+
to { transform: rotate(360deg); }
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
.opencode-loading-text {
|
|
587
|
+
margin-top: 12px;
|
|
588
|
+
color: var(--oc-text-secondary);
|
|
589
|
+
font-size: 14px;
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
.opencode-chrome-warmup-failed {
|
|
593
|
+
position: absolute;
|
|
594
|
+
top: 0;
|
|
595
|
+
left: 0;
|
|
596
|
+
right: 0;
|
|
597
|
+
bottom: 0;
|
|
598
|
+
background: var(--oc-bg-secondary);
|
|
599
|
+
display: flex;
|
|
600
|
+
flex-direction: column;
|
|
601
|
+
align-items: center;
|
|
602
|
+
justify-content: center;
|
|
603
|
+
z-index: 15;
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
.opencode-chrome-warmup-failed-icon {
|
|
607
|
+
color: var(--oc-warning, #f59e0b);
|
|
608
|
+
margin-bottom: 16px;
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
.opencode-chrome-warmup-failed-title {
|
|
612
|
+
color: var(--oc-text-primary);
|
|
613
|
+
font-size: 18px;
|
|
614
|
+
font-weight: 600;
|
|
615
|
+
margin-bottom: 8px;
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
.opencode-chrome-warmup-failed-text {
|
|
619
|
+
color: var(--oc-text-secondary);
|
|
620
|
+
font-size: 14px;
|
|
621
|
+
margin-bottom: 24px;
|
|
622
|
+
text-align: left;
|
|
623
|
+
max-width: 400px;
|
|
624
|
+
line-height: 1.6;
|
|
625
|
+
text-align: center;
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
.opencode-chrome-warmup-failed-text p {
|
|
629
|
+
margin: 0 0 12px 0;
|
|
630
|
+
font-weight: 500;
|
|
631
|
+
color: var(--oc-text-primary);
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
.opencode-chrome-warmup-steps {
|
|
635
|
+
margin: 0;
|
|
636
|
+
padding-left: 20px;
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
.opencode-chrome-warmup-steps li {
|
|
640
|
+
margin-bottom: 8px;
|
|
641
|
+
color: var(--oc-text-secondary);
|
|
642
|
+
font-size: 13px;
|
|
643
|
+
line-height: 1.5;
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
.opencode-chrome-warmup-steps li:last-child {
|
|
647
|
+
margin-bottom: 0;
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
.opencode-chrome-warmup-code {
|
|
651
|
+
display: inline-block;
|
|
652
|
+
background: var(--oc-bg-tertiary);
|
|
653
|
+
color: var(--oc-primary);
|
|
654
|
+
padding: 2px 6px;
|
|
655
|
+
border-radius: 4px;
|
|
656
|
+
font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
|
|
657
|
+
font-size: 12px;
|
|
658
|
+
font-weight: 500;
|
|
659
|
+
word-break: break-all;
|
|
660
|
+
margin: 0 2px;
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
.opencode-chrome-warmup-failed-actions {
|
|
664
|
+
display: flex;
|
|
665
|
+
gap: 12px;
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
.opencode-chrome-warmup-failed-btn {
|
|
669
|
+
padding: 10px 24px;
|
|
670
|
+
border-radius: 8px;
|
|
671
|
+
border: none;
|
|
672
|
+
font-size: 14px;
|
|
673
|
+
font-weight: 500;
|
|
674
|
+
cursor: pointer;
|
|
675
|
+
transition: all 0.2s;
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
.opencode-chrome-warmup-failed-btn.primary {
|
|
679
|
+
background: var(--oc-primary);
|
|
680
|
+
color: white;
|
|
681
|
+
box-shadow: var(--oc-shadow-primary);
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
.opencode-chrome-warmup-failed-btn.primary:hover:not(:disabled) {
|
|
685
|
+
background: var(--oc-primary-hover);
|
|
686
|
+
transform: translateY(-1px);
|
|
687
|
+
box-shadow: var(--oc-shadow-primary-hover);
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
.opencode-chrome-warmup-failed-btn.primary:active:not(:disabled) {
|
|
691
|
+
transform: translateY(0);
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
.opencode-chrome-warmup-failed-btn:disabled {
|
|
695
|
+
opacity: 0.6;
|
|
696
|
+
cursor: not-allowed;
|
|
362
697
|
}
|
|
698
|
+
`;
|
|
699
|
+
document.head.appendChild(style);
|