import { existsSync } from "node:fs"; import { dirname, join, resolve } from "node:path"; import { fileURLToPath } from "node:url"; const configDir = dirname(fileURLToPath(import.meta.url)); const backendDir = dirname(configDir); const extensionRoot = resolve(backendDir, ".."); export interface WebUiPaths { extensionRoot: string; repoRoot: string; agentDir: string; publicDir: string; pidFile: string; sessionsDir: string; agentExtensionsDir: string; agentNpmNodeModules: string; agentSettingsFile: string; systemPromptFile: string; modelsConfigFile: string; mcpCacheFile: string; mcpConfigFile: string; piCliDist: string; } export function createWebUiPaths(): WebUiPaths { const repoRoot = process.cwd(); const agentDir = resolve(process.env.PI_CODING_AGENT_DIR || join(repoRoot, ".pi", "agent")); return { extensionRoot, repoRoot, agentDir, publicDir: join(extensionRoot, "frontend", "dist"), pidFile: join(extensionRoot, ".webui.pid"), sessionsDir: join(agentDir, "sessions"), agentExtensionsDir: join(agentDir, "extensions"), agentNpmNodeModules: join(agentDir, "npm", "node_modules"), agentSettingsFile: join(agentDir, "settings.json"), systemPromptFile: join(agentDir, "AGENTS.md"), modelsConfigFile: join(agentDir, "models.json"), mcpCacheFile: join(agentDir, "mcp-cache.json"), mcpConfigFile: join(agentDir, "mcp.json"), piCliDist: join(repoRoot, "packages", "coding-agent", "dist", "cli.js"), }; } export type PiRpcLaunchMode = "dist" | "tsx"; export function resolvePiRpcLaunch( paths: WebUiPaths, ): { command: string; args: string[]; mode: PiRpcLaunchMode } { const rpcArgs = ["--mode", "rpc"]; if (existsSync(paths.piCliDist)) { return { command: process.execPath, args: [paths.piCliDist, ...rpcArgs], mode: "dist" }; } const tsxCli = join(paths.repoRoot, "node_modules", "tsx", "dist", "cli.mjs"); const piCliSrc = join(paths.repoRoot, "packages", "coding-agent", "src", "cli.ts"); if (existsSync(tsxCli) && existsSync(piCliSrc)) { return { command: process.execPath, args: [tsxCli, piCliSrc, ...rpcArgs], mode: "tsx" }; } const buildHint = process.platform === "win32" ? "请先运行: npm run build 或 pi-built.bat" : "请先运行: npm run build 或 sproutclaw build"; throw new Error(`[webui] pi 未找到: ${paths.piCliDist}。${buildHint}`); }