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 function resolvePiRpcLaunch(paths: WebUiPaths): { command: string; args: string[]; mode: "dist" } { const rpcArgs = ["--mode", "rpc"]; if (!existsSync(paths.piCliDist)) { throw new Error( `[webui] 构建版 sproutclaw 未找到: ${paths.piCliDist}。请先运行: sproutclaw build`, ); } return { command: process.execPath, args: [paths.piCliDist, ...rpcArgs], mode: "dist" }; }