vite-plugin-opencode-assistant 1.0.15 → 1.0.16
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 +300 -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 +324 -69
- package/es/core/proxy-server.js +127 -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 +329 -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 +2988 -2973
- package/lib/core/api.d.ts +18 -6
- package/lib/core/api.js +321 -74
- package/lib/core/proxy-server.js +127 -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/client/index.js
CHANGED
|
@@ -1,79 +1,29 @@
|
|
|
1
|
+
var __create = Object.create;
|
|
1
2
|
var __defProp = Object.defineProperty;
|
|
2
|
-
var
|
|
3
|
-
var
|
|
4
|
-
var
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
5
6
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
-
var
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
for (var prop of __getOwnPropSymbols(b)) {
|
|
14
|
-
if (__propIsEnum.call(b, prop))
|
|
15
|
-
__defNormalProp(a, prop, b[prop]);
|
|
16
|
-
}
|
|
17
|
-
return a;
|
|
18
|
-
};
|
|
19
|
-
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
|
|
20
|
-
var __async = (__this, __arguments, generator) => {
|
|
21
|
-
return new Promise((resolve, reject) => {
|
|
22
|
-
var fulfilled = (value) => {
|
|
23
|
-
try {
|
|
24
|
-
step(generator.next(value));
|
|
25
|
-
} catch (e) {
|
|
26
|
-
reject(e);
|
|
27
|
-
}
|
|
28
|
-
};
|
|
29
|
-
var rejected = (value) => {
|
|
30
|
-
try {
|
|
31
|
-
step(generator.throw(value));
|
|
32
|
-
} catch (e) {
|
|
33
|
-
reject(e);
|
|
34
|
-
}
|
|
35
|
-
};
|
|
36
|
-
var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
|
|
37
|
-
step((generator = generator.apply(__this, __arguments)).next());
|
|
38
|
-
});
|
|
7
|
+
var __copyProps = (to, from, except, desc) => {
|
|
8
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
9
|
+
for (let key of __getOwnPropNames(from))
|
|
10
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
11
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
12
|
+
}
|
|
13
|
+
return to;
|
|
39
14
|
};
|
|
15
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
16
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
17
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
18
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
19
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
20
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
21
|
+
mod
|
|
22
|
+
));
|
|
40
23
|
var import_vue = require("vue");
|
|
41
|
-
var import_components = require("@vite-plugin-opencode-assistant/components");
|
|
42
|
-
var import_style = require("@vite-plugin-opencode-assistant/components/style.css");
|
|
43
24
|
var import_shared = require("@vite-plugin-opencode-assistant/shared");
|
|
44
|
-
|
|
45
|
-
|
|
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
|
-
}
|
|
62
|
-
function utf8ToBase64(str) {
|
|
63
|
-
const bytes = new TextEncoder().encode(str);
|
|
64
|
-
const binString = Array.from(bytes, (byte) => String.fromCodePoint(byte)).join("");
|
|
65
|
-
return btoa(binString);
|
|
66
|
-
}
|
|
67
|
-
let proxyUrl = "";
|
|
68
|
-
function toProxyUrl(url) {
|
|
69
|
-
if (!url || !proxyUrl) return url;
|
|
70
|
-
try {
|
|
71
|
-
const urlObj = new URL(url, window.location.origin);
|
|
72
|
-
return `${proxyUrl}${urlObj.pathname}${urlObj.search}`;
|
|
73
|
-
} catch (e) {
|
|
74
|
-
return url;
|
|
75
|
-
}
|
|
76
|
-
}
|
|
25
|
+
var import_App_vue = __toESM(require("./App.vue.js"));
|
|
26
|
+
var import_styles = require("./styles.css");
|
|
77
27
|
let config = {};
|
|
78
28
|
const scriptTag = document.querySelector(`script[${import_shared.CONFIG_DATA_ATTR}]`);
|
|
79
29
|
if (scriptTag) {
|
|
@@ -89,470 +39,12 @@ if (scriptTag) {
|
|
|
89
39
|
}
|
|
90
40
|
}
|
|
91
41
|
}
|
|
92
|
-
const App = {
|
|
93
|
-
setup() {
|
|
94
|
-
const open = (0, import_vue.ref)(false);
|
|
95
|
-
const selectMode = (0, import_vue.ref)(false);
|
|
96
|
-
const sessionListCollapsed = (0, import_vue.ref)(true);
|
|
97
|
-
const loading = (0, import_vue.ref)(false);
|
|
98
|
-
const loadingSessionList = (0, import_vue.ref)(void 0);
|
|
99
|
-
const iframeSrc = (0, import_vue.ref)("");
|
|
100
|
-
const currentSessionId = (0, import_vue.ref)(null);
|
|
101
|
-
const sessions = (0, import_vue.ref)([]);
|
|
102
|
-
const selectedElements = (0, import_vue.ref)([]);
|
|
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
|
-
});
|
|
132
|
-
const {
|
|
133
|
-
position = "bottom-right",
|
|
134
|
-
theme: initialTheme = "auto",
|
|
135
|
-
open: autoOpen = false,
|
|
136
|
-
// sessionUrl 不再从配置读取,完全依赖 SSE 状态同步
|
|
137
|
-
proxyUrl: configProxyUrl = "",
|
|
138
|
-
hotkey = "ctrl+k",
|
|
139
|
-
cwd = ""
|
|
140
|
-
} = config;
|
|
141
|
-
if (configProxyUrl) {
|
|
142
|
-
proxyUrl = configProxyUrl;
|
|
143
|
-
}
|
|
144
|
-
const theme = (0, import_vue.ref)(initialTheme);
|
|
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
|
-
});
|
|
150
|
-
const extractSessionId = (url) => {
|
|
151
|
-
if (!url) return null;
|
|
152
|
-
const match = url.match(/\/session\/([^/?]+)/);
|
|
153
|
-
return match ? match[1] : null;
|
|
154
|
-
};
|
|
155
|
-
try {
|
|
156
|
-
const stored = sessionStorage.getItem("__opencode_selected_elements__");
|
|
157
|
-
if (stored) {
|
|
158
|
-
selectedElements.value = JSON.parse(stored);
|
|
159
|
-
}
|
|
160
|
-
} catch (e) {
|
|
161
|
-
}
|
|
162
|
-
(0, import_vue.watch)(
|
|
163
|
-
selectedElements,
|
|
164
|
-
(val) => {
|
|
165
|
-
sessionStorage.setItem("__opencode_selected_elements__", JSON.stringify(val));
|
|
166
|
-
},
|
|
167
|
-
{ deep: true }
|
|
168
|
-
);
|
|
169
|
-
const showNotification = (msg) => {
|
|
170
|
-
var _a, _b;
|
|
171
|
-
(_b = (_a = widgetRef.value) == null ? void 0 : _a.showNotification) == null ? void 0 : _b.call(_a, msg);
|
|
172
|
-
};
|
|
173
|
-
const loadSessions = () => __async(null, null, function* () {
|
|
174
|
-
loadingSessionList.value = true;
|
|
175
|
-
try {
|
|
176
|
-
const response = yield fetch("/__opencode_sessions__");
|
|
177
|
-
const data = yield response.json();
|
|
178
|
-
sessions.value = data.filter((s) => s.directory === cwd && s.title !== "__chrome_mcp_warmup__").map((s) => {
|
|
179
|
-
var _a;
|
|
180
|
-
return __spreadProps(__spreadValues({}, s), {
|
|
181
|
-
updatedAt: ((_a = s.time) == null ? void 0 : _a.updated) || Date.now()
|
|
182
|
-
});
|
|
183
|
-
});
|
|
184
|
-
} catch (e) {
|
|
185
|
-
console.error("[OpenCode] Failed to load sessions:", e);
|
|
186
|
-
} finally {
|
|
187
|
-
loadingSessionList.value = false;
|
|
188
|
-
}
|
|
189
|
-
});
|
|
190
|
-
const createSession = () => __async(null, null, function* () {
|
|
191
|
-
try {
|
|
192
|
-
const response = yield fetch("/__opencode_sessions__", { method: "POST" });
|
|
193
|
-
const newSession = yield response.json();
|
|
194
|
-
sessions.value.unshift({
|
|
195
|
-
id: newSession.id,
|
|
196
|
-
title: "\u65B0\u4F1A\u8BDD",
|
|
197
|
-
updatedAt: Date.now()
|
|
198
|
-
});
|
|
199
|
-
currentSessionId.value = newSession.id;
|
|
200
|
-
iframeSrc.value = `${proxyUrl}/${utf8ToBase64(cwd)}/session/${newSession.id}`;
|
|
201
|
-
loadSessions();
|
|
202
|
-
} catch (e) {
|
|
203
|
-
showNotification("\u521B\u5EFA\u4F1A\u8BDD\u5931\u8D25");
|
|
204
|
-
}
|
|
205
|
-
});
|
|
206
|
-
const deleteSession = (session) => __async(null, null, function* () {
|
|
207
|
-
try {
|
|
208
|
-
yield fetch(`/__opencode_sessions__?id=${session.id}`, { method: "DELETE" });
|
|
209
|
-
yield loadSessions();
|
|
210
|
-
showNotification("\u4F1A\u8BDD\u5DF2\u5220\u9664");
|
|
211
|
-
if (currentSessionId.value === session.id) {
|
|
212
|
-
if (sessions.value.length > 0) {
|
|
213
|
-
const nextSession = sessions.value[0];
|
|
214
|
-
currentSessionId.value = nextSession.id;
|
|
215
|
-
iframeSrc.value = `${proxyUrl}/${utf8ToBase64(cwd)}/session/${nextSession.id}`;
|
|
216
|
-
} else {
|
|
217
|
-
currentSessionId.value = null;
|
|
218
|
-
iframeSrc.value = "";
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
} catch (e) {
|
|
222
|
-
showNotification("\u5220\u9664\u4F1A\u8BDD\u5931\u8D25");
|
|
223
|
-
}
|
|
224
|
-
});
|
|
225
|
-
const selectSession = (session) => {
|
|
226
|
-
if (currentSessionId.value === session.id) return;
|
|
227
|
-
currentSessionId.value = session.id;
|
|
228
|
-
iframeLoading.value = true;
|
|
229
|
-
iframeSrc.value = `${proxyUrl}/${utf8ToBase64(cwd)}/session/${session.id}`;
|
|
230
|
-
};
|
|
231
|
-
let sseConnection = null;
|
|
232
|
-
let sseRetryCount = 0;
|
|
233
|
-
const MAX_SSE_RETRIES = 10;
|
|
234
|
-
const SSE_RETRY_DELAY = 1e3;
|
|
235
|
-
const setupSSE = () => {
|
|
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 = [];
|
|
291
|
-
}
|
|
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";
|
|
300
|
-
}
|
|
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);
|
|
311
|
-
}
|
|
312
|
-
}
|
|
313
|
-
};
|
|
314
|
-
let currentPageUrl = "";
|
|
315
|
-
let currentPageTitle = "";
|
|
316
|
-
const updateContext = (force = false) => {
|
|
317
|
-
if (serviceStatus.value === "idle") return;
|
|
318
|
-
const newUrl = window.location.href;
|
|
319
|
-
const newTitle = document.title;
|
|
320
|
-
if (force || newUrl !== currentPageUrl || newTitle !== currentPageTitle) {
|
|
321
|
-
currentPageUrl = newUrl;
|
|
322
|
-
currentPageTitle = newTitle;
|
|
323
|
-
fetch("/__opencode_context__", {
|
|
324
|
-
method: "POST",
|
|
325
|
-
headers: { "Content-Type": "application/json" },
|
|
326
|
-
body: JSON.stringify({
|
|
327
|
-
url: newUrl,
|
|
328
|
-
title: newTitle,
|
|
329
|
-
selectedElements: selectedElements.value
|
|
330
|
-
})
|
|
331
|
-
}).catch(() => {
|
|
332
|
-
});
|
|
333
|
-
}
|
|
334
|
-
};
|
|
335
|
-
const ensureServicesStarted = () => __async(null, null, function* () {
|
|
336
|
-
if (serviceStatus.value !== "idle") return true;
|
|
337
|
-
try {
|
|
338
|
-
const res = yield fetch("/__opencode_start__");
|
|
339
|
-
const data = yield res.json();
|
|
340
|
-
if (data.success) {
|
|
341
|
-
serviceStatus.value = "starting";
|
|
342
|
-
setupSSE();
|
|
343
|
-
return true;
|
|
344
|
-
}
|
|
345
|
-
} catch (e) {
|
|
346
|
-
}
|
|
347
|
-
return false;
|
|
348
|
-
});
|
|
349
|
-
const mainHotkey = parseHotkey(hotkey);
|
|
350
|
-
const selectHotkey = parseHotkey("ctrl+p");
|
|
351
|
-
(0, import_vue.onMounted)(() => {
|
|
352
|
-
if (serviceStatus.value !== "idle") {
|
|
353
|
-
loadSessions();
|
|
354
|
-
setupSSE();
|
|
355
|
-
updateContext(true);
|
|
356
|
-
}
|
|
357
|
-
if (autoOpen && serviceStatus.value !== "idle") {
|
|
358
|
-
setTimeout(() => {
|
|
359
|
-
open.value = true;
|
|
360
|
-
}, 1e3);
|
|
361
|
-
}
|
|
362
|
-
const originalPushState = history.pushState;
|
|
363
|
-
const originalReplaceState = history.replaceState;
|
|
364
|
-
const scheduleContextUpdate = () => {
|
|
365
|
-
requestAnimationFrame(() => updateContext());
|
|
366
|
-
};
|
|
367
|
-
history.pushState = function(...args) {
|
|
368
|
-
originalPushState.apply(this, args);
|
|
369
|
-
scheduleContextUpdate();
|
|
370
|
-
};
|
|
371
|
-
history.replaceState = function(...args) {
|
|
372
|
-
originalReplaceState.apply(this, args);
|
|
373
|
-
scheduleContextUpdate();
|
|
374
|
-
};
|
|
375
|
-
window.addEventListener("popstate", scheduleContextUpdate);
|
|
376
|
-
window.addEventListener("hashchange", scheduleContextUpdate);
|
|
377
|
-
const titleObserver = new MutationObserver(() => {
|
|
378
|
-
if (document.title !== currentPageTitle) updateContext();
|
|
379
|
-
});
|
|
380
|
-
if (document.head) {
|
|
381
|
-
titleObserver.observe(document.head, { childList: true, subtree: true });
|
|
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
|
-
};
|
|
402
|
-
});
|
|
403
|
-
const handleToggle = (val) => __async(null, null, function* () {
|
|
404
|
-
if (serviceStatus.value === "idle" && val) {
|
|
405
|
-
loading.value = true;
|
|
406
|
-
const started = yield ensureServicesStarted();
|
|
407
|
-
loading.value = false;
|
|
408
|
-
if (!started) {
|
|
409
|
-
showNotification("\u670D\u52A1\u542F\u52A8\u5931\u8D25");
|
|
410
|
-
return;
|
|
411
|
-
}
|
|
412
|
-
}
|
|
413
|
-
open.value = val;
|
|
414
|
-
if (val) updateContext();
|
|
415
|
-
if (val) {
|
|
416
|
-
iframeLoading.value = false;
|
|
417
|
-
}
|
|
418
|
-
});
|
|
419
|
-
const handleSelectNode = (element) => {
|
|
420
|
-
const exists = selectedElements.value.some(
|
|
421
|
-
(el) => el.filePath === element.filePath && el.line === element.line
|
|
422
|
-
);
|
|
423
|
-
if (!exists) {
|
|
424
|
-
selectedElements.value.push(element);
|
|
425
|
-
showNotification(`\u5DF2\u9009\u4E2D\u5143\u7D20 (${selectedElements.value.length}\u4E2A)`);
|
|
426
|
-
updateContext(true);
|
|
427
|
-
} else {
|
|
428
|
-
showNotification("\u8BE5\u5143\u7D20\u5DF2\u9009\u4E2D");
|
|
429
|
-
}
|
|
430
|
-
};
|
|
431
|
-
const handleClearSelected = () => {
|
|
432
|
-
selectedElements.value = [];
|
|
433
|
-
updateContext(true);
|
|
434
|
-
showNotification("\u5DF2\u6E05\u9664\u6240\u6709\u9009\u4E2D\u5143\u7D20");
|
|
435
|
-
};
|
|
436
|
-
return () => {
|
|
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
|
-
}
|
|
485
|
-
},
|
|
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
|
-
);
|
|
547
|
-
};
|
|
548
|
-
}
|
|
549
|
-
};
|
|
550
42
|
const INIT_MARKER = "__OPENCODE_INITIALIZED__";
|
|
551
43
|
if (!window[INIT_MARKER]) {
|
|
552
44
|
window[INIT_MARKER] = true;
|
|
553
45
|
const container = document.createElement("div");
|
|
554
46
|
document.body.appendChild(container);
|
|
555
|
-
const app = (0, import_vue.createApp)(
|
|
47
|
+
const app = (0, import_vue.createApp)(import_App_vue.default, { config });
|
|
556
48
|
app.mount(container);
|
|
557
49
|
window.__OPENCODE_CLEANUP__ = () => {
|
|
558
50
|
app.unmount();
|
|
@@ -560,140 +52,3 @@ if (!window[INIT_MARKER]) {
|
|
|
560
52
|
window[INIT_MARKER] = false;
|
|
561
53
|
};
|
|
562
54
|
}
|
|
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;
|
|
697
|
-
}
|
|
698
|
-
`;
|
|
699
|
-
document.head.appendChild(style);
|