import type { IncomingMessage, ServerResponse } from 'node:http'; import type { ProjectType } from '../../../shared/project-config'; import type { HostApiContext } from '../context'; import { parseJsonBody, sendJson, sendNoContent } from '../route-utils'; import { sendCodingRouteError } from './coding-route-errors'; function isProjectRoute(pathname: string): boolean { return pathname === '/api/coding/projects' || pathname.startsWith('/api/coding/projects/'); } export async function handleCodingProjectRoutes( req: IncomingMessage, res: ServerResponse, url: URL, ctx: HostApiContext, ): Promise { if (!isProjectRoute(url.pathname)) return false; const projects = ctx.codingProducts?.projects; const conversations = ctx.codingProducts?.conversations; if (!projects || !conversations) { sendJson(res, 503, { success: false, code: 'CODING_CORE_UNAVAILABLE', error: 'Coding services are unavailable', }); return true; } try { if (url.pathname === '/api/coding/projects' && req.method === 'GET') { const [items, activeProject] = await Promise.all([ projects.listProjects(), projects.getActiveProject(), ]); sendJson(res, 200, { projects: items, activeProjectId: activeProject?.id ?? null }); return true; } if (url.pathname === '/api/coding/projects/open' && req.method === 'POST') { const body = await parseJsonBody<{ projectPath?: string }>(req); sendJson(res, 200, { project: await projects.openProject(body.projectPath ?? '') }); return true; } if (url.pathname === '/api/coding/projects/create' && req.method === 'POST') { const body = await parseJsonBody<{ projectPath?: string; parentPath?: string; projectName?: string; projectType?: ProjectType; }>(req); sendJson(res, 201, { snapshot: await projects.createProject(body) }); return true; } if (url.pathname === '/api/coding/projects/remove' && req.method === 'POST') { const body = await parseJsonBody<{ projectId?: string }>(req); await projects.removeProject(body.projectId ?? ''); sendNoContent(res); return true; } if (url.pathname === '/api/coding/projects/active' && req.method === 'GET') { sendJson(res, 200, { project: await projects.getActiveProject() }); return true; } if (url.pathname === '/api/coding/projects/active' && req.method === 'POST') { const body = await parseJsonBody<{ projectId?: string }>(req); sendJson(res, 200, { project: await projects.setActiveProject(body.projectId ?? '') }); return true; } if (url.pathname === '/api/coding/projects/config' && req.method === 'GET') { sendJson(res, 200, { snapshot: await projects.getConfig(url.searchParams.get('projectId')?.trim() || undefined), }); return true; } if (url.pathname === '/api/coding/projects/config' && req.method === 'PUT') { const body = await parseJsonBody<{ projectId?: string; config?: unknown }>(req); sendJson(res, 200, { snapshot: await projects.saveConfig(body.projectId ?? '', body.config), }); return true; } if (url.pathname === '/api/coding/projects/knowledge' && req.method === 'POST') { const body = await parseJsonBody<{ projectId?: string; fileName?: string; contentBase64?: string; }>(req); sendJson(res, 201, { knowledgeFiles: await projects.addKnowledgeFile({ projectId: body.projectId ?? '', fileName: body.fileName ?? '', contentBase64: body.contentBase64 ?? '', }), }); return true; } if (url.pathname === '/api/coding/projects/conversations' && req.method === 'GET') { sendJson(res, 200, { conversations: await conversations.listConversations( url.searchParams.get('projectId')?.trim() || undefined, ), }); return true; } if (url.pathname === '/api/coding/projects/conversations' && req.method === 'POST') { const body = await parseJsonBody<{ projectId?: string; agentId?: unknown; title?: unknown }>(req); sendJson(res, 201, { conversation: await conversations.createConversation(body) }); return true; } } catch (error) { sendCodingRouteError(res, error); return true; } return false; }