diff --git a/packages/web/src/app/api/sessions/route.ts b/packages/web/src/app/api/sessions/route.ts index e4a524425..b717cdef2 100644 --- a/packages/web/src/app/api/sessions/route.ts +++ b/packages/web/src/app/api/sessions/route.ts @@ -1,7 +1,28 @@ +import type { Session, ProjectConfig } from "@agent-orchestrator/core"; import { NextResponse } from "next/server"; import { getServices, getSCM, getTracker } from "@/lib/services"; import { sessionToDashboard, enrichSessionPR, enrichSessionIssue, computeStats } from "@/lib/serialize"; +/** Resolve which project a session belongs to. */ +function resolveProject( + core: Session, + projects: Record, +): ProjectConfig | undefined { + // Try explicit projectId first + const direct = projects[core.projectId]; + if (direct) return direct; + + // Match by session prefix + const entry = Object.entries(projects).find(([, p]) => + core.id.startsWith(p.sessionPrefix), + ); + if (entry) return entry[1]; + + // Fall back to first project + const firstKey = Object.keys(projects)[0]; + return firstKey ? projects[firstKey] : undefined; +} + /** GET /api/sessions — List all sessions with full state */ export async function GET() { try { @@ -15,17 +36,7 @@ export async function GET() { // Enrich issue labels using tracker plugin (synchronous) workerSessions.forEach((core, i) => { if (!dashboardSessions[i].issueUrl) return; - let project = config.projects[core.projectId]; - if (!project) { - const entry = Object.entries(config.projects).find(([, p]) => - core.id.startsWith(p.sessionPrefix), - ); - if (entry) project = entry[1]; - } - if (!project) { - const firstKey = Object.keys(config.projects)[0]; - if (firstKey) project = config.projects[firstKey]; - } + const project = resolveProject(core, config.projects); const tracker = getTracker(registry, project); if (!tracker || !project) return; enrichSessionIssue(dashboardSessions[i], tracker, project); @@ -34,18 +45,7 @@ export async function GET() { // Enrich sessions that have PRs with live SCM data (CI, reviews, mergeability) const enrichPromises = workerSessions.map((core, i) => { if (!core.pr) return Promise.resolve(); - // Try explicit projectId, then match by session prefix, then first project - let project = config.projects[core.projectId]; - if (!project) { - const projectEntry = Object.entries(config.projects).find(([, p]) => - core.id.startsWith(p.sessionPrefix), - ); - if (projectEntry) project = projectEntry[1]; - } - if (!project) { - const firstKey = Object.keys(config.projects)[0]; - if (firstKey) project = config.projects[firstKey]; - } + const project = resolveProject(core, config.projects); const scm = getSCM(registry, project); if (!scm) return Promise.resolve(); return enrichSessionPR(dashboardSessions[i], scm, core.pr); diff --git a/packages/web/src/server/terminal-websocket.ts b/packages/web/src/server/terminal-websocket.ts index c2334bd4f..8df2a2d4f 100644 --- a/packages/web/src/server/terminal-websocket.ts +++ b/packages/web/src/server/terminal-websocket.ts @@ -257,7 +257,7 @@ const server = createServer(async (req, res) => { const errorMsg = err instanceof Error ? err.message : String(err); console.error(`[Terminal] Failed to start terminal for ${sessionId}:`, errorMsg); res.writeHead(503, { "Content-Type": "application/json" }); - res.end(JSON.stringify({ error: errorMsg })); + res.end(JSON.stringify({ error: "Failed to start terminal" })); } return; }