import { existsSync, mkdirSync, readFileSync, statSync, writeFileSync, } from "node:fs"; import { homedir } from "node:os"; import { dirname, resolve } from "node:path"; import { webPreferencesPath } from "../../../../src/app-paths.ts"; import { discoverProjects } from "../../../../src/web/project-discovery-service.ts"; export const runtime = "nodejs"; export const dynamic = "force-dynamic"; /** Shape of persisted web preferences. */ interface WebPreferences { devRoot?: string; lastActiveProject?: string; } /** Expand leading `~/` to the user's home directory. */ function expandTilde(p: string): string { if (p === "~") return homedir(); if (p.startsWith("~/")) return homedir() + p.slice(1); return p; } /** * POST /api/switch-root * * Validates the new root path, persists it as the `devRoot` preference, * and returns the discovered projects under the new root. * * Request body: { "devRoot": "/absolute/path" } * Response: { "devRoot": "/resolved/path", "projects": [...] } */ export async function POST(request: Request): Promise { try { const body = (await request.json()) as Record; const rawDevRoot = typeof body.devRoot === "string" ? body.devRoot.trim() : ""; if (!rawDevRoot) { return Response.json( { error: "Missing devRoot in request body" }, { status: 400 }, ); } const expanded = expandTilde(rawDevRoot); const resolved = resolve(expanded); // Validate: path must exist if (!existsSync(resolved)) { return Response.json( { error: `Path does not exist: ${resolved}` }, { status: 400 }, ); } // Validate: path must be a directory try { const stat = statSync(resolved); if (!stat.isDirectory()) { return Response.json( { error: `Not a directory: ${resolved}` }, { status: 400 }, ); } } catch { return Response.json( { error: `Cannot access path: ${resolved}` }, { status: 400 }, ); } // Read existing preferences and merge let existing: WebPreferences = {}; try { if (existsSync(webPreferencesPath)) { existing = JSON.parse(readFileSync(webPreferencesPath, "utf-8")); } } catch { // Corrupt file — start fresh } const prefs: WebPreferences = { ...existing, devRoot: resolved, // Clear last active project since we're changing the root lastActiveProject: undefined, }; // Ensure parent directory exists const dir = dirname(webPreferencesPath); if (!existsSync(dir)) { mkdirSync(dir, { recursive: true }); } writeFileSync(webPreferencesPath, JSON.stringify(prefs, null, 2), "utf-8"); // Discover projects under the new root const projects = discoverProjects(resolved, true); return Response.json({ devRoot: resolved, projects, }); } catch (err) { return Response.json( { error: `Failed to switch root: ${err instanceof Error ? err.message : String(err)}`, }, { status: 500 }, ); } }