vite-plugin-opencode-assistant 1.0.26 → 1.0.28
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.js +64 -36
- package/es/client/composables/index.d.ts +10 -0
- package/es/client/composables/index.js +22 -0
- package/es/client/composables/useOpencodeSSE.d.ts +64 -0
- package/es/client/composables/useOpencodeSSE.js +29 -0
- package/es/client/composables/useOpencodeSessionSSE.d.ts +66 -0
- package/es/client/composables/useOpencodeSessionSSE.js +168 -0
- package/es/client/composables/useSSE.d.ts +85 -18
- package/es/client/composables/useSSE.js +101 -44
- package/es/client/composables/useServerSSE.d.ts +53 -0
- package/es/client/composables/useServerSSE.js +36 -0
- package/es/client/composables/useServiceStatus.d.ts +0 -2
- package/es/client/composables/useServiceStatus.js +1 -7
- package/es/client/composables/useSessions.d.ts +24 -5
- package/es/client/composables/useSessions.js +16 -2
- package/es/core/proxy-server.js +61 -148
- package/es/index.js +3 -1
- package/lib/client/App.vue.js +63 -35
- package/lib/client/composables/index.d.ts +10 -0
- package/lib/client/composables/index.js +54 -0
- package/lib/client/composables/useOpencodeSSE.d.ts +64 -0
- package/lib/client/composables/useOpencodeSSE.js +52 -0
- package/lib/client/composables/useOpencodeSessionSSE.d.ts +66 -0
- package/lib/client/composables/useOpencodeSessionSSE.js +187 -0
- package/lib/client/composables/useSSE.d.ts +85 -18
- package/lib/client/composables/useSSE.js +100 -43
- package/lib/client/composables/useServerSSE.d.ts +53 -0
- package/lib/client/composables/useServerSSE.js +59 -0
- package/lib/client/composables/useServiceStatus.d.ts +0 -2
- package/lib/client/composables/useServiceStatus.js +1 -7
- package/lib/client/composables/useSessions.d.ts +24 -5
- package/lib/client/composables/useSessions.js +16 -2
- package/lib/client.js +3722 -3390
- package/lib/core/proxy-server.js +61 -148
- package/lib/index.js +3 -1
- package/lib/style.css +1 -1
- package/package.json +4 -4
package/es/core/proxy-server.js
CHANGED
|
@@ -102,29 +102,33 @@ function generateBridgeScript(options) {
|
|
|
102
102
|
if (event.data && event.data.type === "OPENCODE_SET_THEME") {
|
|
103
103
|
setTheme(event.data.theme);
|
|
104
104
|
}
|
|
105
|
-
|
|
105
|
+
|
|
106
106
|
if (event.data && event.data.type === "OPENCODE_INSERT_FILE_PART") {
|
|
107
107
|
insertFilePart(event.data.element);
|
|
108
108
|
}
|
|
109
|
-
|
|
109
|
+
|
|
110
110
|
if (event.data && event.data.type === "minimize-state-change") {
|
|
111
111
|
handleMinimizeStateChange(event.data.minimized);
|
|
112
112
|
}
|
|
113
|
-
|
|
113
|
+
|
|
114
114
|
if (event.data && event.data.type === "prompt-dock-visibility-change") {
|
|
115
115
|
handlePromptDockVisibilityChange(event.data.visible);
|
|
116
116
|
}
|
|
117
117
|
});
|
|
118
118
|
|
|
119
119
|
// === \u6700\u5C0F\u5316\u72B6\u6001\u5904\u7406 ===
|
|
120
|
+
let savedMinimizedState = null;
|
|
121
|
+
let savedPromptDockVisibleState = null;
|
|
122
|
+
|
|
120
123
|
function handleMinimizeStateChange(minimized) {
|
|
124
|
+
savedMinimizedState = minimized;
|
|
121
125
|
const dockSurface = document.querySelector('[data-dock-surface="tray"]');
|
|
122
126
|
const sessionTurnList = document.querySelector('[data-slot="session-turn-list"]');
|
|
123
|
-
|
|
127
|
+
|
|
124
128
|
if (dockSurface) {
|
|
125
129
|
dockSurface.style.display = minimized ? 'none' : '';
|
|
126
130
|
}
|
|
127
|
-
|
|
131
|
+
|
|
128
132
|
if (sessionTurnList) {
|
|
129
133
|
sessionTurnList.style.paddingBottom = minimized ? '10px' : '';
|
|
130
134
|
}
|
|
@@ -132,19 +136,30 @@ function generateBridgeScript(options) {
|
|
|
132
136
|
|
|
133
137
|
// === \u5BF9\u8BDD\u6846\u663E\u793A\u72B6\u6001\u5904\u7406 ===
|
|
134
138
|
function handlePromptDockVisibilityChange(visible) {
|
|
139
|
+
savedPromptDockVisibleState = visible;
|
|
135
140
|
const promptDock = document.querySelector('[data-component="session-prompt-dock"]');
|
|
136
141
|
if (promptDock) {
|
|
137
142
|
promptDock.style.display = visible ? '' : 'none';
|
|
138
143
|
}
|
|
139
144
|
}
|
|
145
|
+
|
|
146
|
+
// === \u5E94\u7528\u4FDD\u5B58\u7684\u72B6\u6001 ===
|
|
147
|
+
function applySavedStates() {
|
|
148
|
+
if (savedMinimizedState !== null) {
|
|
149
|
+
handleMinimizeStateChange(savedMinimizedState);
|
|
150
|
+
}
|
|
151
|
+
if (savedPromptDockVisibleState !== null) {
|
|
152
|
+
handlePromptDockVisibilityChange(savedPromptDockVisibleState);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
140
155
|
|
|
141
156
|
// === \u4FDD\u5B58\u8F93\u5165\u6846\u5149\u6807\u4F4D\u7F6E ===
|
|
142
157
|
let savedRange = null;
|
|
143
|
-
|
|
158
|
+
|
|
144
159
|
function setupPromptInputListener() {
|
|
145
160
|
const promptInput = document.querySelector('[data-component="prompt-input"]');
|
|
146
161
|
if (!promptInput) return;
|
|
147
|
-
|
|
162
|
+
|
|
148
163
|
promptInput.addEventListener('blur', function() {
|
|
149
164
|
const selection = window.getSelection();
|
|
150
165
|
if (selection && selection.rangeCount > 0) {
|
|
@@ -154,7 +169,7 @@ function generateBridgeScript(options) {
|
|
|
154
169
|
}
|
|
155
170
|
}
|
|
156
171
|
});
|
|
157
|
-
|
|
172
|
+
|
|
158
173
|
promptInput.addEventListener('focus', function() {
|
|
159
174
|
savedRange = null;
|
|
160
175
|
});
|
|
@@ -180,29 +195,29 @@ function generateBridgeScript(options) {
|
|
|
180
195
|
|
|
181
196
|
const jsonStr = JSON.stringify({
|
|
182
197
|
nodeContext: {
|
|
183
|
-
"filePath": {
|
|
184
|
-
"value": filePath ?? '\u672A\u77E5',
|
|
185
|
-
"desc": "\u6E90\u7801\u6587\u4EF6\u8DEF\u5F84"
|
|
198
|
+
"filePath": {
|
|
199
|
+
"value": filePath ?? '\u672A\u77E5',
|
|
200
|
+
"desc": "\u6E90\u7801\u6587\u4EF6\u8DEF\u5F84"
|
|
186
201
|
},
|
|
187
|
-
"line": {
|
|
188
|
-
"value": line ?? '\u672A\u77E5',
|
|
189
|
-
"desc": "\u4EE3\u7801\u6240\u5728\u884C\u53F7"
|
|
202
|
+
"line": {
|
|
203
|
+
"value": line ?? '\u672A\u77E5',
|
|
204
|
+
"desc": "\u4EE3\u7801\u6240\u5728\u884C\u53F7"
|
|
190
205
|
},
|
|
191
|
-
"column": {
|
|
192
|
-
"value": column ?? '\u672A\u77E5',
|
|
193
|
-
"desc": "\u4EE3\u7801\u6240\u5728\u5217\u53F7"
|
|
206
|
+
"column": {
|
|
207
|
+
"value": column ?? '\u672A\u77E5',
|
|
208
|
+
"desc": "\u4EE3\u7801\u6240\u5728\u5217\u53F7"
|
|
194
209
|
},
|
|
195
|
-
"description": {
|
|
196
|
-
"value": description ?? '\u672A\u77E5',
|
|
197
|
-
"desc": "DOM \u5143\u7D20\u9009\u62E9\u5668"
|
|
210
|
+
"description": {
|
|
211
|
+
"value": description ?? '\u672A\u77E5',
|
|
212
|
+
"desc": "DOM \u5143\u7D20\u9009\u62E9\u5668"
|
|
198
213
|
},
|
|
199
|
-
"innerText": {
|
|
200
|
-
"value": innerText ? innerText.substring(0, 500) : '',
|
|
201
|
-
"desc": "DOM \u5143\u7D20\u5185\u90E8\u6587\u672C"
|
|
214
|
+
"innerText": {
|
|
215
|
+
"value": innerText ? innerText.substring(0, 500) : '',
|
|
216
|
+
"desc": "DOM \u5143\u7D20\u5185\u90E8\u6587\u672C"
|
|
202
217
|
},
|
|
203
|
-
"selectAt": {
|
|
204
|
-
"value": previewPageUrl || '\u672A\u77E5',
|
|
205
|
-
"desc": "\u7528\u6237\u9009\u4E2D\u8282\u70B9\u65F6\u7684\u9875\u9762 URL"
|
|
218
|
+
"selectAt": {
|
|
219
|
+
"value": previewPageUrl || '\u672A\u77E5',
|
|
220
|
+
"desc": "\u7528\u6237\u9009\u4E2D\u8282\u70B9\u65F6\u7684\u9875\u9762 URL"
|
|
206
221
|
}
|
|
207
222
|
}
|
|
208
223
|
});
|
|
@@ -211,30 +226,30 @@ function generateBridgeScript(options) {
|
|
|
211
226
|
span.setAttribute('data-type', 'file');
|
|
212
227
|
span.setAttribute('data-path', jsonStr);
|
|
213
228
|
span.setAttribute('contenteditable', 'false');
|
|
214
|
-
|
|
229
|
+
|
|
215
230
|
span.textContent = displayText;
|
|
216
231
|
|
|
217
232
|
if (savedRange) {
|
|
218
233
|
const range = savedRange;
|
|
219
234
|
range.collapse(false);
|
|
220
235
|
range.insertNode(span);
|
|
221
|
-
|
|
236
|
+
|
|
222
237
|
const space = document.createTextNode('\\u00A0');
|
|
223
238
|
span.parentNode.insertBefore(space, span.nextSibling);
|
|
224
|
-
|
|
239
|
+
|
|
225
240
|
const newRange = document.createRange();
|
|
226
241
|
newRange.setStartAfter(space);
|
|
227
242
|
newRange.collapse(true);
|
|
228
|
-
|
|
243
|
+
|
|
229
244
|
promptInput.focus();
|
|
230
|
-
|
|
245
|
+
|
|
231
246
|
const selection = window.getSelection();
|
|
232
247
|
if (selection) {
|
|
233
248
|
selection.removeAllRanges();
|
|
234
249
|
selection.addRange(newRange);
|
|
235
250
|
}
|
|
236
251
|
savedRange = null;
|
|
237
|
-
|
|
252
|
+
|
|
238
253
|
promptInput.dispatchEvent(new Event('input', { bubbles: true }));
|
|
239
254
|
return;
|
|
240
255
|
}
|
|
@@ -242,20 +257,20 @@ function generateBridgeScript(options) {
|
|
|
242
257
|
const selection = window.getSelection();
|
|
243
258
|
if (selection && selection.rangeCount > 0) {
|
|
244
259
|
const range = selection.getRangeAt(0);
|
|
245
|
-
|
|
260
|
+
|
|
246
261
|
if (promptInput.contains(range.commonAncestorContainer)) {
|
|
247
262
|
range.collapse(false);
|
|
248
263
|
range.insertNode(span);
|
|
249
|
-
|
|
264
|
+
|
|
250
265
|
const space = document.createTextNode('\\u00A0');
|
|
251
266
|
span.parentNode.insertBefore(space, span.nextSibling);
|
|
252
|
-
|
|
267
|
+
|
|
253
268
|
const newRange = document.createRange();
|
|
254
269
|
newRange.setStartAfter(space);
|
|
255
270
|
newRange.collapse(true);
|
|
256
271
|
selection.removeAllRanges();
|
|
257
272
|
selection.addRange(newRange);
|
|
258
|
-
|
|
273
|
+
|
|
259
274
|
promptInput.dispatchEvent(new Event('input', { bubbles: true }));
|
|
260
275
|
return;
|
|
261
276
|
}
|
|
@@ -264,7 +279,7 @@ function generateBridgeScript(options) {
|
|
|
264
279
|
promptInput.appendChild(span);
|
|
265
280
|
const space = document.createTextNode('\\u00A0');
|
|
266
281
|
promptInput.appendChild(space);
|
|
267
|
-
|
|
282
|
+
|
|
268
283
|
const newRange = document.createRange();
|
|
269
284
|
newRange.setStartAfter(space);
|
|
270
285
|
newRange.collapse(true);
|
|
@@ -273,120 +288,18 @@ function generateBridgeScript(options) {
|
|
|
273
288
|
newSelection.removeAllRanges();
|
|
274
289
|
newSelection.addRange(newRange);
|
|
275
290
|
}
|
|
276
|
-
|
|
291
|
+
|
|
277
292
|
promptInput.dispatchEvent(new Event('input', { bubbles: true }));
|
|
278
293
|
promptInput.focus();
|
|
279
294
|
}
|
|
280
295
|
|
|
281
|
-
// === \u601D\u8003\u72B6\u6001\u76D1\u542C (\u5B8C\u5168\u590D\u523B OpenCode Web \u5B9E\u73B0) ===
|
|
282
|
-
// OpenCode Web \u6838\u5FC3\u903B\u8F91:
|
|
283
|
-
// working = !!pending() || sessionStatus().type !== "idle"
|
|
284
|
-
// pending = \u6700\u540E\u4E00\u6761\u672A\u5B8C\u6210\u7684 assistant \u6D88\u606F (time.completed \u4E0D\u662F\u6570\u5B57)
|
|
285
|
-
// sessionStatus = sync.data.session_status[sessionID]
|
|
286
|
-
|
|
287
|
-
let eventSource = null;
|
|
288
|
-
const sessionStatus = {};
|
|
289
|
-
const pendingMessages = {};
|
|
290
|
-
|
|
291
|
-
function getCurrentSessionID() {
|
|
292
|
-
const match = window.location.pathname.match(/\\/session\\/([^\\/]+)/);
|
|
293
|
-
return match ? match[1] : null;
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
function isPending(message) {
|
|
297
|
-
return message.role === 'assistant' && typeof message.time?.completed !== 'number';
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
function updateThinkingState(sessionID) {
|
|
301
|
-
const status = sessionStatus[sessionID];
|
|
302
|
-
const pending = pendingMessages[sessionID];
|
|
303
|
-
|
|
304
|
-
const isThinking = !!pending || (status && status.type !== 'idle');
|
|
305
|
-
|
|
306
|
-
if (window.parent !== window) {
|
|
307
|
-
window.parent.postMessage({
|
|
308
|
-
type: 'OPENCODE_THINKING_STATE',
|
|
309
|
-
thinking: isThinking,
|
|
310
|
-
sessionID: sessionID,
|
|
311
|
-
statusType: status?.type || 'idle',
|
|
312
|
-
hasPending: !!pending
|
|
313
|
-
}, '*');
|
|
314
|
-
}
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
function handleEvent(payload) {
|
|
318
|
-
const type = payload.type;
|
|
319
|
-
const props = payload.properties;
|
|
320
|
-
|
|
321
|
-
switch (type) {
|
|
322
|
-
case 'session.status': {
|
|
323
|
-
const sessionID = props.sessionID;
|
|
324
|
-
sessionStatus[sessionID] = props.status;
|
|
325
|
-
updateThinkingState(sessionID);
|
|
326
|
-
break;
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
case 'message.updated': {
|
|
330
|
-
const info = props.info;
|
|
331
|
-
if (!info || !info.sessionID) break;
|
|
332
|
-
const sessionID = info.sessionID;
|
|
333
|
-
|
|
334
|
-
if (info.role === 'assistant') {
|
|
335
|
-
if (isPending(info)) {
|
|
336
|
-
pendingMessages[sessionID] = info;
|
|
337
|
-
} else {
|
|
338
|
-
delete pendingMessages[sessionID];
|
|
339
|
-
}
|
|
340
|
-
updateThinkingState(sessionID);
|
|
341
|
-
}
|
|
342
|
-
break;
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
case 'message.part.delta': {
|
|
346
|
-
const sessionID = props.sessionID;
|
|
347
|
-
if (sessionID && !pendingMessages[sessionID]) {
|
|
348
|
-
pendingMessages[sessionID] = { role: 'assistant', time: {} };
|
|
349
|
-
updateThinkingState(sessionID);
|
|
350
|
-
}
|
|
351
|
-
break;
|
|
352
|
-
}
|
|
353
|
-
}
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
function setupThinkingListener() {
|
|
357
|
-
if (eventSource) {
|
|
358
|
-
eventSource.close();
|
|
359
|
-
}
|
|
360
|
-
|
|
361
|
-
eventSource = new EventSource('/global/event');
|
|
362
|
-
|
|
363
|
-
eventSource.onmessage = function(event) {
|
|
364
|
-
try {
|
|
365
|
-
const data = JSON.parse(event.data);
|
|
366
|
-
const payload = data.payload;
|
|
367
|
-
if (!payload) return;
|
|
368
|
-
handleEvent(payload);
|
|
369
|
-
} catch (e) {
|
|
370
|
-
// ignore parse errors
|
|
371
|
-
}
|
|
372
|
-
};
|
|
373
|
-
|
|
374
|
-
eventSource.onerror = function(err) {
|
|
375
|
-
console.warn('[OpenCode Bridge] SSE connection error, retrying in 3s...');
|
|
376
|
-
eventSource.close();
|
|
377
|
-
setTimeout(setupThinkingListener, 3000);
|
|
378
|
-
};
|
|
379
|
-
|
|
380
|
-
console.log('[OpenCode Bridge] SSE listener setup complete');
|
|
381
|
-
}
|
|
382
|
-
|
|
383
296
|
// === \u5C31\u7EEA\u901A\u77E5 ===
|
|
384
297
|
function init() {
|
|
385
298
|
if (window.parent !== window) {
|
|
386
299
|
window.parent.postMessage({ type: "OPENCODE_READY" }, "*");
|
|
387
300
|
}
|
|
388
|
-
setupThinkingListener();
|
|
389
301
|
setupPromptInputListener();
|
|
302
|
+
applySavedStates();
|
|
390
303
|
|
|
391
304
|
const observer = new MutationObserver(function(mutations) {
|
|
392
305
|
const promptInput = document.querySelector('[data-component="prompt-input"]');
|
|
@@ -394,6 +307,13 @@ function generateBridgeScript(options) {
|
|
|
394
307
|
setupPromptInputListener();
|
|
395
308
|
promptInput._opencodeListenerAttached = true;
|
|
396
309
|
}
|
|
310
|
+
|
|
311
|
+
// \u5F53\u76EE\u6807\u5143\u7D20\u51FA\u73B0\u65F6\u5E94\u7528\u4FDD\u5B58\u7684\u72B6\u6001
|
|
312
|
+
const promptDock = document.querySelector('[data-component="session-prompt-dock"]');
|
|
313
|
+
const dockSurface = document.querySelector('[data-dock-surface="tray"]');
|
|
314
|
+
if (promptDock || dockSurface) {
|
|
315
|
+
applySavedStates();
|
|
316
|
+
}
|
|
397
317
|
});
|
|
398
318
|
observer.observe(document.body, { childList: true, subtree: true });
|
|
399
319
|
}
|
|
@@ -403,13 +323,6 @@ function generateBridgeScript(options) {
|
|
|
403
323
|
} else {
|
|
404
324
|
init();
|
|
405
325
|
}
|
|
406
|
-
|
|
407
|
-
window.addEventListener('beforeunload', function() {
|
|
408
|
-
if (eventSource) {
|
|
409
|
-
eventSource.close();
|
|
410
|
-
eventSource = null;
|
|
411
|
-
}
|
|
412
|
-
});
|
|
413
326
|
})();
|
|
414
327
|
`;
|
|
415
328
|
}
|
package/es/index.js
CHANGED
|
@@ -175,7 +175,9 @@ function createOpenCodePlugin(options = {}) {
|
|
|
175
175
|
const widget = injectWidget({
|
|
176
176
|
theme: config.theme,
|
|
177
177
|
open: config.open,
|
|
178
|
-
hotkey: config.hotkey
|
|
178
|
+
hotkey: config.hotkey,
|
|
179
|
+
proxyPort: actualProxyPort,
|
|
180
|
+
proxyHost: config.hostname
|
|
179
181
|
});
|
|
180
182
|
timer.end();
|
|
181
183
|
return html.replace("</body>", `${widget}</body>`);
|
package/lib/client/App.vue.js
CHANGED
|
@@ -71,7 +71,8 @@ var import_vue = require("vue");
|
|
|
71
71
|
var import_vue2 = require("vue");
|
|
72
72
|
var import_components = require("@vite-plugin-opencode-assistant/components");
|
|
73
73
|
var import_useHotkey = require("./composables/useHotkey");
|
|
74
|
-
var
|
|
74
|
+
var import_useServerSSE = require("./composables/useServerSSE");
|
|
75
|
+
var import_useOpencodeSessionSSE = require("./composables/useOpencodeSessionSSE");
|
|
75
76
|
var import_useSessions = require("./composables/useSessions");
|
|
76
77
|
var import_useTheme = require("./composables/useTheme");
|
|
77
78
|
var import_useSelectedElements = require("./composables/useSelectedElements");
|
|
@@ -97,9 +98,14 @@ const __vue_sfc__ = /* @__PURE__ */ (0, import_vue.defineComponent)({
|
|
|
97
98
|
const {
|
|
98
99
|
theme: initialTheme = "auto",
|
|
99
100
|
open: autoOpen = false,
|
|
100
|
-
hotkey = "ctrl+k"
|
|
101
|
+
hotkey = "ctrl+k",
|
|
102
|
+
proxyPort = 4098,
|
|
103
|
+
proxyHost = "localhost"
|
|
101
104
|
} = props.config;
|
|
102
105
|
const widgetTheme = initialTheme;
|
|
106
|
+
const proxyBaseUrl = (0, import_vue2.computed)(() => {
|
|
107
|
+
return `http://${proxyHost}:${proxyPort}`;
|
|
108
|
+
});
|
|
103
109
|
const showNotification = (msg, options) => {
|
|
104
110
|
var _a, _b;
|
|
105
111
|
(_b = (_a = widgetRef.value) == null ? void 0 : _a.showNotification) == null ? void 0 : _b.call(_a, msg, options);
|
|
@@ -109,11 +115,9 @@ const __vue_sfc__ = /* @__PURE__ */ (0, import_vue.defineComponent)({
|
|
|
109
115
|
chromeMcpFailed,
|
|
110
116
|
chromeMcpErrorType,
|
|
111
117
|
chromeMcpErrorMessage,
|
|
112
|
-
thinking,
|
|
113
118
|
loadingText,
|
|
114
119
|
updateStatusFromTask,
|
|
115
|
-
setStarting
|
|
116
|
-
setThinking
|
|
120
|
+
setStarting
|
|
117
121
|
} = (0, import_useServiceStatus.useServiceStatus)();
|
|
118
122
|
const {
|
|
119
123
|
selectedElements,
|
|
@@ -133,13 +137,50 @@ const __vue_sfc__ = /* @__PURE__ */ (0, import_vue.defineComponent)({
|
|
|
133
137
|
loadSessions,
|
|
134
138
|
createSession,
|
|
135
139
|
deleteSession,
|
|
136
|
-
selectSession
|
|
137
|
-
|
|
140
|
+
selectSession,
|
|
141
|
+
updateSessionInfo
|
|
142
|
+
} = (0, import_useSessions.useSessions)({ showNotification });
|
|
138
143
|
const { updateContext } = (0, import_useContext.useContext)(serviceStatus, selectedElements);
|
|
144
|
+
const serverSSE = (0, import_useServerSSE.useServerSSE)({
|
|
145
|
+
onStatusSync: (data) => {
|
|
146
|
+
if (data.isStarted !== void 0 && data.isStarted && serviceStatus.value === "idle") {
|
|
147
|
+
setStarting();
|
|
148
|
+
}
|
|
149
|
+
if (data.task) {
|
|
150
|
+
updateStatusFromTask(data.task, data.errorType, data.errorMessage);
|
|
151
|
+
}
|
|
152
|
+
if (serviceStatus.value !== "idle") {
|
|
153
|
+
loadSessions();
|
|
154
|
+
}
|
|
155
|
+
},
|
|
156
|
+
onTaskUpdate: (data) => {
|
|
157
|
+
updateStatusFromTask(data.task, data.errorType, data.errorMessage);
|
|
158
|
+
},
|
|
159
|
+
onClearElements: () => clearElements(),
|
|
160
|
+
onConnected: () => updateContext(true)
|
|
161
|
+
});
|
|
162
|
+
const opencodeSSE = (0, import_useOpencodeSessionSSE.useOpencodeSessionSSE)({
|
|
163
|
+
proxyBaseUrl: proxyBaseUrl.value,
|
|
164
|
+
currentSessionId,
|
|
165
|
+
onConnected: () => {
|
|
166
|
+
console.log("[OpenCode] Session SSE connected");
|
|
167
|
+
},
|
|
168
|
+
onSessionUpdate: (session) => {
|
|
169
|
+
updateSessionInfo(session);
|
|
170
|
+
}
|
|
171
|
+
});
|
|
172
|
+
const thinking = opencodeSSE.hasAnyThinking;
|
|
173
|
+
const sessionStates = opencodeSSE.sessionStates;
|
|
139
174
|
const showSessionListSkeleton = (0, import_vue2.computed)(() => serviceStatus.value === "starting");
|
|
140
175
|
const computedLoading = (0, import_vue2.computed)(() => {
|
|
141
176
|
return serviceStatus.value === "starting" || iframeLoading.value;
|
|
142
177
|
});
|
|
178
|
+
const displayLoadingText = (0, import_vue2.computed)(() => {
|
|
179
|
+
if (serviceStatus.value === "starting") {
|
|
180
|
+
return loadingText.value;
|
|
181
|
+
}
|
|
182
|
+
return "\u52A0\u8F7D\u4F1A\u8BDD...";
|
|
183
|
+
});
|
|
143
184
|
const retryWarmup = () => __async(null, null, function* () {
|
|
144
185
|
retryingWarmup.value = true;
|
|
145
186
|
try {
|
|
@@ -167,24 +208,6 @@ const __vue_sfc__ = /* @__PURE__ */ (0, import_vue.defineComponent)({
|
|
|
167
208
|
retryingWarmup.value = false;
|
|
168
209
|
}
|
|
169
210
|
});
|
|
170
|
-
const { setupSSE } = (0, import_useSSE.useSSE)(
|
|
171
|
-
(data) => {
|
|
172
|
-
if (data.isStarted !== void 0 && data.isStarted && serviceStatus.value === "idle") {
|
|
173
|
-
setStarting();
|
|
174
|
-
}
|
|
175
|
-
if (data.task) {
|
|
176
|
-
updateStatusFromTask(data.task, data.errorType, data.errorMessage);
|
|
177
|
-
}
|
|
178
|
-
if (serviceStatus.value !== "idle") {
|
|
179
|
-
loadSessions();
|
|
180
|
-
}
|
|
181
|
-
},
|
|
182
|
-
(data) => {
|
|
183
|
-
updateStatusFromTask(data.task, data.errorType, data.errorMessage);
|
|
184
|
-
},
|
|
185
|
-
() => clearElements(),
|
|
186
|
-
() => updateContext(true)
|
|
187
|
-
);
|
|
188
211
|
const ensureServicesStarted = () => __async(null, null, function* () {
|
|
189
212
|
if (serviceStatus.value !== "idle") return true;
|
|
190
213
|
try {
|
|
@@ -192,7 +215,7 @@ const __vue_sfc__ = /* @__PURE__ */ (0, import_vue.defineComponent)({
|
|
|
192
215
|
const data = yield res.json();
|
|
193
216
|
if (data.success) {
|
|
194
217
|
setStarting();
|
|
195
|
-
|
|
218
|
+
serverSSE.connect();
|
|
196
219
|
return true;
|
|
197
220
|
}
|
|
198
221
|
} catch (e) {
|
|
@@ -212,10 +235,17 @@ const __vue_sfc__ = /* @__PURE__ */ (0, import_vue.defineComponent)({
|
|
|
212
235
|
showNotification("Vue Inspector \u672A\u52A0\u8F7D\uFF0C\u65E0\u6CD5\u4F7F\u7528\u5143\u7D20\u9009\u62E9\u529F\u80FD");
|
|
213
236
|
}
|
|
214
237
|
});
|
|
238
|
+
(0, import_vue2.watch)(serviceStatus, (status, oldStatus) => {
|
|
239
|
+
if (status !== "idle" && oldStatus === "idle") {
|
|
240
|
+
serverSSE.connect();
|
|
241
|
+
opencodeSSE.connect();
|
|
242
|
+
}
|
|
243
|
+
});
|
|
215
244
|
(0, import_vue2.onMounted)(() => {
|
|
216
245
|
if (serviceStatus.value !== "idle") {
|
|
217
246
|
loadSessions();
|
|
218
|
-
|
|
247
|
+
serverSSE.connect();
|
|
248
|
+
opencodeSSE.connect();
|
|
219
249
|
updateContext(true);
|
|
220
250
|
}
|
|
221
251
|
if (autoOpen && serviceStatus.value !== "idle") {
|
|
@@ -224,11 +254,8 @@ const __vue_sfc__ = /* @__PURE__ */ (0, import_vue.defineComponent)({
|
|
|
224
254
|
}, 1e3);
|
|
225
255
|
}
|
|
226
256
|
const handleIframeMessage = (event) => {
|
|
227
|
-
var _a
|
|
228
|
-
if (((_a = event.data) == null ? void 0 : _a.type) === "
|
|
229
|
-
setThinking(event.data.thinking);
|
|
230
|
-
}
|
|
231
|
-
if (((_b = event.data) == null ? void 0 : _b.type) === "OPENCODE_READY") {
|
|
257
|
+
var _a;
|
|
258
|
+
if (((_a = event.data) == null ? void 0 : _a.type) === "OPENCODE_READY") {
|
|
232
259
|
sendThemeToIframe();
|
|
233
260
|
}
|
|
234
261
|
};
|
|
@@ -283,7 +310,7 @@ const __vue_sfc__ = /* @__PURE__ */ (0, import_vue.defineComponent)({
|
|
|
283
310
|
const handleFrameLoaded = () => {
|
|
284
311
|
iframeLoading.value = false;
|
|
285
312
|
};
|
|
286
|
-
const __returned__ = { props, open, selectMode, sessionListCollapsed, loading, widgetRef, retryingWarmup, initialTheme, autoOpen, hotkey, widgetTheme, showNotification, serviceStatus, chromeMcpFailed, chromeMcpErrorType, chromeMcpErrorMessage,
|
|
313
|
+
const __returned__ = { props, open, selectMode, sessionListCollapsed, loading, widgetRef, retryingWarmup, initialTheme, autoOpen, hotkey, proxyPort, proxyHost, widgetTheme, proxyBaseUrl, showNotification, serviceStatus, chromeMcpFailed, chromeMcpErrorType, chromeMcpErrorMessage, loadingText, updateStatusFromTask, setStarting, selectedElements, removeElement, clearElements, theme, sendThemeToIframe, sessions, loadingSessionList, currentSessionId, iframeSrc, iframeLoading, loadSessions, createSession, deleteSession, selectSession, updateSessionInfo, updateContext, serverSSE, opencodeSSE, thinking, sessionStates, showSessionListSkeleton, computedLoading, displayLoadingText, retryWarmup, ensureServicesStarted, handleToggle, handleSelectNode, handleClearSelected, handleSelectModeChange, handleSessionListCollapsedChange, handleThemeChange, handleRemoveSelectedNode, handleFrameLoaded, get OpenCodeWidget() {
|
|
287
314
|
return import_components.OpenCodeWidget;
|
|
288
315
|
}, LoadingContent: import_LoadingContent_vue.default, ChromeWarmupError: import_ChromeWarmupError_vue.default };
|
|
289
316
|
Object.defineProperty(__returned__, "__isScriptSetup", { enumerable: false, value: true });
|
|
@@ -304,6 +331,7 @@ function __vue_render__(_ctx, _cache, $props, $setup, $data, $options) {
|
|
|
304
331
|
"iframe-src": $setup.iframeSrc,
|
|
305
332
|
"current-session-id": $setup.currentSessionId,
|
|
306
333
|
sessions: $setup.sessions,
|
|
334
|
+
"session-states": $setup.sessionStates,
|
|
307
335
|
"session-key": "id",
|
|
308
336
|
"hotkey-label": $setup.hotkey,
|
|
309
337
|
thinking: $setup.thinking,
|
|
@@ -322,7 +350,7 @@ function __vue_render__(_ctx, _cache, $props, $setup, $data, $options) {
|
|
|
322
350
|
onFrameLoaded: $setup.handleFrameLoaded
|
|
323
351
|
}, {
|
|
324
352
|
loading: (0, import_vue3.withCtx)(() => [
|
|
325
|
-
(0, import_vue3.createVNode)($setup["LoadingContent"], { "loading-text": $setup.
|
|
353
|
+
(0, import_vue3.createVNode)($setup["LoadingContent"], { "loading-text": $setup.displayLoadingText }, null, 8, ["loading-text"])
|
|
326
354
|
]),
|
|
327
355
|
error: (0, import_vue3.withCtx)(() => [
|
|
328
356
|
$setup.chromeMcpFailed ? ((0, import_vue3.openBlock)(), (0, import_vue3.createBlock)($setup["ChromeWarmupError"], {
|
|
@@ -335,7 +363,7 @@ function __vue_render__(_ctx, _cache, $props, $setup, $data, $options) {
|
|
|
335
363
|
]),
|
|
336
364
|
_: 1
|
|
337
365
|
/* STABLE */
|
|
338
|
-
}, 8, ["theme", "open", "select-mode", "session-list-collapsed", "frame-loading", "loading-session-list", "show-session-list-skeleton", "show-error", "iframe-src", "current-session-id", "sessions", "hotkey-label", "thinking", "onCreateSession", "onDeleteSession", "onSelectSession", "onEmptyAction"]);
|
|
366
|
+
}, 8, ["theme", "open", "select-mode", "session-list-collapsed", "frame-loading", "loading-session-list", "show-session-list-skeleton", "show-error", "iframe-src", "current-session-id", "sessions", "session-states", "hotkey-label", "thinking", "onCreateSession", "onDeleteSession", "onSelectSession", "onEmptyAction"]);
|
|
339
367
|
}
|
|
340
368
|
__vue_sfc__.render = __vue_render__;
|
|
341
369
|
var App_vue_default = __vue_sfc__;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export { useSSE } from "./useSSE";
|
|
2
|
+
export { useServerSSE } from "./useServerSSE";
|
|
3
|
+
export { useOpencodeSSE } from "./useOpencodeSSE";
|
|
4
|
+
export { useOpencodeSessionSSE } from "./useOpencodeSessionSSE";
|
|
5
|
+
export { useHotkey } from "./useHotkey";
|
|
6
|
+
export { useSessions } from "./useSessions";
|
|
7
|
+
export { useTheme } from "./useTheme";
|
|
8
|
+
export { useSelectedElements } from "./useSelectedElements";
|
|
9
|
+
export { useServiceStatus } from "./useServiceStatus";
|
|
10
|
+
export { useContext } from "./useContext";
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
|
+
var __export = (target, all) => {
|
|
6
|
+
for (var name in all)
|
|
7
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
8
|
+
};
|
|
9
|
+
var __copyProps = (to, from, except, desc) => {
|
|
10
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
11
|
+
for (let key of __getOwnPropNames(from))
|
|
12
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
13
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
14
|
+
}
|
|
15
|
+
return to;
|
|
16
|
+
};
|
|
17
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
18
|
+
var composables_exports = {};
|
|
19
|
+
__export(composables_exports, {
|
|
20
|
+
useContext: () => import_useContext.useContext,
|
|
21
|
+
useHotkey: () => import_useHotkey.useHotkey,
|
|
22
|
+
useOpencodeSSE: () => import_useOpencodeSSE.useOpencodeSSE,
|
|
23
|
+
useOpencodeSessionSSE: () => import_useOpencodeSessionSSE.useOpencodeSessionSSE,
|
|
24
|
+
useSSE: () => import_useSSE.useSSE,
|
|
25
|
+
useSelectedElements: () => import_useSelectedElements.useSelectedElements,
|
|
26
|
+
useServerSSE: () => import_useServerSSE.useServerSSE,
|
|
27
|
+
useServiceStatus: () => import_useServiceStatus.useServiceStatus,
|
|
28
|
+
useSessions: () => import_useSessions.useSessions,
|
|
29
|
+
useTheme: () => import_useTheme.useTheme
|
|
30
|
+
});
|
|
31
|
+
module.exports = __toCommonJS(composables_exports);
|
|
32
|
+
var import_useSSE = require("./useSSE");
|
|
33
|
+
var import_useServerSSE = require("./useServerSSE");
|
|
34
|
+
var import_useOpencodeSSE = require("./useOpencodeSSE");
|
|
35
|
+
var import_useOpencodeSessionSSE = require("./useOpencodeSessionSSE");
|
|
36
|
+
var import_useHotkey = require("./useHotkey");
|
|
37
|
+
var import_useSessions = require("./useSessions");
|
|
38
|
+
var import_useTheme = require("./useTheme");
|
|
39
|
+
var import_useSelectedElements = require("./useSelectedElements");
|
|
40
|
+
var import_useServiceStatus = require("./useServiceStatus");
|
|
41
|
+
var import_useContext = require("./useContext");
|
|
42
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
43
|
+
0 && (module.exports = {
|
|
44
|
+
useContext,
|
|
45
|
+
useHotkey,
|
|
46
|
+
useOpencodeSSE,
|
|
47
|
+
useOpencodeSessionSSE,
|
|
48
|
+
useSSE,
|
|
49
|
+
useSelectedElements,
|
|
50
|
+
useServerSSE,
|
|
51
|
+
useServiceStatus,
|
|
52
|
+
useSessions,
|
|
53
|
+
useTheme
|
|
54
|
+
});
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { type Ref } from "vue";
|
|
2
|
+
/**
|
|
3
|
+
* OpenCode SSE 事件 payload
|
|
4
|
+
*/
|
|
5
|
+
export interface OpencodeSSEPayload {
|
|
6
|
+
type: string;
|
|
7
|
+
properties: {
|
|
8
|
+
sessionID?: string;
|
|
9
|
+
status?: {
|
|
10
|
+
type: string;
|
|
11
|
+
};
|
|
12
|
+
info?: {
|
|
13
|
+
sessionID?: string;
|
|
14
|
+
role?: string;
|
|
15
|
+
time?: {
|
|
16
|
+
completed?: number;
|
|
17
|
+
created?: number;
|
|
18
|
+
updated?: number;
|
|
19
|
+
archived?: number;
|
|
20
|
+
compacting?: number;
|
|
21
|
+
};
|
|
22
|
+
title?: string;
|
|
23
|
+
id?: string;
|
|
24
|
+
summary?: {
|
|
25
|
+
additions?: number;
|
|
26
|
+
deletions?: number;
|
|
27
|
+
files?: number;
|
|
28
|
+
};
|
|
29
|
+
};
|
|
30
|
+
[key: string]: unknown;
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* OpenCode SSE 消息结构
|
|
35
|
+
*/
|
|
36
|
+
export interface OpencodeSSEMessage {
|
|
37
|
+
payload: OpencodeSSEPayload;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* OpenCode SSE 配置选项
|
|
41
|
+
*/
|
|
42
|
+
export interface OpencodeSSEOptions {
|
|
43
|
+
/** OpenCode proxy 基础 URL (例如: http://localhost:4098/xxx) */
|
|
44
|
+
proxyBaseUrl: string;
|
|
45
|
+
/** 是否启用 */
|
|
46
|
+
enabled?: Ref<boolean>;
|
|
47
|
+
/** 事件处理器 */
|
|
48
|
+
onEvent?: (payload: OpencodeSSEPayload) => void;
|
|
49
|
+
/** 连接成功回调 */
|
|
50
|
+
onConnected?: () => void;
|
|
51
|
+
/** 连接错误回调 */
|
|
52
|
+
onError?: (error: Error) => void;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* 监听 OpenCode SSE 事件
|
|
56
|
+
* 端点: /global/event (通过 proxy server)
|
|
57
|
+
* 只负责连接管理和消息分发,不包含业务逻辑
|
|
58
|
+
*/
|
|
59
|
+
export declare function useOpencodeSSE(options: OpencodeSSEOptions): {
|
|
60
|
+
status: Ref<import("./useSSE").SSEConnectionStatus, import("./useSSE").SSEConnectionStatus>;
|
|
61
|
+
isConnected: import("vue").ComputedRef<boolean>;
|
|
62
|
+
connect: () => void;
|
|
63
|
+
disconnect: () => void;
|
|
64
|
+
};
|