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/es/core/api.d.ts
CHANGED
|
@@ -1,15 +1,27 @@
|
|
|
1
1
|
import type { SessionInfo } from "@vite-plugin-opencode-assistant/shared";
|
|
2
|
+
import { ChromeMcpWarmupError } from "@vite-plugin-opencode-assistant/shared";
|
|
2
3
|
export declare class OpenCodeAPI {
|
|
3
4
|
private hostname;
|
|
4
5
|
private getPort;
|
|
6
|
+
private getProxyPort;
|
|
5
7
|
private warmupChromeMcpConfig;
|
|
6
|
-
|
|
8
|
+
private failedFreeModels;
|
|
9
|
+
constructor(hostname: string, getPort: () => number, getProxyPort: () => number, warmupChromeMcpConfig?: boolean);
|
|
10
|
+
markModelAsFailed(providerID: string, modelID: string): void;
|
|
11
|
+
clearFailedModels(): void;
|
|
7
12
|
private createHttpRequest;
|
|
8
|
-
getSessions(retries?: number): Promise<SessionInfo[]>;
|
|
9
|
-
createSession(retries?: number, title?: string): Promise<SessionInfo>;
|
|
13
|
+
getSessions(projectDir: string, retries?: number): Promise<SessionInfo[]>;
|
|
14
|
+
createSession(projectDir: string, retries?: number, title?: string): Promise<SessionInfo>;
|
|
15
|
+
getCheapestModel(): Promise<{
|
|
16
|
+
providerID: string;
|
|
17
|
+
modelID: string;
|
|
18
|
+
} | null>;
|
|
10
19
|
deleteSession(sessionId: string, retries?: number): Promise<void>;
|
|
11
20
|
getToolIds(retries?: number): Promise<string[]>;
|
|
12
|
-
warmupChromeMcp(viteOrigin?: string): Promise<void>;
|
|
13
|
-
getOrCreateSession(): Promise<string>;
|
|
14
|
-
retryWarmupChromeMcp(viteOrigin?: string): Promise<
|
|
21
|
+
warmupChromeMcp(projectDir: string, viteOrigin?: string): Promise<void>;
|
|
22
|
+
getOrCreateSession(projectDir: string): Promise<string>;
|
|
23
|
+
retryWarmupChromeMcp(projectDir: string, viteOrigin?: string): Promise<{
|
|
24
|
+
success: boolean;
|
|
25
|
+
error?: ChromeMcpWarmupError;
|
|
26
|
+
}>;
|
|
15
27
|
}
|
package/es/core/api.js
CHANGED
|
@@ -1,5 +1,22 @@
|
|
|
1
1
|
var __defProp = Object.defineProperty;
|
|
2
|
+
var __defProps = Object.defineProperties;
|
|
3
|
+
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
|
|
4
|
+
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
|
2
7
|
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
8
|
+
var __spreadValues = (a, b) => {
|
|
9
|
+
for (var prop in b || (b = {}))
|
|
10
|
+
if (__hasOwnProp.call(b, prop))
|
|
11
|
+
__defNormalProp(a, prop, b[prop]);
|
|
12
|
+
if (__getOwnPropSymbols)
|
|
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));
|
|
3
20
|
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
4
21
|
var __async = (__this, __arguments, generator) => {
|
|
5
22
|
return new Promise((resolve, reject) => {
|
|
@@ -26,43 +43,37 @@ import {
|
|
|
26
43
|
PerformanceTimer,
|
|
27
44
|
createLogger,
|
|
28
45
|
DEFAULT_RETRIES,
|
|
29
|
-
RETRY_DELAY
|
|
46
|
+
RETRY_DELAY,
|
|
47
|
+
ChromeMcpWarmupErrorType,
|
|
48
|
+
ChromeMcpWarmupError,
|
|
49
|
+
CHROME_DEVTOOLS_PORT,
|
|
50
|
+
checkChromeDevToolsAvailable,
|
|
51
|
+
sleep,
|
|
52
|
+
base64Encode,
|
|
53
|
+
extractTextFromResponse
|
|
30
54
|
} from "@vite-plugin-opencode-assistant/shared";
|
|
31
55
|
const log = createLogger("API");
|
|
32
|
-
function sleep(ms) {
|
|
33
|
-
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
34
|
-
}
|
|
35
|
-
function base64Encode(str) {
|
|
36
|
-
return Buffer.from(str).toString("base64");
|
|
37
|
-
}
|
|
38
|
-
function extractTextFromResponse(data) {
|
|
39
|
-
if (!data || typeof data !== "object") return null;
|
|
40
|
-
const obj = data;
|
|
41
|
-
if (obj.parts && Array.isArray(obj.parts)) {
|
|
42
|
-
const textParts = obj.parts.filter(
|
|
43
|
-
(p) => p && typeof p === "object" && p.type === "text"
|
|
44
|
-
).map((p) => p.text).filter(Boolean);
|
|
45
|
-
if (textParts.length > 0) return textParts.join("");
|
|
46
|
-
}
|
|
47
|
-
if (obj.text && typeof obj.text === "string") {
|
|
48
|
-
return obj.text;
|
|
49
|
-
}
|
|
50
|
-
if (obj.content && typeof obj.content === "string") {
|
|
51
|
-
return obj.content;
|
|
52
|
-
}
|
|
53
|
-
if (obj.message && typeof obj.message === "string") {
|
|
54
|
-
return obj.message;
|
|
55
|
-
}
|
|
56
|
-
if (typeof data === "string") {
|
|
57
|
-
return data;
|
|
58
|
-
}
|
|
59
|
-
return null;
|
|
60
|
-
}
|
|
61
56
|
class OpenCodeAPI {
|
|
62
|
-
constructor(hostname, getPort, warmupChromeMcpConfig = false) {
|
|
57
|
+
constructor(hostname, getPort, getProxyPort, warmupChromeMcpConfig = false) {
|
|
63
58
|
__publicField(this, "hostname", hostname);
|
|
64
59
|
__publicField(this, "getPort", getPort);
|
|
60
|
+
__publicField(this, "getProxyPort", getProxyPort);
|
|
65
61
|
__publicField(this, "warmupChromeMcpConfig", warmupChromeMcpConfig);
|
|
62
|
+
__publicField(this, "failedFreeModels", /* @__PURE__ */ new Set());
|
|
63
|
+
}
|
|
64
|
+
markModelAsFailed(providerID, modelID) {
|
|
65
|
+
const key = `${providerID}:${modelID}`;
|
|
66
|
+
this.failedFreeModels.add(key);
|
|
67
|
+
log.debug("Marked model as failed", {
|
|
68
|
+
providerID,
|
|
69
|
+
modelID,
|
|
70
|
+
key,
|
|
71
|
+
failedCount: this.failedFreeModels.size
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
clearFailedModels() {
|
|
75
|
+
this.failedFreeModels.clear();
|
|
76
|
+
log.debug("Cleared failed models cache");
|
|
66
77
|
}
|
|
67
78
|
createHttpRequest(options, body, timeout) {
|
|
68
79
|
const timer = new PerformanceTimer("HTTP Request", {
|
|
@@ -98,20 +109,26 @@ class OpenCodeAPI {
|
|
|
98
109
|
req.end();
|
|
99
110
|
});
|
|
100
111
|
}
|
|
101
|
-
getSessions() {
|
|
102
|
-
return __async(this, arguments, function* (retries = DEFAULT_RETRIES) {
|
|
103
|
-
const timer = log.timer("getSessions", { retries });
|
|
112
|
+
getSessions(_0) {
|
|
113
|
+
return __async(this, arguments, function* (projectDir, retries = DEFAULT_RETRIES) {
|
|
114
|
+
const timer = log.timer("getSessions", { retries, projectDir });
|
|
104
115
|
let lastError = null;
|
|
105
116
|
for (let i = 0; i < retries; i++) {
|
|
106
117
|
try {
|
|
107
|
-
log.debug(`Attempt ${i + 1}/${retries}`, { operation: "getSessions" });
|
|
118
|
+
log.debug(`Attempt ${i + 1}/${retries}`, { operation: "getSessions", projectDir });
|
|
108
119
|
const sessions = yield this.createHttpRequest({
|
|
109
120
|
hostname: this.hostname,
|
|
110
121
|
port: this.getPort(),
|
|
111
|
-
path: "/session"
|
|
122
|
+
path: "/session",
|
|
123
|
+
headers: {
|
|
124
|
+
"x-opencode-directory": encodeURIComponent(projectDir)
|
|
125
|
+
}
|
|
112
126
|
});
|
|
127
|
+
const sessionsWithUrl = sessions.map((s) => __spreadProps(__spreadValues({}, s), {
|
|
128
|
+
url: `http://${this.hostname}:${this.getProxyPort()}/${base64Encode(s.directory)}/session/${s.id}`
|
|
129
|
+
}));
|
|
113
130
|
timer.end(`Found ${sessions.length} sessions`);
|
|
114
|
-
return
|
|
131
|
+
return sessionsWithUrl;
|
|
115
132
|
} catch (e) {
|
|
116
133
|
lastError = e instanceof Error ? e : new Error(String(e));
|
|
117
134
|
log.debug(`Attempt ${i + 1} failed: ${lastError.message}`, {
|
|
@@ -129,15 +146,16 @@ class OpenCodeAPI {
|
|
|
129
146
|
throw lastError;
|
|
130
147
|
});
|
|
131
148
|
}
|
|
132
|
-
createSession() {
|
|
133
|
-
return __async(this, arguments, function* (retries = DEFAULT_RETRIES, title) {
|
|
134
|
-
const timer = log.timer("createSession", { retries, title });
|
|
149
|
+
createSession(_0) {
|
|
150
|
+
return __async(this, arguments, function* (projectDir, retries = DEFAULT_RETRIES, title) {
|
|
151
|
+
const timer = log.timer("createSession", { retries, title, projectDir });
|
|
135
152
|
let lastError = null;
|
|
136
153
|
for (let i = 0; i < retries; i++) {
|
|
137
154
|
try {
|
|
138
155
|
log.debug(`Attempt ${i + 1}/${retries}`, {
|
|
139
156
|
operation: "createSession",
|
|
140
|
-
title
|
|
157
|
+
title,
|
|
158
|
+
projectDir
|
|
141
159
|
});
|
|
142
160
|
const requestBody = title ? JSON.stringify({ title }) : void 0;
|
|
143
161
|
const session = yield this.createHttpRequest(
|
|
@@ -146,12 +164,17 @@ class OpenCodeAPI {
|
|
|
146
164
|
port: this.getPort(),
|
|
147
165
|
path: "/session",
|
|
148
166
|
method: "POST",
|
|
149
|
-
headers: requestBody ? { "Content-Type": "application/json" } :
|
|
167
|
+
headers: __spreadProps(__spreadValues({}, requestBody ? { "Content-Type": "application/json" } : {}), {
|
|
168
|
+
"x-opencode-directory": encodeURIComponent(projectDir)
|
|
169
|
+
})
|
|
150
170
|
},
|
|
151
171
|
requestBody
|
|
152
172
|
);
|
|
173
|
+
const sessionWithUrl = __spreadProps(__spreadValues({}, session), {
|
|
174
|
+
url: `http://${this.hostname}:${this.getProxyPort()}/${base64Encode(projectDir)}/session/${session.id}`
|
|
175
|
+
});
|
|
153
176
|
timer.end(`Created session: ${session.id}`);
|
|
154
|
-
return
|
|
177
|
+
return sessionWithUrl;
|
|
155
178
|
} catch (e) {
|
|
156
179
|
lastError = e instanceof Error ? e : new Error(String(e));
|
|
157
180
|
log.debug(`Attempt ${i + 1} failed: ${lastError.message}`, {
|
|
@@ -169,6 +192,63 @@ class OpenCodeAPI {
|
|
|
169
192
|
throw lastError;
|
|
170
193
|
});
|
|
171
194
|
}
|
|
195
|
+
getCheapestModel() {
|
|
196
|
+
return __async(this, null, function* () {
|
|
197
|
+
var _a, _b;
|
|
198
|
+
try {
|
|
199
|
+
const response = yield this.createHttpRequest({
|
|
200
|
+
hostname: this.hostname,
|
|
201
|
+
port: this.getPort(),
|
|
202
|
+
path: "/provider",
|
|
203
|
+
method: "GET"
|
|
204
|
+
});
|
|
205
|
+
const connectedProviders = new Set(response.connected);
|
|
206
|
+
const allModels = [];
|
|
207
|
+
for (const provider of response.all) {
|
|
208
|
+
if (!connectedProviders.has(provider.id)) {
|
|
209
|
+
log.debug("Skipping not connected provider", { providerID: provider.id });
|
|
210
|
+
continue;
|
|
211
|
+
}
|
|
212
|
+
for (const [modelID, model] of Object.entries(provider.models)) {
|
|
213
|
+
allModels.push({
|
|
214
|
+
providerID: provider.id,
|
|
215
|
+
modelID,
|
|
216
|
+
name: model.name,
|
|
217
|
+
inputCost: (_b = (_a = model.cost) == null ? void 0 : _a.input) != null ? _b : 0
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
allModels.sort((a, b) => a.inputCost - b.inputCost);
|
|
222
|
+
const availableModel = allModels.find(
|
|
223
|
+
(model) => !this.failedFreeModels.has(`${model.providerID}:${model.modelID}`)
|
|
224
|
+
);
|
|
225
|
+
if (!availableModel) {
|
|
226
|
+
log.debug("All models have failed", {
|
|
227
|
+
totalModels: allModels.length,
|
|
228
|
+
failedModels: this.failedFreeModels.size,
|
|
229
|
+
connectedProviders: response.connected
|
|
230
|
+
});
|
|
231
|
+
return null;
|
|
232
|
+
}
|
|
233
|
+
log.debug("Found cheapest available model for warmup", {
|
|
234
|
+
providerID: availableModel.providerID,
|
|
235
|
+
modelID: availableModel.modelID,
|
|
236
|
+
name: availableModel.name,
|
|
237
|
+
inputCost: availableModel.inputCost,
|
|
238
|
+
totalModels: allModels.length,
|
|
239
|
+
failedModels: this.failedFreeModels.size,
|
|
240
|
+
connectedProviders: response.connected
|
|
241
|
+
});
|
|
242
|
+
return {
|
|
243
|
+
providerID: availableModel.providerID,
|
|
244
|
+
modelID: availableModel.modelID
|
|
245
|
+
};
|
|
246
|
+
} catch (error) {
|
|
247
|
+
log.warn("Failed to get cheapest model", { error });
|
|
248
|
+
return null;
|
|
249
|
+
}
|
|
250
|
+
});
|
|
251
|
+
}
|
|
172
252
|
deleteSession(_0) {
|
|
173
253
|
return __async(this, arguments, function* (sessionId, retries = DEFAULT_RETRIES) {
|
|
174
254
|
const timer = log.timer("deleteSession", { sessionId, retries });
|
|
@@ -239,13 +319,33 @@ class OpenCodeAPI {
|
|
|
239
319
|
throw lastError;
|
|
240
320
|
});
|
|
241
321
|
}
|
|
242
|
-
warmupChromeMcp(viteOrigin) {
|
|
322
|
+
warmupChromeMcp(projectDir, viteOrigin) {
|
|
243
323
|
return __async(this, null, function* () {
|
|
244
324
|
if (!this.warmupChromeMcpConfig) return;
|
|
245
325
|
const timer = log.timer("warmupChromeMcp", { viteOrigin });
|
|
246
326
|
let warmupSessionId = null;
|
|
327
|
+
let freeModel = null;
|
|
328
|
+
const chromeAvailable = yield checkChromeDevToolsAvailable();
|
|
329
|
+
if (!chromeAvailable) {
|
|
330
|
+
const error = new ChromeMcpWarmupError(
|
|
331
|
+
ChromeMcpWarmupErrorType.CHROME_NOT_CONNECTED,
|
|
332
|
+
"Chrome DevTools Protocol is not available",
|
|
333
|
+
"Chrome remote debugging is not enabled or not running on port 9222. Please enable Chrome remote debugging first."
|
|
334
|
+
);
|
|
335
|
+
log.warn("Chrome DevTools not available", {
|
|
336
|
+
port: CHROME_DEVTOOLS_PORT,
|
|
337
|
+
hint: "Enable Chrome remote debugging at chrome://inspect/#remote-debugging"
|
|
338
|
+
});
|
|
339
|
+
timer.end("Chrome DevTools not available");
|
|
340
|
+
throw error;
|
|
341
|
+
}
|
|
342
|
+
log.debug("Chrome DevTools is available, proceeding with warmup");
|
|
247
343
|
try {
|
|
248
|
-
const warmupSession = yield this.createSession(
|
|
344
|
+
const warmupSession = yield this.createSession(
|
|
345
|
+
projectDir,
|
|
346
|
+
DEFAULT_RETRIES,
|
|
347
|
+
"__chrome_mcp_warmup__"
|
|
348
|
+
);
|
|
249
349
|
warmupSessionId = warmupSession.id;
|
|
250
350
|
const prompt = [
|
|
251
351
|
"Call the browser tool list_pages immediately to establish the Chrome DevTools MCP connection.",
|
|
@@ -255,7 +355,16 @@ class OpenCodeAPI {
|
|
|
255
355
|
"After the tool call is complete, reply with exactly: ready",
|
|
256
356
|
"If the tool call fails, reply with exactly: fail"
|
|
257
357
|
].join(" ");
|
|
258
|
-
const WARMUP_TIMEOUT =
|
|
358
|
+
const WARMUP_TIMEOUT = 6e4;
|
|
359
|
+
freeModel = yield this.getCheapestModel();
|
|
360
|
+
if (freeModel) {
|
|
361
|
+
log.debug("Using cheapest model for warmup", {
|
|
362
|
+
providerID: freeModel.providerID,
|
|
363
|
+
modelID: freeModel.modelID
|
|
364
|
+
});
|
|
365
|
+
} else {
|
|
366
|
+
log.debug("No model available, using default model");
|
|
367
|
+
}
|
|
259
368
|
const data = yield this.createHttpRequest(
|
|
260
369
|
{
|
|
261
370
|
hostname: this.hostname,
|
|
@@ -264,21 +373,80 @@ class OpenCodeAPI {
|
|
|
264
373
|
method: "POST",
|
|
265
374
|
headers: { "Content-Type": "application/json" }
|
|
266
375
|
},
|
|
267
|
-
JSON.stringify({
|
|
376
|
+
JSON.stringify(__spreadValues({
|
|
268
377
|
system: "You are warming up Chrome DevTools MCP during startup. You must use the available browser tools immediately before replying.",
|
|
269
378
|
parts: [{ type: "text", text: prompt }]
|
|
270
|
-
}
|
|
379
|
+
}, freeModel && {
|
|
380
|
+
model: {
|
|
381
|
+
providerID: freeModel.providerID,
|
|
382
|
+
modelID: freeModel.modelID
|
|
383
|
+
}
|
|
384
|
+
})),
|
|
271
385
|
WARMUP_TIMEOUT
|
|
272
386
|
);
|
|
273
387
|
const responseText = extractTextFromResponse(data);
|
|
274
|
-
if (!
|
|
275
|
-
throw new
|
|
388
|
+
if (!responseText) {
|
|
389
|
+
throw new ChromeMcpWarmupError(
|
|
390
|
+
ChromeMcpWarmupErrorType.AI_RESPONSE_ERROR,
|
|
391
|
+
"AI did not respond to the warmup request",
|
|
392
|
+
"Empty response from AI"
|
|
393
|
+
);
|
|
394
|
+
}
|
|
395
|
+
const lowerResponse = responseText.toLowerCase();
|
|
396
|
+
if (lowerResponse.includes("fail")) {
|
|
397
|
+
throw new ChromeMcpWarmupError(
|
|
398
|
+
ChromeMcpWarmupErrorType.CHROME_NOT_CONNECTED,
|
|
399
|
+
"Chrome DevTools MCP is not connected",
|
|
400
|
+
"AI reported that browser tools are not available. This should not happen if Chrome DevTools check passed."
|
|
401
|
+
);
|
|
402
|
+
}
|
|
403
|
+
if (!lowerResponse.includes("ready")) {
|
|
404
|
+
throw new ChromeMcpWarmupError(
|
|
405
|
+
ChromeMcpWarmupErrorType.AI_RESPONSE_ERROR,
|
|
406
|
+
"AI response does not indicate success",
|
|
407
|
+
`AI responded with: ${responseText.substring(0, 200)}`
|
|
408
|
+
);
|
|
276
409
|
}
|
|
277
410
|
timer.end("Chrome MCP warmed up");
|
|
278
411
|
} catch (e) {
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
412
|
+
if (e instanceof ChromeMcpWarmupError) {
|
|
413
|
+
if (e.type === ChromeMcpWarmupErrorType.SESSION_ERROR) {
|
|
414
|
+
timer.end("Session creation failed");
|
|
415
|
+
}
|
|
416
|
+
log.warn(`Chrome MCP warmup failed: ${e.type}`, {
|
|
417
|
+
message: e.message,
|
|
418
|
+
details: e.details
|
|
419
|
+
});
|
|
420
|
+
timer.end(`Chrome MCP warmup failed: ${e.type}`);
|
|
421
|
+
throw e;
|
|
422
|
+
}
|
|
423
|
+
if (freeModel) {
|
|
424
|
+
this.markModelAsFailed(freeModel.providerID, freeModel.modelID);
|
|
425
|
+
log.debug("Marked model as failed due to warmup error", {
|
|
426
|
+
providerID: freeModel.providerID,
|
|
427
|
+
modelID: freeModel.modelID,
|
|
428
|
+
error: e instanceof Error ? e.message : String(e)
|
|
429
|
+
});
|
|
430
|
+
}
|
|
431
|
+
const errorMessage = e instanceof Error ? e.message : String(e);
|
|
432
|
+
if (errorMessage.includes("timeout") || errorMessage.includes("Timeout")) {
|
|
433
|
+
const error2 = new ChromeMcpWarmupError(
|
|
434
|
+
ChromeMcpWarmupErrorType.AI_TIMEOUT,
|
|
435
|
+
"AI response timeout",
|
|
436
|
+
"AI did not respond within 30 seconds. Please check if the OpenCode AI model is properly configured and available."
|
|
437
|
+
);
|
|
438
|
+
log.warn("Chrome MCP warmup timeout", { error: errorMessage });
|
|
439
|
+
timer.end("Chrome MCP warmup timeout");
|
|
440
|
+
throw error2;
|
|
441
|
+
}
|
|
442
|
+
const error = new ChromeMcpWarmupError(
|
|
443
|
+
ChromeMcpWarmupErrorType.UNKNOWN,
|
|
444
|
+
"Unknown error during Chrome MCP warmup",
|
|
445
|
+
errorMessage
|
|
446
|
+
);
|
|
447
|
+
log.warn("Chrome MCP warmup failed with unknown error", { error: errorMessage });
|
|
448
|
+
timer.end("Chrome MCP warmup failed");
|
|
449
|
+
throw error;
|
|
282
450
|
} finally {
|
|
283
451
|
if (warmupSessionId) {
|
|
284
452
|
try {
|
|
@@ -293,34 +461,53 @@ class OpenCodeAPI {
|
|
|
293
461
|
}
|
|
294
462
|
});
|
|
295
463
|
}
|
|
296
|
-
getOrCreateSession() {
|
|
464
|
+
getOrCreateSession(projectDir) {
|
|
297
465
|
return __async(this, null, function* () {
|
|
298
|
-
const timer = log.timer("getOrCreateSession");
|
|
299
|
-
const projectDir = process.cwd();
|
|
466
|
+
const timer = log.timer("getOrCreateSession", { projectDir });
|
|
300
467
|
log.debug("Getting sessions...", { projectDir });
|
|
301
|
-
const sessions = yield this.getSessions();
|
|
468
|
+
const sessions = yield this.getSessions(projectDir);
|
|
302
469
|
log.debug(`Found ${sessions.length} sessions`, {
|
|
303
470
|
sessions: sessions.map((s) => ({ id: s.id, directory: s.directory }))
|
|
304
471
|
});
|
|
305
472
|
const matchingSession = sessions.find((s) => s.directory === projectDir);
|
|
306
473
|
if (matchingSession) {
|
|
307
|
-
const url2 = `http://${this.hostname}:${this.
|
|
474
|
+
const url2 = `http://${this.hostname}:${this.getProxyPort()}/${base64Encode(projectDir)}/session/${matchingSession.id}`;
|
|
308
475
|
timer.end(`Using existing session: ${matchingSession.id}`);
|
|
309
476
|
return url2;
|
|
310
477
|
}
|
|
311
478
|
log.debug("Creating new session...", { projectDir });
|
|
312
|
-
const newSession = yield this.createSession();
|
|
313
|
-
const url = `http://${this.hostname}:${this.
|
|
479
|
+
const newSession = yield this.createSession(projectDir);
|
|
480
|
+
const url = `http://${this.hostname}:${this.getProxyPort()}/${base64Encode(projectDir)}/session/${newSession.id}`;
|
|
314
481
|
timer.end(`Created new session: ${newSession.id}`);
|
|
315
482
|
return url;
|
|
316
483
|
});
|
|
317
484
|
}
|
|
318
|
-
retryWarmupChromeMcp(viteOrigin) {
|
|
485
|
+
retryWarmupChromeMcp(projectDir, viteOrigin) {
|
|
319
486
|
return __async(this, null, function* () {
|
|
320
487
|
const timer = log.timer("retryWarmupChromeMcp", { viteOrigin });
|
|
321
488
|
let warmupSessionId = null;
|
|
489
|
+
let freeModel = null;
|
|
490
|
+
const chromeAvailable = yield checkChromeDevToolsAvailable();
|
|
491
|
+
if (!chromeAvailable) {
|
|
492
|
+
const error = new ChromeMcpWarmupError(
|
|
493
|
+
ChromeMcpWarmupErrorType.CHROME_NOT_CONNECTED,
|
|
494
|
+
"Chrome DevTools Protocol is not available",
|
|
495
|
+
"Chrome remote debugging is not enabled or not running on port 9222. Please enable Chrome remote debugging first."
|
|
496
|
+
);
|
|
497
|
+
log.warn("Chrome DevTools not available for retry", {
|
|
498
|
+
port: CHROME_DEVTOOLS_PORT,
|
|
499
|
+
hint: "Enable Chrome remote debugging at chrome://inspect/#remote-debugging"
|
|
500
|
+
});
|
|
501
|
+
timer.end("Chrome DevTools not available for retry");
|
|
502
|
+
return { success: false, error };
|
|
503
|
+
}
|
|
504
|
+
log.debug("Chrome DevTools is available, proceeding with retry warmup");
|
|
322
505
|
try {
|
|
323
|
-
const warmupSession = yield this.createSession(
|
|
506
|
+
const warmupSession = yield this.createSession(
|
|
507
|
+
projectDir,
|
|
508
|
+
DEFAULT_RETRIES,
|
|
509
|
+
"__chrome_mcp_warmup__"
|
|
510
|
+
);
|
|
324
511
|
warmupSessionId = warmupSession.id;
|
|
325
512
|
const prompt = [
|
|
326
513
|
"Call the browser tool list_pages immediately to establish the Chrome DevTools MCP connection.",
|
|
@@ -331,6 +518,15 @@ class OpenCodeAPI {
|
|
|
331
518
|
"If the tool call fails, reply with exactly: fail"
|
|
332
519
|
].join(" ");
|
|
333
520
|
const WARMUP_TIMEOUT = 6e4;
|
|
521
|
+
freeModel = yield this.getCheapestModel();
|
|
522
|
+
if (freeModel) {
|
|
523
|
+
log.debug("Using cheapest model for retry warmup", {
|
|
524
|
+
providerID: freeModel.providerID,
|
|
525
|
+
modelID: freeModel.modelID
|
|
526
|
+
});
|
|
527
|
+
} else {
|
|
528
|
+
log.debug("No model available for retry, using default model");
|
|
529
|
+
}
|
|
334
530
|
const data = yield this.createHttpRequest(
|
|
335
531
|
{
|
|
336
532
|
hostname: this.hostname,
|
|
@@ -339,23 +535,82 @@ class OpenCodeAPI {
|
|
|
339
535
|
method: "POST",
|
|
340
536
|
headers: { "Content-Type": "application/json" }
|
|
341
537
|
},
|
|
342
|
-
JSON.stringify({
|
|
538
|
+
JSON.stringify(__spreadValues({
|
|
343
539
|
system: "You are warming up Chrome DevTools MCP during startup. You must use the available browser tools immediately before replying.",
|
|
344
540
|
parts: [{ type: "text", text: prompt }]
|
|
345
|
-
}
|
|
541
|
+
}, freeModel && {
|
|
542
|
+
model: {
|
|
543
|
+
providerID: freeModel.providerID,
|
|
544
|
+
modelID: freeModel.modelID
|
|
545
|
+
}
|
|
546
|
+
})),
|
|
346
547
|
WARMUP_TIMEOUT
|
|
347
548
|
);
|
|
348
549
|
log.debug("Chrome MCP warmup response:", { data });
|
|
349
550
|
const responseText = extractTextFromResponse(data);
|
|
350
|
-
if (!
|
|
351
|
-
throw new
|
|
551
|
+
if (!responseText) {
|
|
552
|
+
throw new ChromeMcpWarmupError(
|
|
553
|
+
ChromeMcpWarmupErrorType.AI_RESPONSE_ERROR,
|
|
554
|
+
"AI did not respond to the warmup request",
|
|
555
|
+
"Empty response from AI"
|
|
556
|
+
);
|
|
557
|
+
}
|
|
558
|
+
const lowerResponse = responseText.toLowerCase();
|
|
559
|
+
if (lowerResponse.includes("fail")) {
|
|
560
|
+
throw new ChromeMcpWarmupError(
|
|
561
|
+
ChromeMcpWarmupErrorType.CHROME_NOT_CONNECTED,
|
|
562
|
+
"Chrome DevTools MCP is not connected",
|
|
563
|
+
"AI reported that browser tools are not available. This should not happen if Chrome DevTools check passed."
|
|
564
|
+
);
|
|
565
|
+
}
|
|
566
|
+
if (!lowerResponse.includes("ready")) {
|
|
567
|
+
throw new ChromeMcpWarmupError(
|
|
568
|
+
ChromeMcpWarmupErrorType.AI_RESPONSE_ERROR,
|
|
569
|
+
"AI response does not indicate success",
|
|
570
|
+
`AI responded with: ${responseText.substring(0, 200)}`
|
|
571
|
+
);
|
|
352
572
|
}
|
|
353
573
|
timer.end("Chrome MCP warmed up successfully");
|
|
354
|
-
return true;
|
|
574
|
+
return { success: true };
|
|
355
575
|
} catch (e) {
|
|
356
|
-
|
|
576
|
+
if (e instanceof ChromeMcpWarmupError) {
|
|
577
|
+
if (e.type === ChromeMcpWarmupErrorType.SESSION_ERROR) {
|
|
578
|
+
timer.end("Session creation failed");
|
|
579
|
+
}
|
|
580
|
+
log.warn(`Chrome MCP warmup retry failed: ${e.type}`, {
|
|
581
|
+
message: e.message,
|
|
582
|
+
details: e.details
|
|
583
|
+
});
|
|
584
|
+
timer.end(`Chrome MCP warmup retry failed: ${e.type}`);
|
|
585
|
+
return { success: false, error: e };
|
|
586
|
+
}
|
|
587
|
+
if (freeModel) {
|
|
588
|
+
this.markModelAsFailed(freeModel.providerID, freeModel.modelID);
|
|
589
|
+
log.debug("Marked model as failed due to retry warmup error", {
|
|
590
|
+
providerID: freeModel.providerID,
|
|
591
|
+
modelID: freeModel.modelID,
|
|
592
|
+
error: e instanceof Error ? e.message : String(e)
|
|
593
|
+
});
|
|
594
|
+
}
|
|
595
|
+
const errorMessage = e instanceof Error ? e.message : String(e);
|
|
596
|
+
if (errorMessage.includes("timeout") || errorMessage.includes("Timeout")) {
|
|
597
|
+
const error2 = new ChromeMcpWarmupError(
|
|
598
|
+
ChromeMcpWarmupErrorType.AI_TIMEOUT,
|
|
599
|
+
"AI response timeout",
|
|
600
|
+
"AI did not respond within 60 seconds. Please check if the OpenCode AI model is properly configured and available."
|
|
601
|
+
);
|
|
602
|
+
log.warn("Chrome MCP warmup retry timeout", { error: errorMessage });
|
|
603
|
+
timer.end("Chrome MCP warmup retry timeout");
|
|
604
|
+
return { success: false, error: error2 };
|
|
605
|
+
}
|
|
606
|
+
const error = new ChromeMcpWarmupError(
|
|
607
|
+
ChromeMcpWarmupErrorType.UNKNOWN,
|
|
608
|
+
"Unknown error during Chrome MCP warmup retry",
|
|
609
|
+
errorMessage
|
|
610
|
+
);
|
|
611
|
+
log.warn("Chrome MCP warmup retry failed with unknown error", { error: errorMessage });
|
|
357
612
|
timer.end("Chrome MCP warmup retry failed");
|
|
358
|
-
return false;
|
|
613
|
+
return { success: false, error };
|
|
359
614
|
} finally {
|
|
360
615
|
if (warmupSessionId) {
|
|
361
616
|
try {
|