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.
Files changed (37) hide show
  1. package/es/client/App.vue.js +64 -36
  2. package/es/client/composables/index.d.ts +10 -0
  3. package/es/client/composables/index.js +22 -0
  4. package/es/client/composables/useOpencodeSSE.d.ts +64 -0
  5. package/es/client/composables/useOpencodeSSE.js +29 -0
  6. package/es/client/composables/useOpencodeSessionSSE.d.ts +66 -0
  7. package/es/client/composables/useOpencodeSessionSSE.js +168 -0
  8. package/es/client/composables/useSSE.d.ts +85 -18
  9. package/es/client/composables/useSSE.js +101 -44
  10. package/es/client/composables/useServerSSE.d.ts +53 -0
  11. package/es/client/composables/useServerSSE.js +36 -0
  12. package/es/client/composables/useServiceStatus.d.ts +0 -2
  13. package/es/client/composables/useServiceStatus.js +1 -7
  14. package/es/client/composables/useSessions.d.ts +24 -5
  15. package/es/client/composables/useSessions.js +16 -2
  16. package/es/core/proxy-server.js +61 -148
  17. package/es/index.js +3 -1
  18. package/lib/client/App.vue.js +63 -35
  19. package/lib/client/composables/index.d.ts +10 -0
  20. package/lib/client/composables/index.js +54 -0
  21. package/lib/client/composables/useOpencodeSSE.d.ts +64 -0
  22. package/lib/client/composables/useOpencodeSSE.js +52 -0
  23. package/lib/client/composables/useOpencodeSessionSSE.d.ts +66 -0
  24. package/lib/client/composables/useOpencodeSessionSSE.js +187 -0
  25. package/lib/client/composables/useSSE.d.ts +85 -18
  26. package/lib/client/composables/useSSE.js +100 -43
  27. package/lib/client/composables/useServerSSE.d.ts +53 -0
  28. package/lib/client/composables/useServerSSE.js +59 -0
  29. package/lib/client/composables/useServiceStatus.d.ts +0 -2
  30. package/lib/client/composables/useServiceStatus.js +1 -7
  31. package/lib/client/composables/useSessions.d.ts +24 -5
  32. package/lib/client/composables/useSessions.js +16 -2
  33. package/lib/client.js +3722 -3390
  34. package/lib/core/proxy-server.js +61 -148
  35. package/lib/index.js +3 -1
  36. package/lib/style.css +1 -1
  37. package/package.json +4 -4
@@ -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>`);
@@ -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 import_useSSE = require("./composables/useSSE");
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
- } = (0, import_useSessions.useSessions)(showNotification);
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
- setupSSE();
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
- setupSSE();
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, _b;
228
- if (((_a = event.data) == null ? void 0 : _a.type) === "OPENCODE_THINKING_STATE") {
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, thinking, loadingText, updateStatusFromTask, setStarting, setThinking, selectedElements, removeElement, clearElements, theme, sendThemeToIframe, sessions, loadingSessionList, currentSessionId, iframeSrc, iframeLoading, loadSessions, createSession, deleteSession, selectSession, updateContext, showSessionListSkeleton, computedLoading, retryWarmup, setupSSE, ensureServicesStarted, handleToggle, handleSelectNode, handleClearSelected, handleSelectModeChange, handleSessionListCollapsedChange, handleThemeChange, handleRemoveSelectedNode, handleFrameLoaded, get OpenCodeWidget() {
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.loadingText }, null, 8, ["loading-text"])
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
+ };