import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent"; import { spawn, type ChildProcess } from "node:child_process"; import { fileURLToPath } from "node:url"; import { dirname, join } from "node:path"; const __dirname = dirname(fileURLToPath(import.meta.url)); const SERVER_ENTRY = join(__dirname, "..", "server", "index.js"); function openBrowser(url: string) { const platform = process.platform; try { if (platform === "darwin") { spawn("open", [url], { detached: true, stdio: "ignore" }).unref(); } else if (platform === "win32") { spawn("cmd", ["/c", "start", "", url], { detached: true, stdio: "ignore" }).unref(); } else { spawn("xdg-open", [url], { detached: true, stdio: "ignore" }).unref(); } } catch { // 打开浏览器失败不影响服务本身,用户可手动访问 url } } export default function (pi: ExtensionAPI) { let proc: ChildProcess | null = null; let url = ""; function stop(ctx: ExtensionContext) { if (!proc) return; proc.kill(); proc = null; ctx.ui.notify("Pi Web Console 已停止", "info"); } pi.registerCommand("web-console", { description: "启动/停止 Pi Web Console(本会话的浏览器 UI)。用法:/web-console [port|stop]", handler: async (args, ctx) => { const arg = args.trim(); if (arg === "stop") { stop(ctx); return; } if (proc) { ctx.ui.notify(`Pi Web Console 已在运行:${url}`, "info"); openBrowser(url); return; } const port = /^\d+$/.test(arg) ? arg : process.env.PI_WEB_CONSOLE_PORT || "4120"; const host = process.env.PI_WEB_CONSOLE_HOST || "127.0.0.1"; proc = spawn(process.execPath, [SERVER_ENTRY], { cwd: ctx.cwd, env: { ...process.env, HOST: host, PORT: port, DEFAULT_CWD: ctx.cwd, }, stdio: "ignore", }); proc.on("exit", () => { proc = null; }); url = `http://${host}:${port}`; ctx.ui.notify(`Pi Web Console 启动中:${url}`, "info"); openBrowser(url); }, }); pi.on("session_shutdown", async (_event, ctx) => { stop(ctx); }); }