pockcode 0.0.1
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/build/client/assets/addon-fit-DthTIhi3.js +1 -0
- package/build/client/assets/geist-cyrillic-ext-wght-normal-DjL33-gN.woff2 +0 -0
- package/build/client/assets/geist-cyrillic-wght-normal-BEAKL7Jp.woff2 +0 -0
- package/build/client/assets/geist-latin-ext-wght-normal-DC-KSUi6.woff2 +0 -0
- package/build/client/assets/geist-latin-wght-normal-BgDaEnEv.woff2 +0 -0
- package/build/client/assets/geist-vietnamese-wght-normal-6IgcOCM7.woff2 +0 -0
- package/build/client/assets/index-D7-eRInW.css +2 -0
- package/build/client/assets/index-DQn6eSCt.js +31 -0
- package/build/client/assets/xterm-DooSxjI5.js +36 -0
- package/build/client/index.html +27 -0
- package/dist/assets/api.server-D6ONM6ZJ.js +1736 -0
- package/dist/assets/auth.server-B_P8Jm6O.js +87 -0
- package/dist/assets/chat-status-monitor.server-D2VG_D8P.js +136 -0
- package/dist/assets/chats.service-H6m23Fna.js +4684 -0
- package/dist/assets/manager.server-Cru4ZxHo.js +1334 -0
- package/dist/assets/message-schedule-monitor.server-C4NZg62k.js +32 -0
- package/dist/assets/message-schedules.service-Be9t4LDg.js +407 -0
- package/dist/assets/runtime-paths.server-D6rRjGVb.js +32 -0
- package/dist/assets/socket.server-7dC-9Fnw.js +436 -0
- package/dist/pockcode.js +305 -0
- package/package.json +71 -0
- package/prisma/schema.prisma +234 -0
package/dist/pockcode.js
ADDED
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { createServer } from "node:http";
|
|
3
|
+
import { createReadStream } from "node:fs";
|
|
4
|
+
import { readFile, stat } from "node:fs/promises";
|
|
5
|
+
import { dirname, extname, resolve, sep } from "node:path";
|
|
6
|
+
import { fileURLToPath } from "node:url";
|
|
7
|
+
//#region bin/pockcode.ts
|
|
8
|
+
var defaultHost = "127.0.0.1";
|
|
9
|
+
var defaultPort = 4733;
|
|
10
|
+
async function main() {
|
|
11
|
+
const parsed = parseArgs(process.argv.slice(2));
|
|
12
|
+
if (parsed === "help") {
|
|
13
|
+
console.log(helpText());
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
if (parsed === "version") {
|
|
17
|
+
console.log(await readPackageVersion());
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
process.env.NODE_ENV ||= "production";
|
|
21
|
+
if (parsed.home) process.env.POCKCODE_HOME = parsed.home;
|
|
22
|
+
const [api, auth, socket, chatMonitor, scheduleMonitor, pluginManager] = await Promise.all([
|
|
23
|
+
import("./assets/api.server-D6ONM6ZJ.js"),
|
|
24
|
+
import("./assets/auth.server-B_P8Jm6O.js"),
|
|
25
|
+
import("./assets/socket.server-7dC-9Fnw.js").then((n) => n.a),
|
|
26
|
+
import("./assets/chat-status-monitor.server-D2VG_D8P.js"),
|
|
27
|
+
import("./assets/message-schedule-monitor.server-C4NZg62k.js"),
|
|
28
|
+
import("./assets/manager.server-Cru4ZxHo.js").then((n) => n.r)
|
|
29
|
+
]);
|
|
30
|
+
const clientRoot = await resolveClientRoot();
|
|
31
|
+
const server = createServer((req, res) => {
|
|
32
|
+
(async () => {
|
|
33
|
+
const url = new URL(req.url ?? "/", `http://${req.headers.host ?? "localhost"}`);
|
|
34
|
+
if (await handleAuthGate(req, res, url, auth)) return;
|
|
35
|
+
if (url.pathname.startsWith("/api/")) {
|
|
36
|
+
await api.handleApiRequest(req, res, url).catch((error) => api.sendRouteError(res, error));
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
await serveClientAsset(req, res, url, clientRoot);
|
|
40
|
+
})().catch((error) => {
|
|
41
|
+
sendText(res, 500, error instanceof Error ? error.message : "Request failed.");
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
socket.installProviderSocketServer(server, { authenticateRequest: async (req) => await auth.hasConfiguredPassword() && await auth.isRequestAuthorized(req) });
|
|
45
|
+
chatMonitor.startChatStatusMonitor();
|
|
46
|
+
scheduleMonitor.startMessageScheduleMonitor();
|
|
47
|
+
pluginManager.startPluginRuntimeManager();
|
|
48
|
+
server.listen(parsed.port, parsed.host, () => {
|
|
49
|
+
console.log(`pockcode listening on http://${displayHost(parsed.host)}:${parsed.port}`);
|
|
50
|
+
console.log("First visit will ask you to set a password if one is not configured.");
|
|
51
|
+
});
|
|
52
|
+
for (const signal of ["SIGINT", "SIGTERM"]) process.on(signal, () => {
|
|
53
|
+
server.close(() => process.exit(0));
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
async function handleAuthGate(req, res, url, auth) {
|
|
57
|
+
if (!await auth.hasConfiguredPassword()) {
|
|
58
|
+
if (url.pathname === "/auth/setup" && req.method === "POST") {
|
|
59
|
+
await handlePasswordSetup(req, res, auth);
|
|
60
|
+
return true;
|
|
61
|
+
}
|
|
62
|
+
if (req.method === "GET" || req.method === "HEAD") {
|
|
63
|
+
sendSetupPage(res);
|
|
64
|
+
return true;
|
|
65
|
+
}
|
|
66
|
+
sendJson(res, 428, { error: "Pockcode password setup is required." });
|
|
67
|
+
return true;
|
|
68
|
+
}
|
|
69
|
+
if (await auth.isRequestAuthorized(req)) return false;
|
|
70
|
+
res.statusCode = 401;
|
|
71
|
+
res.setHeader("WWW-Authenticate", `Basic realm="${auth.pockcodeAuthRealm()}", charset="UTF-8"`);
|
|
72
|
+
res.setHeader("Content-Type", "text/plain; charset=utf-8");
|
|
73
|
+
res.end("Authentication required.");
|
|
74
|
+
return true;
|
|
75
|
+
}
|
|
76
|
+
async function handlePasswordSetup(req, res, auth) {
|
|
77
|
+
const body = await readRequestBody(req, 32e3);
|
|
78
|
+
const contentType = req.headers["content-type"] ?? "";
|
|
79
|
+
const wantsJson = req.headers.accept?.includes("application/json") || contentType.includes("application/json");
|
|
80
|
+
const password = contentType.includes("application/json") ? readJsonPassword(body) : new URLSearchParams(body).get("password") ?? "";
|
|
81
|
+
try {
|
|
82
|
+
await auth.setupPassword(password);
|
|
83
|
+
} catch (error) {
|
|
84
|
+
const message = error instanceof Error ? error.message : "Unable to configure password.";
|
|
85
|
+
if (wantsJson) sendJson(res, 400, { error: message });
|
|
86
|
+
else sendSetupPage(res, message, 400);
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
if (wantsJson) {
|
|
90
|
+
sendJson(res, 201, { ok: true });
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
res.statusCode = 303;
|
|
94
|
+
res.setHeader("Location", "/");
|
|
95
|
+
res.end();
|
|
96
|
+
}
|
|
97
|
+
async function serveClientAsset(req, res, url, clientRoot) {
|
|
98
|
+
if (req.method !== "GET" && req.method !== "HEAD") {
|
|
99
|
+
sendText(res, 405, `${req.method ?? "METHOD"} is not supported.`);
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
const filePath = await resolveClientPath(clientRoot, url.pathname);
|
|
103
|
+
if (!filePath) {
|
|
104
|
+
sendText(res, 403, "Forbidden.");
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
const stats = await stat(filePath).catch(() => null);
|
|
108
|
+
const targetPath = stats?.isFile() ? filePath : resolve(clientRoot, "index.html");
|
|
109
|
+
const targetStats = stats?.isFile() ? stats : await stat(targetPath).catch(() => null);
|
|
110
|
+
if (!targetStats?.isFile()) {
|
|
111
|
+
sendText(res, 404, "Pockcode client build was not found. Run pnpm build first.");
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
res.statusCode = 200;
|
|
115
|
+
res.setHeader("Content-Length", String(targetStats.size));
|
|
116
|
+
res.setHeader("Content-Type", contentTypeFor(targetPath));
|
|
117
|
+
if (targetPath.includes(`${sep}assets${sep}`)) res.setHeader("Cache-Control", "public, max-age=31536000, immutable");
|
|
118
|
+
else res.setHeader("Cache-Control", "no-store");
|
|
119
|
+
if (req.method === "HEAD") {
|
|
120
|
+
res.end();
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
createReadStream(targetPath).pipe(res);
|
|
124
|
+
}
|
|
125
|
+
async function resolveClientPath(clientRoot, pathname) {
|
|
126
|
+
let decoded = "/";
|
|
127
|
+
try {
|
|
128
|
+
decoded = decodeURIComponent(pathname);
|
|
129
|
+
} catch {
|
|
130
|
+
return null;
|
|
131
|
+
}
|
|
132
|
+
if (decoded.includes("\0")) return null;
|
|
133
|
+
const filePath = resolve(clientRoot, decoded === "/" ? "index.html" : decoded.replace(/^\/+/u, ""));
|
|
134
|
+
return filePath === clientRoot || filePath.startsWith(`${clientRoot}${sep}`) ? filePath : null;
|
|
135
|
+
}
|
|
136
|
+
async function resolveClientRoot() {
|
|
137
|
+
const here = dirname(fileURLToPath(import.meta.url));
|
|
138
|
+
const candidates = [
|
|
139
|
+
process.env.POCKCODE_CLIENT_DIR,
|
|
140
|
+
resolve(here, "../build/client"),
|
|
141
|
+
resolve(process.cwd(), "build/client")
|
|
142
|
+
].filter((value) => Boolean(value));
|
|
143
|
+
for (const candidate of candidates) {
|
|
144
|
+
const root = resolve(candidate);
|
|
145
|
+
if (await stat(resolve(root, "index.html")).then((stats) => stats.isFile()).catch(() => false)) return root;
|
|
146
|
+
}
|
|
147
|
+
return resolve(candidates[0] ?? "build/client");
|
|
148
|
+
}
|
|
149
|
+
async function readRequestBody(req, limit) {
|
|
150
|
+
const chunks = [];
|
|
151
|
+
let size = 0;
|
|
152
|
+
for await (const chunk of req) {
|
|
153
|
+
const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
|
|
154
|
+
size += buffer.length;
|
|
155
|
+
if (size > limit) throw new Error("Request body is too large.");
|
|
156
|
+
chunks.push(buffer);
|
|
157
|
+
}
|
|
158
|
+
return Buffer.concat(chunks).toString("utf8");
|
|
159
|
+
}
|
|
160
|
+
function readJsonPassword(body) {
|
|
161
|
+
try {
|
|
162
|
+
const value = JSON.parse(body);
|
|
163
|
+
return value && typeof value === "object" && !Array.isArray(value) && typeof value.password === "string" ? value.password : "";
|
|
164
|
+
} catch {
|
|
165
|
+
return "";
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
function parseArgs(argv) {
|
|
169
|
+
const options = {
|
|
170
|
+
host: defaultHost,
|
|
171
|
+
port: readPort(process.env.PORT) ?? defaultPort
|
|
172
|
+
};
|
|
173
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
174
|
+
const arg = argv[index];
|
|
175
|
+
if (arg === "--help" || arg === "-h") return "help";
|
|
176
|
+
if (arg === "--version" || arg === "-v") return "version";
|
|
177
|
+
if (arg === "--host" || arg === "--bind" || arg === "-H") {
|
|
178
|
+
options.host = readValue(argv, ++index, arg);
|
|
179
|
+
continue;
|
|
180
|
+
}
|
|
181
|
+
if (arg.startsWith("--host=") || arg.startsWith("--bind=")) {
|
|
182
|
+
options.host = arg.slice(arg.indexOf("=") + 1);
|
|
183
|
+
continue;
|
|
184
|
+
}
|
|
185
|
+
if (arg === "--port" || arg === "-p") {
|
|
186
|
+
options.port = readPort(readValue(argv, ++index, arg)) ?? invalidPort(arg);
|
|
187
|
+
continue;
|
|
188
|
+
}
|
|
189
|
+
if (arg.startsWith("--port=")) {
|
|
190
|
+
options.port = readPort(arg.slice(7)) ?? invalidPort("--port");
|
|
191
|
+
continue;
|
|
192
|
+
}
|
|
193
|
+
if (arg === "--home") {
|
|
194
|
+
options.home = readValue(argv, ++index, arg);
|
|
195
|
+
continue;
|
|
196
|
+
}
|
|
197
|
+
if (arg.startsWith("--home=")) {
|
|
198
|
+
options.home = arg.slice(7);
|
|
199
|
+
continue;
|
|
200
|
+
}
|
|
201
|
+
throw new Error(`Unknown option: ${arg}\n\n${helpText()}`);
|
|
202
|
+
}
|
|
203
|
+
return options;
|
|
204
|
+
}
|
|
205
|
+
function readValue(argv, index, option) {
|
|
206
|
+
const value = argv[index];
|
|
207
|
+
if (!value || value.startsWith("-")) throw new Error(`${option} requires a value.`);
|
|
208
|
+
return value;
|
|
209
|
+
}
|
|
210
|
+
function readPort(value) {
|
|
211
|
+
if (!value) return null;
|
|
212
|
+
const port = Number.parseInt(value, 10);
|
|
213
|
+
return Number.isInteger(port) && port > 0 && port <= 65535 ? port : null;
|
|
214
|
+
}
|
|
215
|
+
function invalidPort(option) {
|
|
216
|
+
throw new Error(`${option} requires a port between 1 and 65535.`);
|
|
217
|
+
}
|
|
218
|
+
function sendSetupPage(res, error, status = 200) {
|
|
219
|
+
res.statusCode = status;
|
|
220
|
+
res.setHeader("Content-Type", "text/html; charset=utf-8");
|
|
221
|
+
res.end(`<!doctype html>
|
|
222
|
+
<html lang="en">
|
|
223
|
+
<head>
|
|
224
|
+
<meta charset="utf-8" />
|
|
225
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
226
|
+
<title>pockcode setup</title>
|
|
227
|
+
<style>
|
|
228
|
+
:root { color-scheme: dark; font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; }
|
|
229
|
+
body { min-height: 100vh; margin: 0; display: grid; place-items: center; background: #0f1115; color: #f6f7fb; }
|
|
230
|
+
main { width: min(420px, calc(100vw - 32px)); border: 1px solid #2a2f3a; border-radius: 10px; background: #161922; padding: 24px; box-shadow: 0 24px 80px rgb(0 0 0 / 0.35); }
|
|
231
|
+
h1 { margin: 0 0 8px; font-size: 20px; }
|
|
232
|
+
p { margin: 0 0 18px; color: #aeb6c5; font-size: 14px; line-height: 1.5; }
|
|
233
|
+
label { display: grid; gap: 8px; font-size: 13px; font-weight: 600; }
|
|
234
|
+
input { height: 38px; border-radius: 8px; border: 1px solid #343b49; background: #0f1115; color: #f6f7fb; padding: 0 12px; font: inherit; }
|
|
235
|
+
button { margin-top: 16px; height: 38px; width: 100%; border: 0; border-radius: 8px; background: #f6f7fb; color: #111318; font-weight: 700; cursor: pointer; }
|
|
236
|
+
.error { margin-bottom: 14px; color: #ff9a9a; font-size: 13px; }
|
|
237
|
+
</style>
|
|
238
|
+
</head>
|
|
239
|
+
<body>
|
|
240
|
+
<main>
|
|
241
|
+
<h1>Set up pockcode</h1>
|
|
242
|
+
<p>Create the password used for HTTP Basic authentication.</p>
|
|
243
|
+
${error ? `<div class="error">${escapeHtml(error)}</div>` : ""}
|
|
244
|
+
<form method="post" action="/auth/setup">
|
|
245
|
+
<label>
|
|
246
|
+
Password
|
|
247
|
+
<input name="password" type="password" minlength="8" autocomplete="new-password" autofocus required />
|
|
248
|
+
</label>
|
|
249
|
+
<button type="submit">Save password</button>
|
|
250
|
+
</form>
|
|
251
|
+
</main>
|
|
252
|
+
</body>
|
|
253
|
+
</html>`);
|
|
254
|
+
}
|
|
255
|
+
function sendJson(res, status, data) {
|
|
256
|
+
res.statusCode = status;
|
|
257
|
+
res.setHeader("Content-Type", "application/json");
|
|
258
|
+
res.end(JSON.stringify(data));
|
|
259
|
+
}
|
|
260
|
+
function sendText(res, status, text) {
|
|
261
|
+
if (res.writableEnded) return;
|
|
262
|
+
res.statusCode = status;
|
|
263
|
+
res.setHeader("Content-Type", "text/plain; charset=utf-8");
|
|
264
|
+
res.end(text);
|
|
265
|
+
}
|
|
266
|
+
function contentTypeFor(filePath) {
|
|
267
|
+
const extension = extname(filePath);
|
|
268
|
+
if (extension === ".html") return "text/html; charset=utf-8";
|
|
269
|
+
if (extension === ".css") return "text/css; charset=utf-8";
|
|
270
|
+
if (extension === ".js" || extension === ".mjs") return "text/javascript; charset=utf-8";
|
|
271
|
+
if (extension === ".json") return "application/json; charset=utf-8";
|
|
272
|
+
if (extension === ".svg") return "image/svg+xml";
|
|
273
|
+
if (extension === ".png") return "image/png";
|
|
274
|
+
if (extension === ".jpg" || extension === ".jpeg") return "image/jpeg";
|
|
275
|
+
if (extension === ".webp") return "image/webp";
|
|
276
|
+
if (extension === ".woff2") return "font/woff2";
|
|
277
|
+
return "application/octet-stream";
|
|
278
|
+
}
|
|
279
|
+
function displayHost(host) {
|
|
280
|
+
return host === "0.0.0.0" || host === "::" ? "localhost" : host;
|
|
281
|
+
}
|
|
282
|
+
async function readPackageVersion() {
|
|
283
|
+
const packagePath = resolve(dirname(fileURLToPath(import.meta.url)), "../package.json");
|
|
284
|
+
return JSON.parse(await readFile(packagePath, "utf8")).version ?? "0.0.0";
|
|
285
|
+
}
|
|
286
|
+
function escapeHtml(value) {
|
|
287
|
+
return value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll("\"", """);
|
|
288
|
+
}
|
|
289
|
+
function helpText() {
|
|
290
|
+
return `Usage: pockcode [options]
|
|
291
|
+
|
|
292
|
+
Options:
|
|
293
|
+
-H, --host, --bind <host> Host/interface to bind (default: ${defaultHost})
|
|
294
|
+
-p, --port <port> Port to listen on (default: ${defaultPort})
|
|
295
|
+
--home <path> Pockcode data directory (default: ~/.pockcode)
|
|
296
|
+
-v, --version Print version
|
|
297
|
+
-h, --help Print help
|
|
298
|
+
`;
|
|
299
|
+
}
|
|
300
|
+
main().catch((error) => {
|
|
301
|
+
console.error(error instanceof Error ? error.message : error);
|
|
302
|
+
process.exit(1);
|
|
303
|
+
});
|
|
304
|
+
//#endregion
|
|
305
|
+
export {};
|
package/package.json
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "pockcode",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "git+https://github.com/monokaijs/pockcode.git"
|
|
8
|
+
},
|
|
9
|
+
"engines": {
|
|
10
|
+
"node": ">=20.0.0"
|
|
11
|
+
},
|
|
12
|
+
"bin": {
|
|
13
|
+
"pockcode": "./dist/pockcode.js"
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"build/client",
|
|
17
|
+
"dist",
|
|
18
|
+
"prisma/schema.prisma"
|
|
19
|
+
],
|
|
20
|
+
"publishConfig": {
|
|
21
|
+
"registry": "https://registry.npmjs.org/"
|
|
22
|
+
},
|
|
23
|
+
"packageManager": "pnpm@10.17.1",
|
|
24
|
+
"scripts": {
|
|
25
|
+
"dev": "vite --host 0.0.0.0",
|
|
26
|
+
"build": "tsc -b && vite build --config vite.client.config.ts && vite build --config vite.cli.config.ts",
|
|
27
|
+
"postinstall": "prisma generate --schema=prisma/schema.prisma",
|
|
28
|
+
"prepack": "npm run build",
|
|
29
|
+
"preview": "node dist/pockcode.js --host 0.0.0.0",
|
|
30
|
+
"test": "vitest run",
|
|
31
|
+
"test:real-codex": "node scripts/real-codex-smoke.mjs",
|
|
32
|
+
"typecheck": "tsc --noEmit"
|
|
33
|
+
},
|
|
34
|
+
"dependencies": {
|
|
35
|
+
"@base-ui/react": "^1.6.0",
|
|
36
|
+
"@fontsource-variable/geist": "^5.2.9",
|
|
37
|
+
"@monaco-editor/react": "^4.7.0",
|
|
38
|
+
"@openai/codex": "^0.130.0",
|
|
39
|
+
"@prisma/client": "^6.19.3",
|
|
40
|
+
"@react-router/dev": "^7.15.1",
|
|
41
|
+
"@xterm/addon-fit": "^0.11.0",
|
|
42
|
+
"@xterm/xterm": "^6.0.0",
|
|
43
|
+
"class-variance-authority": "^0.7.1",
|
|
44
|
+
"clsx": "^2.1.1",
|
|
45
|
+
"dotenv": "^17.4.2",
|
|
46
|
+
"grammy": "^1.44.0",
|
|
47
|
+
"lucide-react": "^1.21.0",
|
|
48
|
+
"monaco-editor": "^0.55.1",
|
|
49
|
+
"node-pty": "^1.1.0",
|
|
50
|
+
"prisma": "^6.19.3",
|
|
51
|
+
"react": "^19.2.7",
|
|
52
|
+
"react-dom": "^19.2.7",
|
|
53
|
+
"react-router": "^7.15.1",
|
|
54
|
+
"smol-toml": "^1.7.0",
|
|
55
|
+
"socket.io": "^4.8.3",
|
|
56
|
+
"socket.io-client": "^4.8.3",
|
|
57
|
+
"tailwind-merge": "^3.6.0",
|
|
58
|
+
"tw-animate-css": "^1.4.0"
|
|
59
|
+
},
|
|
60
|
+
"devDependencies": {
|
|
61
|
+
"@tailwindcss/vite": "^4.3.1",
|
|
62
|
+
"@types/node": "^24.12.4",
|
|
63
|
+
"@types/react": "^19.2.14",
|
|
64
|
+
"@types/react-dom": "^19.2.3",
|
|
65
|
+
"@vitejs/plugin-react": "^6.0.2",
|
|
66
|
+
"tailwindcss": "^4.3.1",
|
|
67
|
+
"typescript": "^5.9.3",
|
|
68
|
+
"vite": "^8.0.16",
|
|
69
|
+
"vitest": "^4.1.9"
|
|
70
|
+
}
|
|
71
|
+
}
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
generator client {
|
|
2
|
+
provider = "prisma-client-js"
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
datasource db {
|
|
6
|
+
provider = "sqlite"
|
|
7
|
+
url = env("DATABASE_URL")
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
enum ProviderAccountStatus {
|
|
11
|
+
DISCONNECTED
|
|
12
|
+
AUTHENTICATING
|
|
13
|
+
CONNECTED
|
|
14
|
+
INVALIDATED
|
|
15
|
+
ERROR
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
enum ChatStatus {
|
|
19
|
+
IDLE
|
|
20
|
+
RUNNING
|
|
21
|
+
ARCHIVED
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
enum MessageScheduleStatus {
|
|
25
|
+
ACTIVE
|
|
26
|
+
PAUSED
|
|
27
|
+
COMPLETED
|
|
28
|
+
ARCHIVED
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
enum MessageScheduleRunStatus {
|
|
32
|
+
QUEUED
|
|
33
|
+
RUNNING
|
|
34
|
+
COMPLETED
|
|
35
|
+
FAILED
|
|
36
|
+
CANCELLED
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
enum RunStatus {
|
|
40
|
+
QUEUED
|
|
41
|
+
RUNNING
|
|
42
|
+
COMPLETED
|
|
43
|
+
FAILED
|
|
44
|
+
CANCELLED
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
model ProviderSetting {
|
|
48
|
+
providerId String @id
|
|
49
|
+
settings Json @default("{}")
|
|
50
|
+
createdAt DateTime @default(now())
|
|
51
|
+
updatedAt DateTime @updatedAt
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
model PluginSetting {
|
|
55
|
+
pluginId String @id
|
|
56
|
+
enabled Boolean @default(false)
|
|
57
|
+
settings Json @default("{}")
|
|
58
|
+
secrets Json @default("{}")
|
|
59
|
+
createdAt DateTime @default(now())
|
|
60
|
+
updatedAt DateTime @updatedAt
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
model PluginState {
|
|
64
|
+
pluginId String @id
|
|
65
|
+
state Json @default("{}")
|
|
66
|
+
createdAt DateTime @default(now())
|
|
67
|
+
updatedAt DateTime @updatedAt
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
model WorkspaceHistory {
|
|
71
|
+
id String @default(uuid()) @unique
|
|
72
|
+
path String @id
|
|
73
|
+
name String
|
|
74
|
+
lastOpenedAt DateTime @default(now())
|
|
75
|
+
createdAt DateTime @default(now())
|
|
76
|
+
updatedAt DateTime @updatedAt
|
|
77
|
+
|
|
78
|
+
@@index([lastOpenedAt])
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
model ProviderAccount {
|
|
82
|
+
id String @id @default(uuid())
|
|
83
|
+
providerId String
|
|
84
|
+
displayName String
|
|
85
|
+
status ProviderAccountStatus @default(DISCONNECTED)
|
|
86
|
+
settings Json @default("{}")
|
|
87
|
+
runtimeDefaults Json @default("{}")
|
|
88
|
+
authState Json?
|
|
89
|
+
lastAuthUrl String?
|
|
90
|
+
lastAuthMode String?
|
|
91
|
+
lastAuthLoginId String?
|
|
92
|
+
lastAuthUserCode String?
|
|
93
|
+
lastError String?
|
|
94
|
+
createdAt DateTime @default(now())
|
|
95
|
+
updatedAt DateTime @updatedAt
|
|
96
|
+
chats Chat[] @relation("ChatAccount")
|
|
97
|
+
runs ChatRun[] @relation("RunAccount")
|
|
98
|
+
|
|
99
|
+
@@index([providerId])
|
|
100
|
+
@@index([status])
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
model McpServer {
|
|
104
|
+
id String @id @default(uuid())
|
|
105
|
+
name String @unique
|
|
106
|
+
displayName String?
|
|
107
|
+
transport String
|
|
108
|
+
config Json @default("{}")
|
|
109
|
+
enabled Boolean @default(true)
|
|
110
|
+
required Boolean @default(false)
|
|
111
|
+
startupTimeoutSec Float?
|
|
112
|
+
toolTimeoutSec Float?
|
|
113
|
+
toolPolicy Json @default("{}")
|
|
114
|
+
adapterSettings Json @default("{}")
|
|
115
|
+
createdAt DateTime @default(now())
|
|
116
|
+
updatedAt DateTime @updatedAt
|
|
117
|
+
installations McpServerInstallation[]
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
model McpServerInstallation {
|
|
121
|
+
id String @id @default(uuid())
|
|
122
|
+
serverId String
|
|
123
|
+
providerId String
|
|
124
|
+
accountId String
|
|
125
|
+
enabled Boolean @default(true)
|
|
126
|
+
lastSyncAt DateTime?
|
|
127
|
+
lastStatus String?
|
|
128
|
+
lastError String?
|
|
129
|
+
createdAt DateTime @default(now())
|
|
130
|
+
updatedAt DateTime @updatedAt
|
|
131
|
+
server McpServer @relation(fields: [serverId], references: [id], onDelete: Cascade)
|
|
132
|
+
|
|
133
|
+
@@unique([serverId, providerId, accountId])
|
|
134
|
+
@@index([providerId, accountId])
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
model Chat {
|
|
138
|
+
id String @id @default(uuid())
|
|
139
|
+
providerId String
|
|
140
|
+
accountId String?
|
|
141
|
+
autoRotateAccount Boolean @default(false)
|
|
142
|
+
title String
|
|
143
|
+
workingDirectory String?
|
|
144
|
+
model String?
|
|
145
|
+
reasoningEffort String?
|
|
146
|
+
serviceTier String?
|
|
147
|
+
collaborationMode String @default("default")
|
|
148
|
+
permissionMode String @default("default")
|
|
149
|
+
status ChatStatus @default(IDLE)
|
|
150
|
+
externalThreadId String?
|
|
151
|
+
lastActivityAt DateTime @default(now())
|
|
152
|
+
createdAt DateTime @default(now())
|
|
153
|
+
updatedAt DateTime @updatedAt
|
|
154
|
+
account ProviderAccount? @relation("ChatAccount", fields: [accountId], references: [id], onDelete: SetNull)
|
|
155
|
+
runs ChatRun[]
|
|
156
|
+
|
|
157
|
+
@@index([providerId])
|
|
158
|
+
@@index([accountId])
|
|
159
|
+
@@index([updatedAt])
|
|
160
|
+
@@index([lastActivityAt])
|
|
161
|
+
@@index([externalThreadId])
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
model ChatRun {
|
|
165
|
+
id String @id @default(uuid())
|
|
166
|
+
chatId String
|
|
167
|
+
providerId String
|
|
168
|
+
accountId String?
|
|
169
|
+
status RunStatus @default(QUEUED)
|
|
170
|
+
request Json @default("{}")
|
|
171
|
+
error String?
|
|
172
|
+
externalTurnId String?
|
|
173
|
+
interruptRequestedAt DateTime?
|
|
174
|
+
startedAt DateTime?
|
|
175
|
+
endedAt DateTime?
|
|
176
|
+
createdAt DateTime @default(now())
|
|
177
|
+
updatedAt DateTime @updatedAt
|
|
178
|
+
chat Chat @relation(fields: [chatId], references: [id], onDelete: Cascade)
|
|
179
|
+
account ProviderAccount? @relation("RunAccount", fields: [accountId], references: [id], onDelete: SetNull)
|
|
180
|
+
|
|
181
|
+
@@index([chatId, createdAt])
|
|
182
|
+
@@index([providerId])
|
|
183
|
+
@@index([accountId])
|
|
184
|
+
@@index([externalTurnId])
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
model MessageSchedule {
|
|
188
|
+
id String @id @default(uuid())
|
|
189
|
+
title String
|
|
190
|
+
message String
|
|
191
|
+
workingDirectory String
|
|
192
|
+
chatId String?
|
|
193
|
+
providerId String
|
|
194
|
+
accountId String?
|
|
195
|
+
model String?
|
|
196
|
+
reasoningEffort String?
|
|
197
|
+
serviceTier String?
|
|
198
|
+
collaborationMode String @default("default")
|
|
199
|
+
permissionMode String @default("default")
|
|
200
|
+
goalObjective String?
|
|
201
|
+
status MessageScheduleStatus @default(ACTIVE)
|
|
202
|
+
recurrence Json @default("{}")
|
|
203
|
+
nextRunAt DateTime?
|
|
204
|
+
lastRunAt DateTime?
|
|
205
|
+
lastRunStatus String?
|
|
206
|
+
createdAt DateTime @default(now())
|
|
207
|
+
updatedAt DateTime @updatedAt
|
|
208
|
+
runs MessageScheduleRun[]
|
|
209
|
+
|
|
210
|
+
@@index([workingDirectory])
|
|
211
|
+
@@index([status, nextRunAt])
|
|
212
|
+
@@index([chatId])
|
|
213
|
+
@@index([accountId])
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
model MessageScheduleRun {
|
|
217
|
+
id String @id @default(uuid())
|
|
218
|
+
scheduleId String
|
|
219
|
+
chatId String?
|
|
220
|
+
chatRunId String?
|
|
221
|
+
scheduledFor DateTime
|
|
222
|
+
status MessageScheduleRunStatus @default(QUEUED)
|
|
223
|
+
error String?
|
|
224
|
+
startedAt DateTime?
|
|
225
|
+
endedAt DateTime?
|
|
226
|
+
createdAt DateTime @default(now())
|
|
227
|
+
updatedAt DateTime @updatedAt
|
|
228
|
+
schedule MessageSchedule @relation(fields: [scheduleId], references: [id], onDelete: Cascade)
|
|
229
|
+
|
|
230
|
+
@@index([scheduleId, scheduledFor])
|
|
231
|
+
@@index([chatId])
|
|
232
|
+
@@index([chatRunId])
|
|
233
|
+
@@index([status])
|
|
234
|
+
}
|