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