Files
sproutclaw/.pi/agent/extensions/webui/backend/main.ts
shumengya d51a055d78
Some checks failed
CI / build-check-test (push) Has been cancelled
npm audit / audit (push) Has been cancelled
feat: update webui extensions, models, and agent config
2026-06-10 21:45:53 +08:00

94 lines
2.6 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env node
/**
* pi-mono WebUI Server
*
* 被 webui 扩展启动,作为独立子进程运行。
* 内嵌 HTTP 服务 + pi RPC 子进程,提供浏览器聊天界面。
*
* 用法(由扩展自动调用):
* tsx backend/main.ts --port 19133
*
* 前端静态文件位于 frontend/dist/ 下Vite 构建产物)。
*/
import { existsSync, unlinkSync, writeFileSync } from "node:fs";
import { arch, hostname, platform, release, type } from "node:os";
import { parsePort } from "./config/cli.ts";
import { createWebUiPaths } from "./config/paths.ts";
import { closeWebuiDatabase, initWebuiDatabase } from "./db/index.ts";
import { createWebUiServer } from "./http/server.ts";
import { createPiClient } from "./rpc/pi-client.ts";
import type { WebUiContext } from "./types/context.ts";
const paths = createWebUiPaths();
const port = parsePort();
function writePidFile(): void {
try {
writeFileSync(paths.pidFile, String(process.pid), "utf8");
} catch {
/* ignore */
}
}
function clearPidFile(): void {
try {
if (existsSync(paths.pidFile)) unlinkSync(paths.pidFile);
} catch {
/* ignore */
}
}
function shutdown(exitCode = 0): never {
closeWebuiDatabase();
clearPidFile();
process.exit(exitCode);
}
const webuiDb = initWebuiDatabase(paths.extensionRoot);
console.log(`[webui] 配置数据库: ${webuiDb.dbPath}`);
console.log(`[webui] 运行环境: Node.js ${process.version} | ${type()} ${release()} (${platform()}/${arch()}) | 主机: ${hostname()}`);
process.on("SIGTERM", () => shutdown(0));
process.on("SIGINT", () => shutdown(0));
writePidFile();
const piClient = createPiClient(paths, (code) => {
if (code !== 0 && code !== null) {
console.error(`[webui] pi RPC 进程异常退出 (code=${code})WebUI 即将关闭`);
setTimeout(() => shutdown(1), 500);
return;
}
shutdown(1);
});
const ctx: WebUiContext = {
config: { paths, port },
rpc: {
sendCmd: piClient.sendCmd,
submitPrompt: piClient.submitPrompt,
sendExtensionUiResponse: piClient.sendExtensionUiResponse,
getRunSnapshot: piClient.getRunSnapshot,
connectSseClient: piClient.connectSseClient,
removeSseClient: piClient.removeSseClient,
},
db: webuiDb,
};
const server = createWebUiServer(ctx);
server.on("error", (err: NodeJS.ErrnoException) => {
if (err.code === "EADDRINUSE") {
console.error(`[webui] 端口 ${port} 已被占用`);
} else {
console.error(`[webui] HTTP 服务启动失败: ${err.message}`);
}
process.exit(1);
});
server.listen(port, "0.0.0.0", () => {
console.log(`[webui] HTTP 服务已启动: http://localhost:${port}`);
console.log(`[webui] 局域网访问: http://${hostname()}:${port}`);
});