vite-plugin-opencode-assistant 1.0.15 → 1.0.17

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 (79) hide show
  1. package/es/client/App.vue.d.ts +6 -0
  2. package/es/client/App.vue.js +317 -0
  3. package/es/client/components/ChromeWarmupError-sfc.css +1 -0
  4. package/es/client/components/ChromeWarmupError.vue.d.ts +11 -0
  5. package/es/client/components/ChromeWarmupError.vue.js +196 -0
  6. package/es/client/components/LoadingContent.vue.d.ts +5 -0
  7. package/es/client/components/LoadingContent.vue.js +39 -0
  8. package/es/client/composables/useContext.d.ts +8 -0
  9. package/es/client/composables/useContext.js +63 -0
  10. package/es/client/composables/useHotkey.d.ts +12 -0
  11. package/es/client/composables/useHotkey.js +41 -0
  12. package/es/client/composables/useSSE.d.ts +20 -0
  13. package/es/client/composables/useSSE.js +61 -0
  14. package/es/client/composables/useSelectedElements.d.ts +19 -0
  15. package/es/client/composables/useSelectedElements.js +43 -0
  16. package/es/client/composables/useServiceStatus.d.ts +13 -0
  17. package/es/client/composables/useServiceStatus.js +53 -0
  18. package/es/client/composables/useSessions.d.ts +26 -0
  19. package/es/client/composables/useSessions.js +127 -0
  20. package/es/client/composables/useTheme.d.ts +12 -0
  21. package/es/client/composables/useTheme.js +42 -0
  22. package/es/client/index.d.ts +1 -1
  23. package/es/client/index.js +5 -675
  24. package/es/client/styles.css +1 -0
  25. package/es/core/api.d.ts +18 -6
  26. package/es/core/api.js +345 -89
  27. package/es/core/proxy-server.js +266 -2
  28. package/es/core/service.d.ts +9 -2
  29. package/es/core/service.js +35 -31
  30. package/es/endpoints/index.js +1 -1
  31. package/es/endpoints/sse.js +0 -3
  32. package/es/endpoints/start.d.ts +1 -2
  33. package/es/endpoints/start.js +2 -2
  34. package/es/endpoints/types.d.ts +5 -2
  35. package/es/endpoints/warmup.js +15 -3
  36. package/es/index.js +8 -12
  37. package/es/utils/system.d.ts +1 -0
  38. package/es/utils/system.js +28 -0
  39. package/lib/client/App.vue.d.ts +6 -0
  40. package/lib/client/App.vue.js +344 -0
  41. package/lib/client/components/ChromeWarmupError-sfc.css +1 -0
  42. package/lib/client/components/ChromeWarmupError.vue.d.ts +11 -0
  43. package/lib/client/components/ChromeWarmupError.vue.js +215 -0
  44. package/lib/client/components/LoadingContent.vue.d.ts +5 -0
  45. package/lib/client/components/LoadingContent.vue.js +58 -0
  46. package/lib/client/composables/useContext.d.ts +8 -0
  47. package/lib/client/composables/useContext.js +86 -0
  48. package/lib/client/composables/useHotkey.d.ts +12 -0
  49. package/lib/client/composables/useHotkey.js +66 -0
  50. package/lib/client/composables/useSSE.d.ts +20 -0
  51. package/lib/client/composables/useSSE.js +84 -0
  52. package/lib/client/composables/useSelectedElements.d.ts +19 -0
  53. package/lib/client/composables/useSelectedElements.js +66 -0
  54. package/lib/client/composables/useServiceStatus.d.ts +13 -0
  55. package/lib/client/composables/useServiceStatus.js +76 -0
  56. package/lib/client/composables/useSessions.d.ts +26 -0
  57. package/lib/client/composables/useSessions.js +148 -0
  58. package/lib/client/composables/useTheme.d.ts +12 -0
  59. package/lib/client/composables/useTheme.js +65 -0
  60. package/lib/client/index.d.ts +1 -1
  61. package/lib/client/index.js +22 -667
  62. package/lib/client/styles.css +1 -0
  63. package/lib/client.js +3280 -3109
  64. package/lib/core/api.d.ts +18 -6
  65. package/lib/core/api.js +342 -94
  66. package/lib/core/proxy-server.js +266 -2
  67. package/lib/core/service.d.ts +9 -2
  68. package/lib/core/service.js +31 -30
  69. package/lib/endpoints/index.js +1 -1
  70. package/lib/endpoints/sse.js +0 -3
  71. package/lib/endpoints/start.d.ts +1 -2
  72. package/lib/endpoints/start.js +2 -2
  73. package/lib/endpoints/types.d.ts +5 -2
  74. package/lib/endpoints/warmup.js +15 -3
  75. package/lib/index.js +8 -12
  76. package/lib/style.css +1 -1
  77. package/lib/utils/system.d.ts +1 -0
  78. package/lib/utils/system.js +29 -0
  79. package/package.json +4 -4
@@ -128,13 +128,268 @@ function generateBridgeScript(options) {
128
128
  if (event.data && event.data.type === "OPENCODE_SET_THEME") {
129
129
  setTheme(event.data.theme);
130
130
  }
131
+
132
+ if (event.data && event.data.type === "OPENCODE_INSERT_FILE_PART") {
133
+ insertFilePart(event.data.element);
134
+ }
131
135
  });
132
136
 
137
+ // === \u4FDD\u5B58\u8F93\u5165\u6846\u5149\u6807\u4F4D\u7F6E ===
138
+ let savedRange = null;
139
+
140
+ function setupPromptInputListener() {
141
+ const promptInput = document.querySelector('[data-component="prompt-input"]');
142
+ if (!promptInput) return;
143
+
144
+ promptInput.addEventListener('blur', function() {
145
+ const selection = window.getSelection();
146
+ if (selection && selection.rangeCount > 0) {
147
+ const range = selection.getRangeAt(0);
148
+ if (promptInput.contains(range.commonAncestorContainer)) {
149
+ savedRange = range.cloneRange();
150
+ }
151
+ }
152
+ });
153
+
154
+ promptInput.addEventListener('focus', function() {
155
+ savedRange = null;
156
+ });
157
+ }
158
+
159
+ // === \u63D2\u5165 File Part \u5230\u8F93\u5165\u6846 ===
160
+ function insertFilePart(element) {
161
+ const promptInput = document.querySelector('[data-component="prompt-input"]');
162
+ if (!promptInput) {
163
+ console.warn('[OpenCode Bridge] Prompt input not found');
164
+ return;
165
+ }
166
+
167
+ const { filePath, line, column, description, innerText, previewPageUrl, previewPageTitle } = element;
168
+
169
+ const selector = description || 'element';
170
+ let textPreview = '';
171
+ if (innerText && innerText.trim()) {
172
+ const trimmed = innerText.trim();
173
+ textPreview = trimmed.length > 5 ? trimmed.substring(0, 5) + '...' : trimmed;
174
+ }
175
+ const displayText = '@' + selector + (textPreview ? '(' + textPreview + ')' : '');
176
+
177
+ const jsonStr = JSON.stringify({
178
+ pageContext: {
179
+ url: previewPageUrl || '',
180
+ title: previewPageTitle || '',
181
+ },
182
+ nodeContext: {
183
+ filePath,
184
+ line,
185
+ column,
186
+ description,
187
+ innerText: innerText ? innerText.substring(0, 500) : ''
188
+ }
189
+ });
190
+
191
+ const span = document.createElement('span');
192
+ span.setAttribute('data-type', 'file');
193
+ span.setAttribute('data-path', jsonStr);
194
+ span.setAttribute('contenteditable', 'false');
195
+
196
+ span.textContent = displayText;
197
+
198
+ if (savedRange) {
199
+ const range = savedRange;
200
+ range.collapse(false);
201
+ range.insertNode(span);
202
+
203
+ const space = document.createTextNode('\\u00A0');
204
+ span.parentNode.insertBefore(space, span.nextSibling);
205
+
206
+ const newRange = document.createRange();
207
+ newRange.setStartAfter(space);
208
+ newRange.collapse(true);
209
+
210
+ promptInput.focus();
211
+
212
+ const selection = window.getSelection();
213
+ if (selection) {
214
+ selection.removeAllRanges();
215
+ selection.addRange(newRange);
216
+ }
217
+ savedRange = null;
218
+
219
+ promptInput.dispatchEvent(new Event('input', { bubbles: true }));
220
+ return;
221
+ }
222
+
223
+ const selection = window.getSelection();
224
+ if (selection && selection.rangeCount > 0) {
225
+ const range = selection.getRangeAt(0);
226
+
227
+ if (promptInput.contains(range.commonAncestorContainer)) {
228
+ range.collapse(false);
229
+ range.insertNode(span);
230
+
231
+ const space = document.createTextNode('\\u00A0');
232
+ span.parentNode.insertBefore(space, span.nextSibling);
233
+
234
+ const newRange = document.createRange();
235
+ newRange.setStartAfter(space);
236
+ newRange.collapse(true);
237
+ selection.removeAllRanges();
238
+ selection.addRange(newRange);
239
+
240
+ promptInput.dispatchEvent(new Event('input', { bubbles: true }));
241
+ return;
242
+ }
243
+ }
244
+
245
+ promptInput.appendChild(span);
246
+ const space = document.createTextNode('\\u00A0');
247
+ promptInput.appendChild(space);
248
+
249
+ const newRange = document.createRange();
250
+ newRange.setStartAfter(space);
251
+ newRange.collapse(true);
252
+ const newSelection = window.getSelection();
253
+ if (newSelection) {
254
+ newSelection.removeAllRanges();
255
+ newSelection.addRange(newRange);
256
+ }
257
+
258
+ promptInput.dispatchEvent(new Event('input', { bubbles: true }));
259
+ promptInput.focus();
260
+ }
261
+
262
+ // === \u601D\u8003\u72B6\u6001\u76D1\u542C (\u5B8C\u5168\u590D\u523B OpenCode Web \u5B9E\u73B0) ===
263
+ // OpenCode Web \u6838\u5FC3\u903B\u8F91:
264
+ // working = !!pending() || sessionStatus().type !== "idle"
265
+ // pending = \u6700\u540E\u4E00\u6761\u672A\u5B8C\u6210\u7684 assistant \u6D88\u606F (time.completed \u4E0D\u662F\u6570\u5B57)
266
+ // sessionStatus = sync.data.session_status[sessionID]
267
+
268
+ let eventSource = null;
269
+ const sessionStatus = {};
270
+ const pendingMessages = {};
271
+
272
+ function getCurrentSessionID() {
273
+ const match = window.location.pathname.match(/\\/session\\/([^\\/]+)/);
274
+ return match ? match[1] : null;
275
+ }
276
+
277
+ function isPending(message) {
278
+ return message.role === 'assistant' && typeof message.time?.completed !== 'number';
279
+ }
280
+
281
+ function updateThinkingState(sessionID) {
282
+ const status = sessionStatus[sessionID];
283
+ const pending = pendingMessages[sessionID];
284
+
285
+ const isThinking = !!pending || (status && status.type !== 'idle');
286
+
287
+ if (window.parent !== window) {
288
+ window.parent.postMessage({
289
+ type: 'OPENCODE_THINKING_STATE',
290
+ thinking: isThinking,
291
+ sessionID: sessionID,
292
+ statusType: status?.type || 'idle',
293
+ hasPending: !!pending
294
+ }, '*');
295
+ }
296
+ }
297
+
298
+ function handleEvent(payload) {
299
+ const type = payload.type;
300
+ const props = payload.properties;
301
+
302
+ switch (type) {
303
+ case 'session.status': {
304
+ const sessionID = props.sessionID;
305
+ sessionStatus[sessionID] = props.status;
306
+ updateThinkingState(sessionID);
307
+ break;
308
+ }
309
+
310
+ case 'message.updated': {
311
+ const info = props.info;
312
+ if (!info || !info.sessionID) break;
313
+ const sessionID = info.sessionID;
314
+
315
+ if (info.role === 'assistant') {
316
+ if (isPending(info)) {
317
+ pendingMessages[sessionID] = info;
318
+ } else {
319
+ delete pendingMessages[sessionID];
320
+ }
321
+ updateThinkingState(sessionID);
322
+ }
323
+ break;
324
+ }
325
+
326
+ case 'message.part.delta': {
327
+ const sessionID = props.sessionID;
328
+ if (sessionID && !pendingMessages[sessionID]) {
329
+ pendingMessages[sessionID] = { role: 'assistant', time: {} };
330
+ updateThinkingState(sessionID);
331
+ }
332
+ break;
333
+ }
334
+ }
335
+ }
336
+
337
+ function setupThinkingListener() {
338
+ if (eventSource) {
339
+ eventSource.close();
340
+ }
341
+
342
+ eventSource = new EventSource('/global/event');
343
+
344
+ eventSource.onmessage = function(event) {
345
+ try {
346
+ const data = JSON.parse(event.data);
347
+ const payload = data.payload;
348
+ if (!payload) return;
349
+ handleEvent(payload);
350
+ } catch (e) {
351
+ // ignore parse errors
352
+ }
353
+ };
354
+
355
+ eventSource.onerror = function(err) {
356
+ console.warn('[OpenCode Bridge] SSE connection error, retrying in 3s...');
357
+ eventSource.close();
358
+ setTimeout(setupThinkingListener, 3000);
359
+ };
360
+
361
+ console.log('[OpenCode Bridge] SSE listener setup complete');
362
+ }
363
+
133
364
  // === \u5C31\u7EEA\u901A\u77E5 ===
134
- window.addEventListener("load", function() {
365
+ function init() {
135
366
  if (window.parent !== window) {
136
367
  window.parent.postMessage({ type: "OPENCODE_READY" }, "*");
137
368
  }
369
+ setupThinkingListener();
370
+ setupPromptInputListener();
371
+
372
+ const observer = new MutationObserver(function(mutations) {
373
+ const promptInput = document.querySelector('[data-component="prompt-input"]');
374
+ if (promptInput && !promptInput._opencodeListenerAttached) {
375
+ setupPromptInputListener();
376
+ promptInput._opencodeListenerAttached = true;
377
+ }
378
+ });
379
+ observer.observe(document.body, { childList: true, subtree: true });
380
+ }
381
+
382
+ if (document.readyState === 'loading') {
383
+ document.addEventListener('DOMContentLoaded', init);
384
+ } else {
385
+ init();
386
+ }
387
+
388
+ window.addEventListener('beforeunload', function() {
389
+ if (eventSource) {
390
+ eventSource.close();
391
+ eventSource = null;
392
+ }
138
393
  });
139
394
  })();
140
395
  `;
@@ -162,7 +417,8 @@ function startProxyServer(targetUrl, port, options = {}) {
162
417
  headers: __spreadProps(__spreadValues({}, req.headers), {
163
418
  host: target.host,
164
419
  "accept-encoding": "identity"
165
- })
420
+ }),
421
+ timeout: 0
166
422
  };
167
423
  const proxyReq = import_http.default.request(requestOptions, (proxyRes) => {
168
424
  var _a;
@@ -208,11 +464,19 @@ function startProxyServer(targetUrl, port, options = {}) {
208
464
  res.writeHead(502);
209
465
  res.end("Proxy error");
210
466
  });
467
+ proxyReq.on("socket", (socket) => {
468
+ socket.setTimeout(0);
469
+ });
470
+ req.on("socket", (socket) => {
471
+ socket.setTimeout(0);
472
+ });
211
473
  req.pipe(proxyReq);
212
474
  });
213
475
  server.on("error", (err) => {
214
476
  reject(err);
215
477
  });
478
+ server.timeout = 0;
479
+ server.keepAliveTimeout = 0;
216
480
  server.listen(port, () => {
217
481
  const address = server.address();
218
482
  const actualPort = typeof address === "object" && address ? address.port : port;
@@ -1,6 +1,7 @@
1
1
  import type { ResultPromise } from "execa";
2
2
  import type http from "http";
3
3
  import type { OpenCodeOptions, ServiceStartupTask } from "@vite-plugin-opencode-assistant/shared";
4
+ import { ChromeMcpWarmupErrorType } from "@vite-plugin-opencode-assistant/shared";
4
5
  import type { OpenCodeAPI } from "./api.js";
5
6
  export declare class OpenCodeService {
6
7
  private config;
@@ -13,16 +14,22 @@ export declare class OpenCodeService {
13
14
  actualProxyPort: number;
14
15
  isStarted: boolean;
15
16
  private startPromise;
16
- sessionUrl: string | null;
17
17
  private proxyServer;
18
18
  chromeMcpWarmupFailed: boolean;
19
+ chromeMcpWarmupErrorType: ChromeMcpWarmupErrorType | null;
20
+ chromeMcpWarmupErrorMessage: string | null;
19
21
  currentTask: {
20
22
  task: ServiceStartupTask;
21
23
  data?: Record<string, unknown>;
22
24
  } | null;
25
+ workspaceRoot: string | null;
23
26
  constructor(config: Required<OpenCodeOptions>, api: OpenCodeAPI, sseClients: Set<http.ServerResponse>, onPortAllocated: (port: number) => void, onProxyPortAllocated: (port: number) => void);
24
27
  private sendTaskUpdate;
25
28
  start(corsOrigins?: string[], contextApiUrl?: string, viteOrigin?: string): Promise<void>;
26
- retryWarmupChromeMcp(viteOrigin?: string): Promise<boolean>;
29
+ retryWarmupChromeMcp(viteOrigin?: string): Promise<{
30
+ success: boolean;
31
+ errorType?: string;
32
+ errorMessage?: string;
33
+ }>;
27
34
  stop(): Promise<void>;
28
35
  }
@@ -72,10 +72,12 @@ class OpenCodeService {
72
72
  __publicField(this, "actualProxyPort");
73
73
  __publicField(this, "isStarted", false);
74
74
  __publicField(this, "startPromise", null);
75
- __publicField(this, "sessionUrl", null);
76
75
  __publicField(this, "proxyServer", null);
77
76
  __publicField(this, "chromeMcpWarmupFailed", false);
77
+ __publicField(this, "chromeMcpWarmupErrorType", null);
78
+ __publicField(this, "chromeMcpWarmupErrorMessage", null);
78
79
  __publicField(this, "currentTask", null);
80
+ __publicField(this, "workspaceRoot", null);
79
81
  var _a;
80
82
  this.actualWebPort = config.webPort;
81
83
  this.actualProxyPort = (_a = config.proxyPort) != null ? _a : import_shared.DEFAULT_PROXY_PORT;
@@ -149,8 +151,10 @@ Please install OpenCode first:
149
151
  log.debug(`Using port ${this.actualWebPort}`);
150
152
  }
151
153
  timer.checkpoint("Port allocated");
154
+ this.workspaceRoot = (0, import_system.findGitRoot)(process.cwd());
155
+ log.info(`Using workspace root: ${this.workspaceRoot}`);
152
156
  this.sendTaskUpdate("preparing_runtime");
153
- const configDir = (0, import_opencode.prepareOpenCodeRuntime)(process.cwd());
157
+ const configDir = (0, import_opencode.prepareOpenCodeRuntime)(this.workspaceRoot);
154
158
  timer.checkpoint("Plugin setup complete");
155
159
  this.sendTaskUpdate("starting_web");
156
160
  log.debug("Starting OpenCode Web process...", {
@@ -162,7 +166,7 @@ Please install OpenCode first:
162
166
  port: this.actualWebPort,
163
167
  hostname: this.config.hostname,
164
168
  serverUrl: "",
165
- cwd: process.cwd(),
169
+ cwd: this.workspaceRoot,
166
170
  configDir,
167
171
  corsOrigins,
168
172
  contextApiUrl
@@ -235,39 +239,30 @@ Please install OpenCode first:
235
239
  this.sendTaskUpdate("warming_up_chrome");
236
240
  let warmupFailed = false;
237
241
  try {
238
- yield this.api.warmupChromeMcp(viteOrigin);
242
+ yield this.api.warmupChromeMcp(this.workspaceRoot, viteOrigin);
239
243
  timer.checkpoint("Chrome MCP warmup complete");
240
244
  } catch (e) {
241
245
  log.warn("Chrome MCP warmup failed", { error: e });
242
246
  this.chromeMcpWarmupFailed = true;
243
247
  warmupFailed = true;
248
+ if (e instanceof import_shared.ChromeMcpWarmupError) {
249
+ this.chromeMcpWarmupErrorType = e.type;
250
+ this.chromeMcpWarmupErrorMessage = e.message;
251
+ } else {
252
+ this.chromeMcpWarmupErrorType = import_shared.ChromeMcpWarmupErrorType.UNKNOWN;
253
+ this.chromeMcpWarmupErrorMessage = e instanceof Error ? e.message : String(e);
254
+ }
244
255
  }
245
256
  this.sendTaskUpdate("creating_session");
246
- let sessionFailed = false;
247
- try {
248
- this.sessionUrl = yield this.api.getOrCreateSession();
249
- timer.checkpoint("Session created");
250
- log.debug(`Session URL: ${this.sessionUrl}`);
251
- } catch (e) {
252
- log.warn("Failed to get/create session", { error: e });
253
- sessionFailed = true;
254
- }
255
- if (sessionFailed) {
256
- this.sendTaskUpdate("session_creation_failed");
257
- this.isStarted = false;
258
- this.startPromise = null;
259
- } else if (warmupFailed) {
260
- this.sendTaskUpdate("chrome_mcp_failed", { sessionUrl: this.sessionUrl });
261
- this.isStarted = true;
262
- } else {
263
- this.sendTaskUpdate("ready", { sessionUrl: this.sessionUrl });
264
- }
265
- if (!sessionFailed) {
257
+ if (warmupFailed) {
258
+ this.sendTaskUpdate("chrome_mcp_failed", {
259
+ errorType: this.chromeMcpWarmupErrorType,
260
+ errorMessage: this.chromeMcpWarmupErrorMessage
261
+ });
266
262
  this.isStarted = true;
267
263
  } else {
268
- this.sessionUrl = null;
264
+ this.sendTaskUpdate("ready");
269
265
  }
270
- log.debug(`OpenCode services started successfully: ${this.sessionUrl || webUrl}`);
271
266
  timer.end("\u2713 Services started successfully");
272
267
  }))();
273
268
  return this.startPromise;
@@ -275,12 +270,18 @@ Please install OpenCode first:
275
270
  }
276
271
  retryWarmupChromeMcp(viteOrigin) {
277
272
  return __async(this, null, function* () {
278
- const success = yield this.api.retryWarmupChromeMcp(viteOrigin);
279
- if (success) {
273
+ const result = yield this.api.retryWarmupChromeMcp(this.workspaceRoot, viteOrigin);
274
+ if (result.success) {
280
275
  this.chromeMcpWarmupFailed = false;
281
- this.sendTaskUpdate("ready", { sessionUrl: this.sessionUrl });
276
+ this.sendTaskUpdate("ready");
277
+ return { success: true };
282
278
  }
283
- return success;
279
+ const error = result.error;
280
+ return {
281
+ success: false,
282
+ errorType: error == null ? void 0 : error.type,
283
+ errorMessage: (error == null ? void 0 : error.message) || "Unknown error"
284
+ };
284
285
  });
285
286
  }
286
287
  stop() {
@@ -31,7 +31,7 @@ __reExport(endpoints_exports, require("./types.js"), module.exports);
31
31
  function setupMiddlewares(server, ctx) {
32
32
  (0, import_widget.setupWidgetEndpoints)(server, ctx);
33
33
  (0, import_context.setupContextEndpoint)(server, ctx);
34
- (0, import_start.setupStartEndpoint)(server, ctx);
34
+ (0, import_start.setupStartEndpoint)(server);
35
35
  (0, import_sse.setupSseEndpoint)(server, ctx);
36
36
  (0, import_sessions.setupSessionsEndpoint)(server, ctx);
37
37
  (0, import_warmup.setupWarmupEndpoint)(server, ctx);
@@ -67,9 +67,6 @@ function setupSseEndpoint(server, ctx) {
67
67
  Object.assign(statusPayload, ctx.currentTask.data);
68
68
  }
69
69
  }
70
- if (ctx.sessionUrl) {
71
- statusPayload.sessionUrl = ctx.sessionUrl;
72
- }
73
70
  res.write(`data: ${JSON.stringify(statusPayload)}
74
71
 
75
72
  `);
@@ -1,3 +1,2 @@
1
1
  import type { ViteDevServer } from "vite";
2
- import type { EndpointContext } from "./types.js";
3
- export declare function setupStartEndpoint(server: ViteDevServer, ctx: EndpointContext): void;
2
+ export declare function setupStartEndpoint(server: ViteDevServer): void;
@@ -42,13 +42,13 @@ __export(start_exports, {
42
42
  module.exports = __toCommonJS(start_exports);
43
43
  var import_shared = require("@vite-plugin-opencode-assistant/shared");
44
44
  var import_shared2 = require("@vite-plugin-opencode-assistant/shared");
45
- function setupStartEndpoint(server, ctx) {
45
+ function setupStartEndpoint(server) {
46
46
  server.middlewares.use(import_shared.START_API_PATH, (_req, res) => __async(null, null, function* () {
47
47
  const reqCtx = new import_shared2.RequestContext("GET", import_shared.START_API_PATH);
48
48
  res.setHeader("Content-Type", "application/json");
49
49
  res.setHeader("Access-Control-Allow-Origin", "*");
50
50
  res.writeHead(200);
51
- res.end(JSON.stringify({ success: true, sessionUrl: ctx.sessionUrl }));
51
+ res.end(JSON.stringify({ success: true }));
52
52
  reqCtx.end(200);
53
53
  }));
54
54
  }
@@ -1,7 +1,6 @@
1
1
  import type { PageContext, SessionInfo, ServiceStartupTask } from "@vite-plugin-opencode-assistant/shared";
2
2
  import type http from "http";
3
3
  export interface EndpointContext {
4
- get sessionUrl(): string | null;
5
4
  get webUrl(): string | null;
6
5
  get sseClients(): Set<http.ServerResponse>;
7
6
  get pageContext(): PageContext;
@@ -16,5 +15,9 @@ export interface EndpointContext {
16
15
  deleteSession: (id: string) => Promise<void>;
17
16
  resolveWidgetPath: () => string;
18
17
  resolveWidgetStylePath: () => string;
19
- retryWarmupChromeMcp: () => Promise<boolean>;
18
+ retryWarmupChromeMcp: () => Promise<{
19
+ success: boolean;
20
+ errorType?: string;
21
+ errorMessage?: string;
22
+ }>;
20
23
  }
@@ -50,15 +50,27 @@ function setupWarmupEndpoint(server, ctx) {
50
50
  return;
51
51
  }
52
52
  try {
53
- const success = yield ctx.retryWarmupChromeMcp();
53
+ const result = yield ctx.retryWarmupChromeMcp();
54
54
  res.setHeader("Content-Type", "application/json");
55
55
  res.writeHead(200);
56
- res.end(JSON.stringify({ success }));
56
+ if (result.success) {
57
+ res.end(JSON.stringify({ success: true }));
58
+ } else {
59
+ res.end(JSON.stringify({
60
+ success: false,
61
+ errorType: result.errorType,
62
+ error: result.errorMessage
63
+ }));
64
+ }
57
65
  } catch (e) {
58
66
  log.error("Failed to retry warmup", { error: e });
59
67
  res.setHeader("Content-Type", "application/json");
60
68
  res.writeHead(500);
61
- res.end(JSON.stringify({ success: false, error: String(e) }));
69
+ res.end(JSON.stringify({
70
+ success: false,
71
+ errorType: "UNKNOWN",
72
+ error: String(e)
73
+ }));
62
74
  }
63
75
  }));
64
76
  }
package/lib/index.js CHANGED
@@ -92,7 +92,12 @@ function createOpenCodePlugin(options = {}) {
92
92
  let actualProxyPort = (_a = config.proxyPort) != null ? _a : import_shared.DEFAULT_PROXY_PORT;
93
93
  let pageContext = { url: "", title: "" };
94
94
  const sseClients = /* @__PURE__ */ new Set();
95
- const api = new import_api.OpenCodeAPI(config.hostname, () => actualWebPort, config.warmupChromeMcp);
95
+ const api = new import_api.OpenCodeAPI(
96
+ config.hostname,
97
+ () => actualWebPort,
98
+ () => actualProxyPort,
99
+ config.warmupChromeMcp
100
+ );
96
101
  const service = new import_service.OpenCodeService(
97
102
  config,
98
103
  api,
@@ -117,9 +122,6 @@ function createOpenCodePlugin(options = {}) {
117
122
  let viteOrigin = "";
118
123
  const getViteOrigin = () => viteOrigin;
119
124
  (0, import_endpoints.setupMiddlewares)(server, {
120
- get sessionUrl() {
121
- return service.sessionUrl;
122
- },
123
125
  get webUrl() {
124
126
  return actualWebPort ? `http://${config.hostname}:${actualWebPort}` : null;
125
127
  },
@@ -138,8 +140,8 @@ function createOpenCodePlugin(options = {}) {
138
140
  get currentTask() {
139
141
  return service.currentTask;
140
142
  },
141
- getSessions: () => api.getSessions(),
142
- createSession: () => api.createSession(),
143
+ getSessions: () => api.getSessions(service.workspaceRoot),
144
+ createSession: () => api.createSession(service.workspaceRoot),
143
145
  deleteSession: (id) => api.deleteSession(id),
144
146
  resolveWidgetPath: import_paths.resolveWidgetPath,
145
147
  resolveWidgetStylePath: import_paths.resolveWidgetStylePath,
@@ -195,15 +197,9 @@ function createOpenCodePlugin(options = {}) {
195
197
  transformIndexHtml(html) {
196
198
  const timer = log.timer("transformIndexHtml");
197
199
  const widget = (0, import_injector.injectWidget)({
198
- webUrl: `http://${config.hostname}:${actualWebPort}`,
199
- proxyUrl: `http://${config.hostname}:${actualProxyPort}`,
200
- serverUrl: `http://${config.hostname}:${actualWebPort}`,
201
200
  position: config.position,
202
201
  theme: config.theme,
203
202
  open: config.open,
204
- autoReload: config.autoReload,
205
- cwd: process.cwd(),
206
- // 不再注入 sessionUrl,客户端完全依赖 SSE 状态同步
207
203
  hotkey: config.hotkey
208
204
  });
209
205
  timer.end();