vite-plugin-opencode-assistant 1.0.13 → 1.0.15
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 +384 -86
- package/es/core/api.d.ts +1 -0
- package/es/core/api.js +97 -15
- package/es/core/proxy-server.d.ts +5 -1
- package/es/core/proxy-server.js +75 -69
- package/es/core/service.d.ts +8 -1
- package/es/core/service.js +128 -28
- 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/es/utils/system.d.ts +2 -1
- package/es/utils/system.js +11 -10
- package/lib/client/index.js +380 -85
- package/lib/client.js +2880 -2619
- package/lib/core/api.d.ts +1 -0
- package/lib/core/api.js +97 -15
- package/lib/core/proxy-server.d.ts +5 -1
- package/lib/core/proxy-server.js +75 -69
- package/lib/core/service.d.ts +8 -1
- package/lib/core/service.js +127 -28
- 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/lib/utils/system.d.ts +2 -1
- package/lib/utils/system.js +10 -5
- package/package.json +5 -5
package/lib/client/index.js
CHANGED
|
@@ -101,13 +101,40 @@ const App = {
|
|
|
101
101
|
const sessions = (0, import_vue.ref)([]);
|
|
102
102
|
const selectedElements = (0, import_vue.ref)([]);
|
|
103
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
|
+
});
|
|
104
132
|
const {
|
|
105
133
|
position = "bottom-right",
|
|
106
134
|
theme: initialTheme = "auto",
|
|
107
135
|
open: autoOpen = false,
|
|
108
|
-
sessionUrl
|
|
136
|
+
// sessionUrl 不再从配置读取,完全依赖 SSE 状态同步
|
|
109
137
|
proxyUrl: configProxyUrl = "",
|
|
110
|
-
lazy = false,
|
|
111
138
|
hotkey = "ctrl+k",
|
|
112
139
|
cwd = ""
|
|
113
140
|
} = config;
|
|
@@ -115,18 +142,16 @@ const App = {
|
|
|
115
142
|
proxyUrl = configProxyUrl;
|
|
116
143
|
}
|
|
117
144
|
const theme = (0, import_vue.ref)(initialTheme);
|
|
118
|
-
const
|
|
119
|
-
const
|
|
120
|
-
|
|
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
|
+
});
|
|
121
150
|
const extractSessionId = (url) => {
|
|
122
151
|
if (!url) return null;
|
|
123
152
|
const match = url.match(/\/session\/([^/?]+)/);
|
|
124
153
|
return match ? match[1] : null;
|
|
125
154
|
};
|
|
126
|
-
currentSessionId.value = extractSessionId(initialSessionUrl);
|
|
127
|
-
if (servicesStarted && initialSessionUrl) {
|
|
128
|
-
iframeSrc.value = toProxyUrl(initialSessionUrl);
|
|
129
|
-
}
|
|
130
155
|
try {
|
|
131
156
|
const stored = sessionStorage.getItem("__opencode_selected_elements__");
|
|
132
157
|
if (stored) {
|
|
@@ -200,38 +225,96 @@ const App = {
|
|
|
200
225
|
const selectSession = (session) => {
|
|
201
226
|
if (currentSessionId.value === session.id) return;
|
|
202
227
|
currentSessionId.value = session.id;
|
|
203
|
-
|
|
228
|
+
iframeLoading.value = true;
|
|
204
229
|
iframeSrc.value = `${proxyUrl}/${utf8ToBase64(cwd)}/session/${session.id}`;
|
|
205
|
-
setTimeout(() => {
|
|
206
|
-
loading.value = false;
|
|
207
|
-
}, 500);
|
|
208
230
|
};
|
|
209
231
|
let sseConnection = null;
|
|
232
|
+
let sseRetryCount = 0;
|
|
233
|
+
const MAX_SSE_RETRIES = 10;
|
|
234
|
+
const SSE_RETRY_DELAY = 1e3;
|
|
210
235
|
const setupSSE = () => {
|
|
211
|
-
if (
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
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 = [];
|
|
222
291
|
}
|
|
223
|
-
|
|
224
|
-
}
|
|
225
|
-
|
|
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";
|
|
226
300
|
}
|
|
227
|
-
|
|
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);
|
|
228
311
|
}
|
|
229
|
-
}
|
|
312
|
+
}
|
|
230
313
|
};
|
|
231
314
|
let currentPageUrl = "";
|
|
232
315
|
let currentPageTitle = "";
|
|
233
316
|
const updateContext = (force = false) => {
|
|
234
|
-
if (
|
|
317
|
+
if (serviceStatus.value === "idle") return;
|
|
235
318
|
const newUrl = window.location.href;
|
|
236
319
|
const newTitle = document.title;
|
|
237
320
|
if (force || newUrl !== currentPageUrl || newTitle !== currentPageTitle) {
|
|
@@ -250,17 +333,12 @@ const App = {
|
|
|
250
333
|
}
|
|
251
334
|
};
|
|
252
335
|
const ensureServicesStarted = () => __async(null, null, function* () {
|
|
253
|
-
if (
|
|
336
|
+
if (serviceStatus.value !== "idle") return true;
|
|
254
337
|
try {
|
|
255
338
|
const res = yield fetch("/__opencode_start__");
|
|
256
339
|
const data = yield res.json();
|
|
257
340
|
if (data.success) {
|
|
258
|
-
|
|
259
|
-
if (data.sessionUrl) {
|
|
260
|
-
iframeSrc.value = toProxyUrl(data.sessionUrl);
|
|
261
|
-
currentSessionId.value = extractSessionId(data.sessionUrl);
|
|
262
|
-
isWaitingForSession.value = false;
|
|
263
|
-
}
|
|
341
|
+
serviceStatus.value = "starting";
|
|
264
342
|
setupSSE();
|
|
265
343
|
return true;
|
|
266
344
|
}
|
|
@@ -271,28 +349,31 @@ const App = {
|
|
|
271
349
|
const mainHotkey = parseHotkey(hotkey);
|
|
272
350
|
const selectHotkey = parseHotkey("ctrl+p");
|
|
273
351
|
(0, import_vue.onMounted)(() => {
|
|
274
|
-
if (
|
|
352
|
+
if (serviceStatus.value !== "idle") {
|
|
275
353
|
loadSessions();
|
|
276
354
|
setupSSE();
|
|
277
355
|
updateContext(true);
|
|
278
356
|
}
|
|
279
|
-
if (autoOpen &&
|
|
357
|
+
if (autoOpen && serviceStatus.value !== "idle") {
|
|
280
358
|
setTimeout(() => {
|
|
281
359
|
open.value = true;
|
|
282
360
|
}, 1e3);
|
|
283
361
|
}
|
|
284
362
|
const originalPushState = history.pushState;
|
|
285
363
|
const originalReplaceState = history.replaceState;
|
|
364
|
+
const scheduleContextUpdate = () => {
|
|
365
|
+
requestAnimationFrame(() => updateContext());
|
|
366
|
+
};
|
|
286
367
|
history.pushState = function(...args) {
|
|
287
368
|
originalPushState.apply(this, args);
|
|
288
|
-
|
|
369
|
+
scheduleContextUpdate();
|
|
289
370
|
};
|
|
290
371
|
history.replaceState = function(...args) {
|
|
291
372
|
originalReplaceState.apply(this, args);
|
|
292
|
-
|
|
373
|
+
scheduleContextUpdate();
|
|
293
374
|
};
|
|
294
|
-
window.addEventListener("popstate",
|
|
295
|
-
window.addEventListener("hashchange",
|
|
375
|
+
window.addEventListener("popstate", scheduleContextUpdate);
|
|
376
|
+
window.addEventListener("hashchange", scheduleContextUpdate);
|
|
296
377
|
const titleObserver = new MutationObserver(() => {
|
|
297
378
|
if (document.title !== currentPageTitle) updateContext();
|
|
298
379
|
});
|
|
@@ -320,7 +401,7 @@ const App = {
|
|
|
320
401
|
};
|
|
321
402
|
});
|
|
322
403
|
const handleToggle = (val) => __async(null, null, function* () {
|
|
323
|
-
if (
|
|
404
|
+
if (serviceStatus.value === "idle" && val) {
|
|
324
405
|
loading.value = true;
|
|
325
406
|
const started = yield ensureServicesStarted();
|
|
326
407
|
loading.value = false;
|
|
@@ -331,6 +412,9 @@ const App = {
|
|
|
331
412
|
}
|
|
332
413
|
open.value = val;
|
|
333
414
|
if (val) updateContext();
|
|
415
|
+
if (val) {
|
|
416
|
+
iframeLoading.value = false;
|
|
417
|
+
}
|
|
334
418
|
});
|
|
335
419
|
const handleSelectNode = (element) => {
|
|
336
420
|
const exists = selectedElements.value.some(
|
|
@@ -350,48 +434,116 @@ const App = {
|
|
|
350
434
|
showNotification("\u5DF2\u6E05\u9664\u6240\u6709\u9009\u4E2D\u5143\u7D20");
|
|
351
435
|
};
|
|
352
436
|
return () => {
|
|
353
|
-
return (0, import_vue.h)(
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
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;
|
|
373
484
|
}
|
|
374
485
|
},
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
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
|
+
);
|
|
395
547
|
};
|
|
396
548
|
}
|
|
397
549
|
};
|
|
@@ -400,5 +552,148 @@ if (!window[INIT_MARKER]) {
|
|
|
400
552
|
window[INIT_MARKER] = true;
|
|
401
553
|
const container = document.createElement("div");
|
|
402
554
|
document.body.appendChild(container);
|
|
403
|
-
(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;
|
|
404
697
|
}
|
|
698
|
+
`;
|
|
699
|
+
document.head.appendChild(style);
|