vite-plugin-opencode-assistant 1.0.4 → 1.0.6
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/{dist/vite → es}/index.d.ts +1 -1
- 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 +28 -33
- package/README.md +0 -287
- package/dist/constants.d.ts +0 -74
- package/dist/constants.js +0 -75
- 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 -372
- 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 -126
- package/dist/types.js +0 -2
- package/dist/types.js.map +0 -1
- package/dist/vite/client.js +0 -2468
- package/dist/vite/client.js.map +0 -1
- package/dist/vite/index.js +0 -697
- 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,163 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
3
|
+
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
4
|
+
var __async = (__this, __arguments, generator) => {
|
|
5
|
+
return new Promise((resolve, reject) => {
|
|
6
|
+
var fulfilled = (value) => {
|
|
7
|
+
try {
|
|
8
|
+
step(generator.next(value));
|
|
9
|
+
} catch (e) {
|
|
10
|
+
reject(e);
|
|
11
|
+
}
|
|
12
|
+
};
|
|
13
|
+
var rejected = (value) => {
|
|
14
|
+
try {
|
|
15
|
+
step(generator.throw(value));
|
|
16
|
+
} catch (e) {
|
|
17
|
+
reject(e);
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
|
|
21
|
+
step((generator = generator.apply(__this, __arguments)).next());
|
|
22
|
+
});
|
|
23
|
+
};
|
|
24
|
+
import { prepareOpenCodeRuntime, startOpenCodeWeb } from "@vite-plugin-opencode-assistant/opencode";
|
|
25
|
+
import { SERVER_START_TIMEOUT, createLogger } from "@vite-plugin-opencode-assistant/shared";
|
|
26
|
+
import {
|
|
27
|
+
checkOpenCodeInstalled,
|
|
28
|
+
findAvailablePort,
|
|
29
|
+
killOrphanOpenCodeProcesses,
|
|
30
|
+
waitForServer
|
|
31
|
+
} from "../utils/system.js";
|
|
32
|
+
const log = createLogger("Service");
|
|
33
|
+
class OpenCodeService {
|
|
34
|
+
constructor(config, api, sseClients, onPortAllocated) {
|
|
35
|
+
__publicField(this, "config", config);
|
|
36
|
+
__publicField(this, "api", api);
|
|
37
|
+
__publicField(this, "sseClients", sseClients);
|
|
38
|
+
__publicField(this, "onPortAllocated", onPortAllocated);
|
|
39
|
+
__publicField(this, "webProcess", null);
|
|
40
|
+
__publicField(this, "actualWebPort");
|
|
41
|
+
__publicField(this, "isStarted", false);
|
|
42
|
+
__publicField(this, "startPromise", null);
|
|
43
|
+
__publicField(this, "sessionUrl", null);
|
|
44
|
+
this.actualWebPort = config.webPort;
|
|
45
|
+
}
|
|
46
|
+
start(corsOrigins, contextApiUrl, viteOrigin) {
|
|
47
|
+
return __async(this, null, function* () {
|
|
48
|
+
if (this.isStarted && this.webProcess) {
|
|
49
|
+
log.debug("Services already started, skipping");
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
if (this.startPromise) {
|
|
53
|
+
log.debug("Waiting for existing start promise");
|
|
54
|
+
return this.startPromise;
|
|
55
|
+
}
|
|
56
|
+
this.startPromise = (() => __async(this, null, function* () {
|
|
57
|
+
const timer = log.timer("startServices", {
|
|
58
|
+
corsOrigins,
|
|
59
|
+
contextApiUrl,
|
|
60
|
+
viteOrigin
|
|
61
|
+
});
|
|
62
|
+
log.info("Starting OpenCode services...");
|
|
63
|
+
const orphanCount = yield killOrphanOpenCodeProcesses();
|
|
64
|
+
if (orphanCount > 0) {
|
|
65
|
+
log.debug(`Killed ${orphanCount} orphan OpenCode process(es)`);
|
|
66
|
+
}
|
|
67
|
+
if (!(yield checkOpenCodeInstalled())) {
|
|
68
|
+
log.error(`OpenCode is not installed!
|
|
69
|
+
|
|
70
|
+
Please install OpenCode first:
|
|
71
|
+
|
|
72
|
+
# YOLO
|
|
73
|
+
curl -fsSL https://opencode.ai/install | bash
|
|
74
|
+
|
|
75
|
+
# Package managers
|
|
76
|
+
npm i -g opencode-ai@latest # or bun/pnpm/yarn
|
|
77
|
+
scoop install opencode # Windows
|
|
78
|
+
choco install opencode # Windows
|
|
79
|
+
brew install anomalyco/tap/opencode # macOS and Linux (recommended, always up to date)
|
|
80
|
+
brew install opencode # macOS and Linux (official brew formula, updated less)
|
|
81
|
+
sudo pacman -S opencode # Arch Linux (Stable)
|
|
82
|
+
paru -S opencode-bin # Arch Linux (Latest from AUR)
|
|
83
|
+
mise use -g opencode # Any OS
|
|
84
|
+
nix run nixpkgs#opencode # or github:anomalyco/opencode for latest dev branch
|
|
85
|
+
`);
|
|
86
|
+
timer.end("\u274C OpenCode not installed");
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
timer.checkpoint("OpenCode installation verified");
|
|
90
|
+
this.actualWebPort = yield findAvailablePort(this.config.webPort, this.config.hostname);
|
|
91
|
+
this.onPortAllocated(this.actualWebPort);
|
|
92
|
+
if (this.actualWebPort !== this.config.webPort) {
|
|
93
|
+
log.info(`Port ${this.config.webPort} is in use, using ${this.actualWebPort} instead`);
|
|
94
|
+
} else {
|
|
95
|
+
log.debug(`Using port ${this.actualWebPort}`);
|
|
96
|
+
}
|
|
97
|
+
timer.checkpoint("Port allocated");
|
|
98
|
+
const configDir = prepareOpenCodeRuntime(process.cwd());
|
|
99
|
+
timer.checkpoint("Plugin setup complete");
|
|
100
|
+
log.debug("Starting OpenCode Web process...", {
|
|
101
|
+
port: this.actualWebPort,
|
|
102
|
+
hostname: this.config.hostname,
|
|
103
|
+
configDir
|
|
104
|
+
});
|
|
105
|
+
this.webProcess = startOpenCodeWeb({
|
|
106
|
+
port: this.actualWebPort,
|
|
107
|
+
hostname: this.config.hostname,
|
|
108
|
+
serverUrl: "",
|
|
109
|
+
cwd: process.cwd(),
|
|
110
|
+
configDir,
|
|
111
|
+
corsOrigins,
|
|
112
|
+
contextApiUrl
|
|
113
|
+
});
|
|
114
|
+
timer.checkpoint("Web process started");
|
|
115
|
+
const webUrl = `http://${this.config.hostname}:${this.actualWebPort}`;
|
|
116
|
+
log.info(`Waiting for OpenCode Web to become ready at ${webUrl}...`);
|
|
117
|
+
yield waitForServer(webUrl, SERVER_START_TIMEOUT);
|
|
118
|
+
log.info(`OpenCode Web started at ${webUrl}`);
|
|
119
|
+
yield this.api.warmupChromeMcp(viteOrigin);
|
|
120
|
+
timer.checkpoint("Chrome MCP warmup complete");
|
|
121
|
+
try {
|
|
122
|
+
this.sessionUrl = yield this.api.getOrCreateSession();
|
|
123
|
+
timer.checkpoint("Session created");
|
|
124
|
+
log.debug(`Session URL: ${this.sessionUrl}`);
|
|
125
|
+
this.sseClients.forEach((client) => {
|
|
126
|
+
try {
|
|
127
|
+
client.write(
|
|
128
|
+
`data: ${JSON.stringify({ type: "SESSION_READY", sessionUrl: this.sessionUrl })}
|
|
129
|
+
|
|
130
|
+
`
|
|
131
|
+
);
|
|
132
|
+
} catch (e) {
|
|
133
|
+
log.debug("Failed to send SESSION_READY event", { error: e });
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
} catch (e) {
|
|
137
|
+
log.warn("Failed to get/create session", { error: e });
|
|
138
|
+
}
|
|
139
|
+
this.isStarted = true;
|
|
140
|
+
log.debug(`OpenCode services started successfully: ${this.sessionUrl || webUrl}`);
|
|
141
|
+
timer.end("\u2713 Services started successfully");
|
|
142
|
+
}))();
|
|
143
|
+
return this.startPromise;
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
stop() {
|
|
147
|
+
return __async(this, null, function* () {
|
|
148
|
+
const timer = log.timer("stopServices");
|
|
149
|
+
log.info("Stopping OpenCode services...");
|
|
150
|
+
if (this.webProcess) {
|
|
151
|
+
log.debug("Killing web process", { pid: this.webProcess.pid });
|
|
152
|
+
this.webProcess.kill("SIGTERM");
|
|
153
|
+
this.webProcess = null;
|
|
154
|
+
}
|
|
155
|
+
this.isStarted = false;
|
|
156
|
+
this.startPromise = null;
|
|
157
|
+
timer.end("\u2713 Services stopped");
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
export {
|
|
162
|
+
OpenCodeService
|
|
163
|
+
};
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
var __async = (__this, __arguments, generator) => {
|
|
2
|
+
return new Promise((resolve, reject) => {
|
|
3
|
+
var fulfilled = (value) => {
|
|
4
|
+
try {
|
|
5
|
+
step(generator.next(value));
|
|
6
|
+
} catch (e) {
|
|
7
|
+
reject(e);
|
|
8
|
+
}
|
|
9
|
+
};
|
|
10
|
+
var rejected = (value) => {
|
|
11
|
+
try {
|
|
12
|
+
step(generator.throw(value));
|
|
13
|
+
} catch (e) {
|
|
14
|
+
reject(e);
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
|
|
18
|
+
step((generator = generator.apply(__this, __arguments)).next());
|
|
19
|
+
});
|
|
20
|
+
};
|
|
21
|
+
import { CONTEXT_API_PATH } from "@vite-plugin-opencode-assistant/shared";
|
|
22
|
+
import { RequestContext, createLogger } from "@vite-plugin-opencode-assistant/shared";
|
|
23
|
+
const log = createLogger("Endpoints:Context");
|
|
24
|
+
function setupContextEndpoint(server, ctx) {
|
|
25
|
+
server.middlewares.use(CONTEXT_API_PATH, (req, res) => __async(null, null, function* () {
|
|
26
|
+
const reqCtx = new RequestContext(req.method || "GET", CONTEXT_API_PATH);
|
|
27
|
+
res.setHeader("Content-Type", "application/json");
|
|
28
|
+
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
29
|
+
res.setHeader("Access-Control-Allow-Methods", "GET, POST, DELETE, OPTIONS");
|
|
30
|
+
res.setHeader("Access-Control-Allow-Headers", "Content-Type");
|
|
31
|
+
if (req.method === "OPTIONS") {
|
|
32
|
+
res.writeHead(200);
|
|
33
|
+
res.end();
|
|
34
|
+
reqCtx.end(200);
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
if (req.method === "GET") {
|
|
38
|
+
res.writeHead(200);
|
|
39
|
+
res.end(JSON.stringify(ctx.pageContext));
|
|
40
|
+
reqCtx.end(200);
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
if (req.method === "DELETE") {
|
|
44
|
+
ctx.pageContext.selectedElements = [];
|
|
45
|
+
log.debug("Selected elements cleared", { sseClients: ctx.sseClients.size });
|
|
46
|
+
let sentCount = 0;
|
|
47
|
+
ctx.sseClients.forEach((client) => {
|
|
48
|
+
try {
|
|
49
|
+
client.write(`data: ${JSON.stringify({ type: "CLEAR_ELEMENTS" })}
|
|
50
|
+
|
|
51
|
+
`);
|
|
52
|
+
sentCount++;
|
|
53
|
+
} catch (e) {
|
|
54
|
+
log.debug("Failed to send SSE message", { error: e });
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
log.debug("SSE messages sent", {
|
|
58
|
+
count: sentCount,
|
|
59
|
+
totalClients: ctx.sseClients.size
|
|
60
|
+
});
|
|
61
|
+
res.writeHead(200);
|
|
62
|
+
res.end(JSON.stringify({ success: true }));
|
|
63
|
+
reqCtx.end(200);
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
if (req.method === "POST") {
|
|
67
|
+
let body = "";
|
|
68
|
+
req.on("data", (chunk) => body += chunk);
|
|
69
|
+
req.on("end", () => {
|
|
70
|
+
var _a;
|
|
71
|
+
try {
|
|
72
|
+
const data = JSON.parse(body);
|
|
73
|
+
ctx.pageContext = {
|
|
74
|
+
url: data.url || "",
|
|
75
|
+
title: data.title || "",
|
|
76
|
+
selectedElements: data.selectedElements || []
|
|
77
|
+
};
|
|
78
|
+
log.debug("Context updated", {
|
|
79
|
+
url: ctx.pageContext.url,
|
|
80
|
+
title: ctx.pageContext.title,
|
|
81
|
+
selectedElementsCount: ((_a = ctx.pageContext.selectedElements) == null ? void 0 : _a.length) || 0
|
|
82
|
+
});
|
|
83
|
+
if (ctx.pageContext.selectedElements && ctx.pageContext.selectedElements.length > 0) {
|
|
84
|
+
log.debug("Selected elements details", {
|
|
85
|
+
elements: ctx.pageContext.selectedElements.map((el) => {
|
|
86
|
+
var _a2;
|
|
87
|
+
return {
|
|
88
|
+
filePath: el.filePath,
|
|
89
|
+
line: el.line,
|
|
90
|
+
text: (_a2 = el.innerText) == null ? void 0 : _a2.substring(0, 50)
|
|
91
|
+
};
|
|
92
|
+
})
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
res.writeHead(200);
|
|
96
|
+
res.end(JSON.stringify({ success: true }));
|
|
97
|
+
reqCtx.end(200);
|
|
98
|
+
} catch (e) {
|
|
99
|
+
log.debug("Invalid JSON in request body", { error: e });
|
|
100
|
+
res.writeHead(400);
|
|
101
|
+
res.end(JSON.stringify({ error: "Invalid JSON" }));
|
|
102
|
+
reqCtx.error(e);
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
res.writeHead(405);
|
|
108
|
+
res.end(JSON.stringify({ error: "Method not allowed" }));
|
|
109
|
+
reqCtx.end(405);
|
|
110
|
+
}));
|
|
111
|
+
}
|
|
112
|
+
export {
|
|
113
|
+
setupContextEndpoint
|
|
114
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { setupWidgetEndpoints } from "./widget.js";
|
|
2
|
+
import { setupContextEndpoint } from "./context.js";
|
|
3
|
+
import { setupStartEndpoint } from "./start.js";
|
|
4
|
+
import { setupSseEndpoint } from "./sse.js";
|
|
5
|
+
import { setupSessionsEndpoint } from "./sessions.js";
|
|
6
|
+
export * from "./types.js";
|
|
7
|
+
function setupMiddlewares(server, ctx) {
|
|
8
|
+
setupWidgetEndpoints(server, ctx);
|
|
9
|
+
setupContextEndpoint(server, ctx);
|
|
10
|
+
setupStartEndpoint(server, ctx);
|
|
11
|
+
setupSseEndpoint(server, ctx);
|
|
12
|
+
setupSessionsEndpoint(server, ctx);
|
|
13
|
+
}
|
|
14
|
+
export {
|
|
15
|
+
setupMiddlewares
|
|
16
|
+
};
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
var __async = (__this, __arguments, generator) => {
|
|
2
|
+
return new Promise((resolve, reject) => {
|
|
3
|
+
var fulfilled = (value) => {
|
|
4
|
+
try {
|
|
5
|
+
step(generator.next(value));
|
|
6
|
+
} catch (e) {
|
|
7
|
+
reject(e);
|
|
8
|
+
}
|
|
9
|
+
};
|
|
10
|
+
var rejected = (value) => {
|
|
11
|
+
try {
|
|
12
|
+
step(generator.throw(value));
|
|
13
|
+
} catch (e) {
|
|
14
|
+
reject(e);
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
|
|
18
|
+
step((generator = generator.apply(__this, __arguments)).next());
|
|
19
|
+
});
|
|
20
|
+
};
|
|
21
|
+
import { SESSIONS_API_PATH } from "@vite-plugin-opencode-assistant/shared";
|
|
22
|
+
import { RequestContext, createLogger } from "@vite-plugin-opencode-assistant/shared";
|
|
23
|
+
const log = createLogger("Endpoints:Sessions");
|
|
24
|
+
function setupSessionsEndpoint(server, ctx) {
|
|
25
|
+
server.middlewares.use(SESSIONS_API_PATH, (req, res) => __async(null, null, function* () {
|
|
26
|
+
const reqCtx = new RequestContext(req.method || "GET", SESSIONS_API_PATH);
|
|
27
|
+
res.setHeader("Content-Type", "application/json");
|
|
28
|
+
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
29
|
+
res.setHeader("Access-Control-Allow-Methods", "GET, POST, DELETE, OPTIONS");
|
|
30
|
+
res.setHeader("Access-Control-Allow-Headers", "Content-Type");
|
|
31
|
+
if (req.method === "OPTIONS") {
|
|
32
|
+
res.writeHead(200);
|
|
33
|
+
res.end();
|
|
34
|
+
reqCtx.end(200);
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
try {
|
|
38
|
+
if (req.method === "GET") {
|
|
39
|
+
reqCtx.checkpoint("Fetching sessions");
|
|
40
|
+
const sessions = yield ctx.getSessions();
|
|
41
|
+
res.writeHead(200);
|
|
42
|
+
res.end(JSON.stringify(sessions));
|
|
43
|
+
reqCtx.end(200);
|
|
44
|
+
} else if (req.method === "POST") {
|
|
45
|
+
reqCtx.checkpoint("Creating session");
|
|
46
|
+
const newSession = yield ctx.createSession();
|
|
47
|
+
res.writeHead(200);
|
|
48
|
+
res.end(JSON.stringify(newSession));
|
|
49
|
+
reqCtx.end(200);
|
|
50
|
+
} else if (req.method === "DELETE") {
|
|
51
|
+
const url = new URL(req.url || "", `http://${req.headers.host}`);
|
|
52
|
+
const sessionId = url.searchParams.get("id");
|
|
53
|
+
if (!sessionId) {
|
|
54
|
+
res.writeHead(400);
|
|
55
|
+
res.end(JSON.stringify({ error: "Session ID is required" }));
|
|
56
|
+
reqCtx.end(400);
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
reqCtx.checkpoint(`Deleting session: ${sessionId}`);
|
|
60
|
+
yield ctx.deleteSession(sessionId);
|
|
61
|
+
res.writeHead(200);
|
|
62
|
+
res.end(JSON.stringify({ success: true }));
|
|
63
|
+
reqCtx.end(200);
|
|
64
|
+
} else {
|
|
65
|
+
res.writeHead(405);
|
|
66
|
+
res.end(JSON.stringify({ error: "Method not allowed" }));
|
|
67
|
+
reqCtx.end(405);
|
|
68
|
+
}
|
|
69
|
+
} catch (e) {
|
|
70
|
+
log.error("Session API error", { error: e, method: req.method });
|
|
71
|
+
res.writeHead(500);
|
|
72
|
+
res.end(JSON.stringify({ error: String(e) }));
|
|
73
|
+
reqCtx.error(e);
|
|
74
|
+
}
|
|
75
|
+
}));
|
|
76
|
+
}
|
|
77
|
+
export {
|
|
78
|
+
setupSessionsEndpoint
|
|
79
|
+
};
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
var __async = (__this, __arguments, generator) => {
|
|
2
|
+
return new Promise((resolve, reject) => {
|
|
3
|
+
var fulfilled = (value) => {
|
|
4
|
+
try {
|
|
5
|
+
step(generator.next(value));
|
|
6
|
+
} catch (e) {
|
|
7
|
+
reject(e);
|
|
8
|
+
}
|
|
9
|
+
};
|
|
10
|
+
var rejected = (value) => {
|
|
11
|
+
try {
|
|
12
|
+
step(generator.throw(value));
|
|
13
|
+
} catch (e) {
|
|
14
|
+
reject(e);
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
|
|
18
|
+
step((generator = generator.apply(__this, __arguments)).next());
|
|
19
|
+
});
|
|
20
|
+
};
|
|
21
|
+
import { SSE_EVENTS_PATH } from "@vite-plugin-opencode-assistant/shared";
|
|
22
|
+
import { RequestContext, createLogger } from "@vite-plugin-opencode-assistant/shared";
|
|
23
|
+
const log = createLogger("Endpoints:SSE");
|
|
24
|
+
function setupSseEndpoint(server, ctx) {
|
|
25
|
+
server.middlewares.use(SSE_EVENTS_PATH, (req, res) => __async(null, null, function* () {
|
|
26
|
+
const reqCtx = new RequestContext("GET", SSE_EVENTS_PATH);
|
|
27
|
+
res.writeHead(200, {
|
|
28
|
+
"Content-Type": "text/event-stream",
|
|
29
|
+
"Cache-Control": "no-cache",
|
|
30
|
+
Connection: "keep-alive",
|
|
31
|
+
"Access-Control-Allow-Origin": "*"
|
|
32
|
+
});
|
|
33
|
+
ctx.sseClients.add(res);
|
|
34
|
+
log.debug("SSE client connected", { totalClients: ctx.sseClients.size });
|
|
35
|
+
res.write(`data: ${JSON.stringify({ type: "CONNECTED" })}
|
|
36
|
+
|
|
37
|
+
`);
|
|
38
|
+
if (ctx.sessionUrl) {
|
|
39
|
+
res.write(
|
|
40
|
+
`data: ${JSON.stringify({ type: "SESSION_READY", sessionUrl: ctx.sessionUrl })}
|
|
41
|
+
|
|
42
|
+
`
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
req.on("close", () => {
|
|
46
|
+
ctx.sseClients.delete(res);
|
|
47
|
+
log.debug("SSE client disconnected", {
|
|
48
|
+
totalClients: ctx.sseClients.size
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
reqCtx.end(200);
|
|
52
|
+
}));
|
|
53
|
+
}
|
|
54
|
+
export {
|
|
55
|
+
setupSseEndpoint
|
|
56
|
+
};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
var __async = (__this, __arguments, generator) => {
|
|
2
|
+
return new Promise((resolve, reject) => {
|
|
3
|
+
var fulfilled = (value) => {
|
|
4
|
+
try {
|
|
5
|
+
step(generator.next(value));
|
|
6
|
+
} catch (e) {
|
|
7
|
+
reject(e);
|
|
8
|
+
}
|
|
9
|
+
};
|
|
10
|
+
var rejected = (value) => {
|
|
11
|
+
try {
|
|
12
|
+
step(generator.throw(value));
|
|
13
|
+
} catch (e) {
|
|
14
|
+
reject(e);
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
|
|
18
|
+
step((generator = generator.apply(__this, __arguments)).next());
|
|
19
|
+
});
|
|
20
|
+
};
|
|
21
|
+
import { START_API_PATH } from "@vite-plugin-opencode-assistant/shared";
|
|
22
|
+
import { RequestContext } from "@vite-plugin-opencode-assistant/shared";
|
|
23
|
+
function setupStartEndpoint(server, ctx) {
|
|
24
|
+
server.middlewares.use(START_API_PATH, (_req, res) => __async(null, null, function* () {
|
|
25
|
+
const reqCtx = new RequestContext("GET", START_API_PATH);
|
|
26
|
+
res.setHeader("Content-Type", "application/json");
|
|
27
|
+
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
28
|
+
res.writeHead(200);
|
|
29
|
+
res.end(JSON.stringify({ success: true, sessionUrl: ctx.sessionUrl }));
|
|
30
|
+
reqCtx.end(200);
|
|
31
|
+
}));
|
|
32
|
+
}
|
|
33
|
+
export {
|
|
34
|
+
setupStartEndpoint
|
|
35
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { PageContext, SessionInfo } from "@vite-plugin-opencode-assistant/shared";
|
|
2
|
+
import type http from "http";
|
|
3
|
+
export interface EndpointContext {
|
|
4
|
+
get sessionUrl(): string | null;
|
|
5
|
+
get sseClients(): Set<http.ServerResponse>;
|
|
6
|
+
get pageContext(): PageContext;
|
|
7
|
+
set pageContext(ctx: PageContext);
|
|
8
|
+
getSessions: () => Promise<SessionInfo[]>;
|
|
9
|
+
createSession: () => Promise<SessionInfo>;
|
|
10
|
+
deleteSession: (id: string) => Promise<void>;
|
|
11
|
+
resolveWidgetPath: () => string;
|
|
12
|
+
resolveWidgetStylePath: () => string;
|
|
13
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
var __async = (__this, __arguments, generator) => {
|
|
2
|
+
return new Promise((resolve, reject) => {
|
|
3
|
+
var fulfilled = (value) => {
|
|
4
|
+
try {
|
|
5
|
+
step(generator.next(value));
|
|
6
|
+
} catch (e) {
|
|
7
|
+
reject(e);
|
|
8
|
+
}
|
|
9
|
+
};
|
|
10
|
+
var rejected = (value) => {
|
|
11
|
+
try {
|
|
12
|
+
step(generator.throw(value));
|
|
13
|
+
} catch (e) {
|
|
14
|
+
reject(e);
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
|
|
18
|
+
step((generator = generator.apply(__this, __arguments)).next());
|
|
19
|
+
});
|
|
20
|
+
};
|
|
21
|
+
import fs from "fs";
|
|
22
|
+
import { WIDGET_SCRIPT_PATH } from "@vite-plugin-opencode-assistant/shared";
|
|
23
|
+
import { RequestContext } from "@vite-plugin-opencode-assistant/shared";
|
|
24
|
+
function setupWidgetEndpoints(server, ctx) {
|
|
25
|
+
server.middlewares.use(WIDGET_SCRIPT_PATH, (_req, res) => __async(null, null, function* () {
|
|
26
|
+
const reqCtx = new RequestContext("GET", WIDGET_SCRIPT_PATH);
|
|
27
|
+
const widgetPath = ctx.resolveWidgetPath();
|
|
28
|
+
if (fs.existsSync(widgetPath)) {
|
|
29
|
+
res.setHeader("Content-Type", "application/javascript");
|
|
30
|
+
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
31
|
+
fs.createReadStream(widgetPath).pipe(res);
|
|
32
|
+
reqCtx.end(200);
|
|
33
|
+
} else {
|
|
34
|
+
res.writeHead(404);
|
|
35
|
+
res.end("Widget script not found");
|
|
36
|
+
reqCtx.end(404);
|
|
37
|
+
}
|
|
38
|
+
}));
|
|
39
|
+
const WIDGET_STYLE_PATH = "/__opencode_widget__.css";
|
|
40
|
+
server.middlewares.use(WIDGET_STYLE_PATH, (_req, res) => __async(null, null, function* () {
|
|
41
|
+
const reqCtx = new RequestContext("GET", WIDGET_STYLE_PATH);
|
|
42
|
+
const stylePath = ctx.resolveWidgetStylePath();
|
|
43
|
+
if (fs.existsSync(stylePath)) {
|
|
44
|
+
res.setHeader("Content-Type", "text/css");
|
|
45
|
+
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
46
|
+
fs.createReadStream(stylePath).pipe(res);
|
|
47
|
+
reqCtx.end(200);
|
|
48
|
+
} else {
|
|
49
|
+
res.writeHead(404);
|
|
50
|
+
res.end("Widget style not found");
|
|
51
|
+
reqCtx.end(404);
|
|
52
|
+
}
|
|
53
|
+
}));
|
|
54
|
+
}
|
|
55
|
+
export {
|
|
56
|
+
setupWidgetEndpoints
|
|
57
|
+
};
|