vite-plugin-opencode-assistant 1.0.3 → 1.0.5
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/index.d.ts +1 -0
- package/es/client/index.js +328 -0
- package/es/core/api.d.ts +14 -0
- package/es/core/api.js +294 -0
- package/es/core/injector.d.ts +2 -0
- package/es/core/injector.js +11 -0
- package/es/core/service.d.ts +18 -0
- package/es/core/service.js +163 -0
- package/es/endpoints/context.d.ts +3 -0
- package/es/endpoints/context.js +114 -0
- package/es/endpoints/index.d.ts +4 -0
- package/es/endpoints/index.js +16 -0
- package/es/endpoints/sessions.d.ts +3 -0
- package/es/endpoints/sessions.js +79 -0
- package/es/endpoints/sse.d.ts +3 -0
- package/es/endpoints/sse.js +56 -0
- package/es/endpoints/start.d.ts +3 -0
- package/es/endpoints/start.js +35 -0
- package/es/endpoints/types.d.ts +13 -0
- package/es/endpoints/widget.d.ts +3 -0
- package/es/endpoints/widget.js +57 -0
- package/es/index.d.ts +3 -0
- package/es/index.js +168 -0
- package/es/utils/paths.d.ts +3 -0
- package/es/utils/paths.js +38 -0
- package/es/utils/system.js +241 -0
- package/lib/client/index.d.ts +1 -0
- package/lib/client/index.js +328 -0
- package/lib/client.js +5597 -0
- package/lib/core/api.d.ts +14 -0
- package/lib/core/api.js +321 -0
- package/lib/core/injector.d.ts +2 -0
- package/lib/core/injector.js +34 -0
- package/lib/core/service.d.ts +18 -0
- package/lib/core/service.js +180 -0
- package/lib/endpoints/context.d.ts +3 -0
- package/lib/endpoints/context.js +137 -0
- package/lib/endpoints/index.d.ts +4 -0
- package/lib/endpoints/index.js +41 -0
- package/lib/endpoints/sessions.d.ts +3 -0
- package/lib/endpoints/sessions.js +102 -0
- package/lib/endpoints/sse.d.ts +3 -0
- package/lib/endpoints/sse.js +79 -0
- package/lib/endpoints/start.d.ts +3 -0
- package/lib/endpoints/start.js +58 -0
- package/lib/endpoints/types.d.ts +13 -0
- package/lib/endpoints/types.js +15 -0
- package/lib/endpoints/widget.d.ts +3 -0
- package/lib/endpoints/widget.js +90 -0
- package/lib/index.d.ts +3 -0
- package/lib/index.js +190 -0
- package/lib/style.css +1 -0
- package/lib/utils/paths.d.ts +3 -0
- package/lib/utils/paths.js +73 -0
- package/lib/utils/system.d.ts +5 -0
- package/lib/utils/system.js +274 -0
- package/package.json +29 -31
- package/README.md +0 -282
- package/dist/constants.d.ts +0 -73
- package/dist/constants.js +0 -74
- package/dist/constants.js.map +0 -1
- package/dist/logger.d.ts +0 -64
- package/dist/logger.js +0 -311
- package/dist/logger.js.map +0 -1
- package/dist/opencode/plugins/page-context.d.ts +0 -7
- package/dist/opencode/plugins/page-context.js +0 -345
- package/dist/opencode/plugins/page-context.js.map +0 -1
- package/dist/opencode/web.d.ts +0 -3
- package/dist/opencode/web.js +0 -81
- package/dist/opencode/web.js.map +0 -1
- package/dist/types.d.ts +0 -124
- package/dist/types.js +0 -2
- package/dist/types.js.map +0 -1
- package/dist/vite/client.js +0 -2288
- package/dist/vite/client.js.map +0 -1
- package/dist/vite/index.d.ts +0 -3
- package/dist/vite/index.js +0 -520
- package/dist/vite/index.js.map +0 -1
- package/dist/vite/injector.d.ts +0 -2
- package/dist/vite/injector.js +0 -6
- package/dist/vite/injector.js.map +0 -1
- package/dist/vite/utils.js +0 -206
- package/dist/vite/utils.js.map +0 -1
- /package/{dist/vite/client.d.ts → es/endpoints/types.js} +0 -0
- /package/{dist/vite/utils.d.ts → es/utils/system.d.ts} +0 -0
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { SessionInfo } from "@vite-plugin-opencode-assistant/shared";
|
|
2
|
+
export declare class OpenCodeAPI {
|
|
3
|
+
private hostname;
|
|
4
|
+
private getPort;
|
|
5
|
+
private warmupChromeMcpConfig;
|
|
6
|
+
constructor(hostname: string, getPort: () => number, warmupChromeMcpConfig?: boolean);
|
|
7
|
+
private createHttpRequest;
|
|
8
|
+
getSessions(retries?: number): Promise<SessionInfo[]>;
|
|
9
|
+
createSession(retries?: number, title?: string): Promise<SessionInfo>;
|
|
10
|
+
deleteSession(sessionId: string, retries?: number): Promise<void>;
|
|
11
|
+
getToolIds(retries?: number): Promise<string[]>;
|
|
12
|
+
warmupChromeMcp(viteOrigin?: string): Promise<void>;
|
|
13
|
+
getOrCreateSession(): Promise<string>;
|
|
14
|
+
}
|
package/lib/core/api.js
ADDED
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
var __create = Object.create;
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
30
|
+
var __async = (__this, __arguments, generator) => {
|
|
31
|
+
return new Promise((resolve, reject) => {
|
|
32
|
+
var fulfilled = (value) => {
|
|
33
|
+
try {
|
|
34
|
+
step(generator.next(value));
|
|
35
|
+
} catch (e) {
|
|
36
|
+
reject(e);
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
var rejected = (value) => {
|
|
40
|
+
try {
|
|
41
|
+
step(generator.throw(value));
|
|
42
|
+
} catch (e) {
|
|
43
|
+
reject(e);
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
|
|
47
|
+
step((generator = generator.apply(__this, __arguments)).next());
|
|
48
|
+
});
|
|
49
|
+
};
|
|
50
|
+
var api_exports = {};
|
|
51
|
+
__export(api_exports, {
|
|
52
|
+
OpenCodeAPI: () => OpenCodeAPI
|
|
53
|
+
});
|
|
54
|
+
module.exports = __toCommonJS(api_exports);
|
|
55
|
+
var import_http = __toESM(require("http"));
|
|
56
|
+
var import_shared = require("@vite-plugin-opencode-assistant/shared");
|
|
57
|
+
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
|
+
class OpenCodeAPI {
|
|
65
|
+
constructor(hostname, getPort, warmupChromeMcpConfig = false) {
|
|
66
|
+
__publicField(this, "hostname", hostname);
|
|
67
|
+
__publicField(this, "getPort", getPort);
|
|
68
|
+
__publicField(this, "warmupChromeMcpConfig", warmupChromeMcpConfig);
|
|
69
|
+
}
|
|
70
|
+
createHttpRequest(options, body) {
|
|
71
|
+
const timer = new import_shared.PerformanceTimer("HTTP Request", {
|
|
72
|
+
operation: `${options.method || "GET"} ${options.path}`
|
|
73
|
+
});
|
|
74
|
+
return new Promise((resolve, reject) => {
|
|
75
|
+
const req = import_http.default.request(options, (res) => {
|
|
76
|
+
let data = "";
|
|
77
|
+
res.on("data", (chunk) => data += chunk);
|
|
78
|
+
res.on("end", () => {
|
|
79
|
+
try {
|
|
80
|
+
const result = JSON.parse(data);
|
|
81
|
+
timer.end(`\u2713 Status: ${res.statusCode}`);
|
|
82
|
+
resolve(result);
|
|
83
|
+
} catch (e) {
|
|
84
|
+
timer.end("\u274C JSON parse error");
|
|
85
|
+
reject(new Error(`JSON parse error: ${data.substring(0, 100)}`));
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
req.on("error", (e) => {
|
|
90
|
+
timer.end("\u274C Request failed");
|
|
91
|
+
reject(e);
|
|
92
|
+
});
|
|
93
|
+
if (body) req.write(body);
|
|
94
|
+
req.end();
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
getSessions() {
|
|
98
|
+
return __async(this, arguments, function* (retries = import_shared.DEFAULT_RETRIES) {
|
|
99
|
+
const timer = log.timer("getSessions", { retries });
|
|
100
|
+
let lastError = null;
|
|
101
|
+
for (let i = 0; i < retries; i++) {
|
|
102
|
+
try {
|
|
103
|
+
log.debug(`Attempt ${i + 1}/${retries}`, { operation: "getSessions" });
|
|
104
|
+
const sessions = yield this.createHttpRequest({
|
|
105
|
+
hostname: this.hostname,
|
|
106
|
+
port: this.getPort(),
|
|
107
|
+
path: "/session"
|
|
108
|
+
});
|
|
109
|
+
timer.end(`Found ${sessions.length} sessions`);
|
|
110
|
+
return sessions;
|
|
111
|
+
} catch (e) {
|
|
112
|
+
lastError = e instanceof Error ? e : new Error(String(e));
|
|
113
|
+
log.debug(`Attempt ${i + 1} failed: ${lastError.message}`, {
|
|
114
|
+
operation: "getSessions"
|
|
115
|
+
});
|
|
116
|
+
if (i < retries - 1) {
|
|
117
|
+
log.debug(`Retrying in ${import_shared.RETRY_DELAY}ms...`, {
|
|
118
|
+
operation: "getSessions"
|
|
119
|
+
});
|
|
120
|
+
yield sleep(import_shared.RETRY_DELAY);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
timer.end("\u274C All retries exhausted");
|
|
125
|
+
throw lastError;
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
createSession() {
|
|
129
|
+
return __async(this, arguments, function* (retries = import_shared.DEFAULT_RETRIES, title) {
|
|
130
|
+
const timer = log.timer("createSession", { retries, title });
|
|
131
|
+
let lastError = null;
|
|
132
|
+
for (let i = 0; i < retries; i++) {
|
|
133
|
+
try {
|
|
134
|
+
log.debug(`Attempt ${i + 1}/${retries}`, {
|
|
135
|
+
operation: "createSession",
|
|
136
|
+
title
|
|
137
|
+
});
|
|
138
|
+
const requestBody = title ? JSON.stringify({ title }) : void 0;
|
|
139
|
+
const session = yield this.createHttpRequest(
|
|
140
|
+
{
|
|
141
|
+
hostname: this.hostname,
|
|
142
|
+
port: this.getPort(),
|
|
143
|
+
path: "/session",
|
|
144
|
+
method: "POST",
|
|
145
|
+
headers: requestBody ? { "Content-Type": "application/json" } : void 0
|
|
146
|
+
},
|
|
147
|
+
requestBody
|
|
148
|
+
);
|
|
149
|
+
timer.end(`Created session: ${session.id}`);
|
|
150
|
+
return session;
|
|
151
|
+
} catch (e) {
|
|
152
|
+
lastError = e instanceof Error ? e : new Error(String(e));
|
|
153
|
+
log.debug(`Attempt ${i + 1} failed: ${lastError.message}`, {
|
|
154
|
+
operation: "createSession"
|
|
155
|
+
});
|
|
156
|
+
if (i < retries - 1) {
|
|
157
|
+
log.debug(`Retrying in ${import_shared.RETRY_DELAY}ms...`, {
|
|
158
|
+
operation: "createSession"
|
|
159
|
+
});
|
|
160
|
+
yield sleep(import_shared.RETRY_DELAY);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
timer.end("\u274C All retries exhausted");
|
|
165
|
+
throw lastError;
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
deleteSession(_0) {
|
|
169
|
+
return __async(this, arguments, function* (sessionId, retries = import_shared.DEFAULT_RETRIES) {
|
|
170
|
+
const timer = log.timer("deleteSession", { sessionId, retries });
|
|
171
|
+
let lastError = null;
|
|
172
|
+
for (let i = 0; i < retries; i++) {
|
|
173
|
+
try {
|
|
174
|
+
log.debug(`Attempt ${i + 1}/${retries}`, {
|
|
175
|
+
operation: "deleteSession",
|
|
176
|
+
sessionId
|
|
177
|
+
});
|
|
178
|
+
yield this.createHttpRequest({
|
|
179
|
+
hostname: this.hostname,
|
|
180
|
+
port: this.getPort(),
|
|
181
|
+
path: `/session/${sessionId}`,
|
|
182
|
+
method: "DELETE"
|
|
183
|
+
});
|
|
184
|
+
timer.end(`Deleted session: ${sessionId}`);
|
|
185
|
+
return;
|
|
186
|
+
} catch (e) {
|
|
187
|
+
lastError = e instanceof Error ? e : new Error(String(e));
|
|
188
|
+
log.debug(`Attempt ${i + 1} failed: ${lastError.message}`, {
|
|
189
|
+
operation: "deleteSession",
|
|
190
|
+
sessionId
|
|
191
|
+
});
|
|
192
|
+
if (i < retries - 1) {
|
|
193
|
+
log.debug(`Retrying in ${import_shared.RETRY_DELAY}ms...`, {
|
|
194
|
+
operation: "deleteSession",
|
|
195
|
+
sessionId
|
|
196
|
+
});
|
|
197
|
+
yield sleep(import_shared.RETRY_DELAY);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
timer.end("\u274C All retries exhausted");
|
|
202
|
+
throw lastError;
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
getToolIds() {
|
|
206
|
+
return __async(this, arguments, function* (retries = import_shared.DEFAULT_RETRIES) {
|
|
207
|
+
const timer = log.timer("getToolIds", { retries });
|
|
208
|
+
let lastError = null;
|
|
209
|
+
for (let i = 0; i < retries; i++) {
|
|
210
|
+
try {
|
|
211
|
+
log.debug(`Attempt ${i + 1}/${retries}`, {
|
|
212
|
+
operation: "getToolIds"
|
|
213
|
+
});
|
|
214
|
+
const toolIds = yield this.createHttpRequest({
|
|
215
|
+
hostname: this.hostname,
|
|
216
|
+
port: this.getPort(),
|
|
217
|
+
path: "/experimental/tool/ids"
|
|
218
|
+
});
|
|
219
|
+
timer.end(`Found ${toolIds.length} tools`);
|
|
220
|
+
return toolIds;
|
|
221
|
+
} catch (e) {
|
|
222
|
+
lastError = e instanceof Error ? e : new Error(String(e));
|
|
223
|
+
log.debug(`Attempt ${i + 1} failed: ${lastError.message}`, {
|
|
224
|
+
operation: "getToolIds"
|
|
225
|
+
});
|
|
226
|
+
if (i < retries - 1) {
|
|
227
|
+
log.debug(`Retrying in ${import_shared.RETRY_DELAY}ms...`, {
|
|
228
|
+
operation: "getToolIds"
|
|
229
|
+
});
|
|
230
|
+
yield sleep(import_shared.RETRY_DELAY);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
timer.end("\u274C All retries exhausted");
|
|
235
|
+
throw lastError;
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
warmupChromeMcp(viteOrigin) {
|
|
239
|
+
return __async(this, null, function* () {
|
|
240
|
+
if (!this.warmupChromeMcpConfig) return;
|
|
241
|
+
const timer = log.timer("warmupChromeMcp", { viteOrigin });
|
|
242
|
+
let warmupSessionId = null;
|
|
243
|
+
try {
|
|
244
|
+
const warmupSession = yield this.createSession(import_shared.DEFAULT_RETRIES, "__chrome_mcp_warmup__");
|
|
245
|
+
warmupSessionId = warmupSession.id;
|
|
246
|
+
let chromeToolIds;
|
|
247
|
+
try {
|
|
248
|
+
const toolIds = yield this.getToolIds();
|
|
249
|
+
chromeToolIds = toolIds.filter((toolId) => /chrome[-_]?devtools/i.test(toolId));
|
|
250
|
+
log.debug("Resolved Chrome MCP tool ids", {
|
|
251
|
+
chromeToolIds
|
|
252
|
+
});
|
|
253
|
+
} catch (e) {
|
|
254
|
+
log.debug("Failed to resolve Chrome MCP tool ids", { error: e });
|
|
255
|
+
}
|
|
256
|
+
const prompt = [
|
|
257
|
+
"Call the browser tool list_pages immediately to establish the Chrome DevTools MCP connection.",
|
|
258
|
+
viteOrigin ? `If there are no pages, call new_page with ${viteOrigin}.` : "If there are no pages, call new_page with about:blank.",
|
|
259
|
+
"Do not read or modify project files.",
|
|
260
|
+
"Do not use any non-browser tools.",
|
|
261
|
+
"After the tool call is complete, reply with exactly: ready"
|
|
262
|
+
].join(" ");
|
|
263
|
+
yield this.createHttpRequest(
|
|
264
|
+
{
|
|
265
|
+
hostname: this.hostname,
|
|
266
|
+
port: this.getPort(),
|
|
267
|
+
path: `/session/${warmupSessionId}/message`,
|
|
268
|
+
method: "POST",
|
|
269
|
+
headers: { "Content-Type": "application/json" }
|
|
270
|
+
},
|
|
271
|
+
JSON.stringify({
|
|
272
|
+
system: "You are warming up Chrome DevTools MCP during startup. You must use the available browser tools immediately before replying.",
|
|
273
|
+
tools: (chromeToolIds == null ? void 0 : chromeToolIds.length) ? chromeToolIds : void 0,
|
|
274
|
+
parts: [{ type: "text", text: prompt }]
|
|
275
|
+
})
|
|
276
|
+
);
|
|
277
|
+
timer.end("Chrome MCP warmed up");
|
|
278
|
+
} catch (e) {
|
|
279
|
+
log.warn("Failed to warm up Chrome MCP", { error: e });
|
|
280
|
+
timer.end("Chrome MCP warmup skipped");
|
|
281
|
+
} finally {
|
|
282
|
+
if (warmupSessionId) {
|
|
283
|
+
try {
|
|
284
|
+
yield this.deleteSession(warmupSessionId, 5);
|
|
285
|
+
} catch (e) {
|
|
286
|
+
log.warn("Failed to delete warmup session after retries", {
|
|
287
|
+
error: e,
|
|
288
|
+
warmupSessionId
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
getOrCreateSession() {
|
|
296
|
+
return __async(this, null, function* () {
|
|
297
|
+
const timer = log.timer("getOrCreateSession");
|
|
298
|
+
const projectDir = process.cwd();
|
|
299
|
+
log.debug("Getting sessions...", { projectDir });
|
|
300
|
+
const sessions = yield this.getSessions();
|
|
301
|
+
log.debug(`Found ${sessions.length} sessions`, {
|
|
302
|
+
sessions: sessions.map((s) => ({ id: s.id, directory: s.directory }))
|
|
303
|
+
});
|
|
304
|
+
const matchingSession = sessions.find((s) => s.directory === projectDir);
|
|
305
|
+
if (matchingSession) {
|
|
306
|
+
const url2 = `http://${this.hostname}:${this.getPort()}/${base64Encode(projectDir)}/session/${matchingSession.id}`;
|
|
307
|
+
timer.end(`Using existing session: ${matchingSession.id}`);
|
|
308
|
+
return url2;
|
|
309
|
+
}
|
|
310
|
+
log.debug("Creating new session...", { projectDir });
|
|
311
|
+
const newSession = yield this.createSession();
|
|
312
|
+
const url = `http://${this.hostname}:${this.getPort()}/${base64Encode(projectDir)}/session/${newSession.id}`;
|
|
313
|
+
timer.end(`Created new session: ${newSession.id}`);
|
|
314
|
+
return url;
|
|
315
|
+
});
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
319
|
+
0 && (module.exports = {
|
|
320
|
+
OpenCodeAPI
|
|
321
|
+
});
|
|
@@ -0,0 +1,34 @@
|
|
|
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 injector_exports = {};
|
|
19
|
+
__export(injector_exports, {
|
|
20
|
+
injectWidget: () => injectWidget
|
|
21
|
+
});
|
|
22
|
+
module.exports = __toCommonJS(injector_exports);
|
|
23
|
+
var import_shared = require("@vite-plugin-opencode-assistant/shared");
|
|
24
|
+
function injectWidget(options) {
|
|
25
|
+
const configBase64 = Buffer.from(JSON.stringify(options)).toString("base64");
|
|
26
|
+
const scriptTag = `<script type="module" src="${import_shared.WIDGET_SCRIPT_PATH}" ${import_shared.CONFIG_DATA_ATTR}="${configBase64}"></script>`;
|
|
27
|
+
const styleTag = `<link rel="stylesheet" href="/__opencode_widget__.css" />`;
|
|
28
|
+
return `${styleTag}
|
|
29
|
+
${scriptTag}`;
|
|
30
|
+
}
|
|
31
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
32
|
+
0 && (module.exports = {
|
|
33
|
+
injectWidget
|
|
34
|
+
});
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { ResultPromise } from "execa";
|
|
2
|
+
import type http from "http";
|
|
3
|
+
import type { OpenCodeOptions } from "@vite-plugin-opencode-assistant/shared";
|
|
4
|
+
import type { OpenCodeAPI } from "./api.js";
|
|
5
|
+
export declare class OpenCodeService {
|
|
6
|
+
private config;
|
|
7
|
+
private api;
|
|
8
|
+
private sseClients;
|
|
9
|
+
private onPortAllocated;
|
|
10
|
+
webProcess: ResultPromise | null;
|
|
11
|
+
actualWebPort: number;
|
|
12
|
+
isStarted: boolean;
|
|
13
|
+
private startPromise;
|
|
14
|
+
sessionUrl: string | null;
|
|
15
|
+
constructor(config: Required<OpenCodeOptions>, api: OpenCodeAPI, sseClients: Set<http.ServerResponse>, onPortAllocated: (port: number) => void);
|
|
16
|
+
start(corsOrigins?: string[], contextApiUrl?: string, viteOrigin?: string): Promise<void>;
|
|
17
|
+
stop(): Promise<void>;
|
|
18
|
+
}
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
20
|
+
var __async = (__this, __arguments, generator) => {
|
|
21
|
+
return new Promise((resolve, reject) => {
|
|
22
|
+
var fulfilled = (value) => {
|
|
23
|
+
try {
|
|
24
|
+
step(generator.next(value));
|
|
25
|
+
} catch (e) {
|
|
26
|
+
reject(e);
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
var rejected = (value) => {
|
|
30
|
+
try {
|
|
31
|
+
step(generator.throw(value));
|
|
32
|
+
} catch (e) {
|
|
33
|
+
reject(e);
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
|
|
37
|
+
step((generator = generator.apply(__this, __arguments)).next());
|
|
38
|
+
});
|
|
39
|
+
};
|
|
40
|
+
var service_exports = {};
|
|
41
|
+
__export(service_exports, {
|
|
42
|
+
OpenCodeService: () => OpenCodeService
|
|
43
|
+
});
|
|
44
|
+
module.exports = __toCommonJS(service_exports);
|
|
45
|
+
var import_opencode = require("@vite-plugin-opencode-assistant/opencode");
|
|
46
|
+
var import_shared = require("@vite-plugin-opencode-assistant/shared");
|
|
47
|
+
var import_system = require("../utils/system.js");
|
|
48
|
+
const log = (0, import_shared.createLogger)("Service");
|
|
49
|
+
class OpenCodeService {
|
|
50
|
+
constructor(config, api, sseClients, onPortAllocated) {
|
|
51
|
+
__publicField(this, "config", config);
|
|
52
|
+
__publicField(this, "api", api);
|
|
53
|
+
__publicField(this, "sseClients", sseClients);
|
|
54
|
+
__publicField(this, "onPortAllocated", onPortAllocated);
|
|
55
|
+
__publicField(this, "webProcess", null);
|
|
56
|
+
__publicField(this, "actualWebPort");
|
|
57
|
+
__publicField(this, "isStarted", false);
|
|
58
|
+
__publicField(this, "startPromise", null);
|
|
59
|
+
__publicField(this, "sessionUrl", null);
|
|
60
|
+
this.actualWebPort = config.webPort;
|
|
61
|
+
}
|
|
62
|
+
start(corsOrigins, contextApiUrl, viteOrigin) {
|
|
63
|
+
return __async(this, null, function* () {
|
|
64
|
+
if (this.isStarted && this.webProcess) {
|
|
65
|
+
log.debug("Services already started, skipping");
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
if (this.startPromise) {
|
|
69
|
+
log.debug("Waiting for existing start promise");
|
|
70
|
+
return this.startPromise;
|
|
71
|
+
}
|
|
72
|
+
this.startPromise = (() => __async(this, null, function* () {
|
|
73
|
+
const timer = log.timer("startServices", {
|
|
74
|
+
corsOrigins,
|
|
75
|
+
contextApiUrl,
|
|
76
|
+
viteOrigin
|
|
77
|
+
});
|
|
78
|
+
log.info("Starting OpenCode services...");
|
|
79
|
+
const orphanCount = yield (0, import_system.killOrphanOpenCodeProcesses)();
|
|
80
|
+
if (orphanCount > 0) {
|
|
81
|
+
log.debug(`Killed ${orphanCount} orphan OpenCode process(es)`);
|
|
82
|
+
}
|
|
83
|
+
if (!(yield (0, import_system.checkOpenCodeInstalled)())) {
|
|
84
|
+
log.error(`OpenCode is not installed!
|
|
85
|
+
|
|
86
|
+
Please install OpenCode first:
|
|
87
|
+
|
|
88
|
+
# YOLO
|
|
89
|
+
curl -fsSL https://opencode.ai/install | bash
|
|
90
|
+
|
|
91
|
+
# Package managers
|
|
92
|
+
npm i -g opencode-ai@latest # or bun/pnpm/yarn
|
|
93
|
+
scoop install opencode # Windows
|
|
94
|
+
choco install opencode # Windows
|
|
95
|
+
brew install anomalyco/tap/opencode # macOS and Linux (recommended, always up to date)
|
|
96
|
+
brew install opencode # macOS and Linux (official brew formula, updated less)
|
|
97
|
+
sudo pacman -S opencode # Arch Linux (Stable)
|
|
98
|
+
paru -S opencode-bin # Arch Linux (Latest from AUR)
|
|
99
|
+
mise use -g opencode # Any OS
|
|
100
|
+
nix run nixpkgs#opencode # or github:anomalyco/opencode for latest dev branch
|
|
101
|
+
`);
|
|
102
|
+
timer.end("\u274C OpenCode not installed");
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
timer.checkpoint("OpenCode installation verified");
|
|
106
|
+
this.actualWebPort = yield (0, import_system.findAvailablePort)(this.config.webPort, this.config.hostname);
|
|
107
|
+
this.onPortAllocated(this.actualWebPort);
|
|
108
|
+
if (this.actualWebPort !== this.config.webPort) {
|
|
109
|
+
log.info(`Port ${this.config.webPort} is in use, using ${this.actualWebPort} instead`);
|
|
110
|
+
} else {
|
|
111
|
+
log.debug(`Using port ${this.actualWebPort}`);
|
|
112
|
+
}
|
|
113
|
+
timer.checkpoint("Port allocated");
|
|
114
|
+
const configDir = (0, import_opencode.prepareOpenCodeRuntime)(process.cwd());
|
|
115
|
+
timer.checkpoint("Plugin setup complete");
|
|
116
|
+
log.debug("Starting OpenCode Web process...", {
|
|
117
|
+
port: this.actualWebPort,
|
|
118
|
+
hostname: this.config.hostname,
|
|
119
|
+
configDir
|
|
120
|
+
});
|
|
121
|
+
this.webProcess = (0, import_opencode.startOpenCodeWeb)({
|
|
122
|
+
port: this.actualWebPort,
|
|
123
|
+
hostname: this.config.hostname,
|
|
124
|
+
serverUrl: "",
|
|
125
|
+
cwd: process.cwd(),
|
|
126
|
+
configDir,
|
|
127
|
+
corsOrigins,
|
|
128
|
+
contextApiUrl
|
|
129
|
+
});
|
|
130
|
+
timer.checkpoint("Web process started");
|
|
131
|
+
const webUrl = `http://${this.config.hostname}:${this.actualWebPort}`;
|
|
132
|
+
log.info(`Waiting for OpenCode Web to become ready at ${webUrl}...`);
|
|
133
|
+
yield (0, import_system.waitForServer)(webUrl, import_shared.SERVER_START_TIMEOUT);
|
|
134
|
+
log.info(`OpenCode Web started at ${webUrl}`);
|
|
135
|
+
yield this.api.warmupChromeMcp(viteOrigin);
|
|
136
|
+
timer.checkpoint("Chrome MCP warmup complete");
|
|
137
|
+
try {
|
|
138
|
+
this.sessionUrl = yield this.api.getOrCreateSession();
|
|
139
|
+
timer.checkpoint("Session created");
|
|
140
|
+
log.debug(`Session URL: ${this.sessionUrl}`);
|
|
141
|
+
this.sseClients.forEach((client) => {
|
|
142
|
+
try {
|
|
143
|
+
client.write(
|
|
144
|
+
`data: ${JSON.stringify({ type: "SESSION_READY", sessionUrl: this.sessionUrl })}
|
|
145
|
+
|
|
146
|
+
`
|
|
147
|
+
);
|
|
148
|
+
} catch (e) {
|
|
149
|
+
log.debug("Failed to send SESSION_READY event", { error: e });
|
|
150
|
+
}
|
|
151
|
+
});
|
|
152
|
+
} catch (e) {
|
|
153
|
+
log.warn("Failed to get/create session", { error: e });
|
|
154
|
+
}
|
|
155
|
+
this.isStarted = true;
|
|
156
|
+
log.debug(`OpenCode services started successfully: ${this.sessionUrl || webUrl}`);
|
|
157
|
+
timer.end("\u2713 Services started successfully");
|
|
158
|
+
}))();
|
|
159
|
+
return this.startPromise;
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
stop() {
|
|
163
|
+
return __async(this, null, function* () {
|
|
164
|
+
const timer = log.timer("stopServices");
|
|
165
|
+
log.info("Stopping OpenCode services...");
|
|
166
|
+
if (this.webProcess) {
|
|
167
|
+
log.debug("Killing web process", { pid: this.webProcess.pid });
|
|
168
|
+
this.webProcess.kill("SIGTERM");
|
|
169
|
+
this.webProcess = null;
|
|
170
|
+
}
|
|
171
|
+
this.isStarted = false;
|
|
172
|
+
this.startPromise = null;
|
|
173
|
+
timer.end("\u2713 Services stopped");
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
178
|
+
0 && (module.exports = {
|
|
179
|
+
OpenCodeService
|
|
180
|
+
});
|