beadboard/src/app/api/runtime/launch/route.ts
zenchantlive d335e5bf71 fix: orchestrator button + Pi SDK session error
- Move leftSidebarMode from URL state to local useState in unified-shell,
    avoiding force-dynamic router round-trip that made the button appear broken                                           - Replace fileURLToPath(new URL(..., import.meta.url)) with process.cwd()
    in bb-pi-bootstrap.ts — import.meta.url is a webpack:// URL in Next.js,
    causing cross-realm TypeError when passed to Node.js fileURLToPath()
2026-03-24 19:02:04 -05:00

55 lines
2 KiB
TypeScript

import { NextResponse } from 'next/server';
import { bbDaemon } from '../../../../lib/bb-daemon';
import type { LaunchSurface } from '../../../../lib/embedded-runtime';
import type { readIssuesFromDisk as ReadIssuesFromDisk } from '../../../../lib/read-issues';
export const dynamic = 'force-dynamic';
interface LaunchDeps {
readIssues?: typeof ReadIssuesFromDisk;
}
function isLaunchSurface(value: string): value is LaunchSurface {
return ['social', 'graph', 'swarm', 'sessions', 'activity', 'task'].includes(value);
}
export async function handleRuntimeLaunchPost(request: Request, deps: LaunchDeps = {}): Promise<Response> {
try {
const body = await request.json();
const projectRoot = typeof body?.projectRoot === 'string' ? body.projectRoot.trim() : '';
const taskId = typeof body?.taskId === 'string' ? body.taskId.trim() : '';
const origin = typeof body?.origin === 'string' && isLaunchSurface(body.origin) ? body.origin : null;
const swarmId = typeof body?.swarmId === 'string' ? body.swarmId : null;
if (!projectRoot || !taskId || !origin) {
return NextResponse.json({ ok: false, error: 'projectRoot, taskId, and origin are required' }, { status: 400 });
}
const read = deps.readIssues ?? (await import('../../../../lib/read-issues')).readIssuesFromDisk;
const issues = await read({ projectRoot, preferBd: true });
const issue = issues.find((entry) => entry.id === taskId);
if (!issue) {
return NextResponse.json({ ok: false, error: 'task not found' }, { status: 404 });
}
const lifecycle = await bbDaemon.ensureRunning();
const result = await bbDaemon.launchFromIssue({
projectRoot,
issue,
origin,
swarmId,
});
return NextResponse.json({ ok: true, lifecycle, data: result });
} catch (error) {
return NextResponse.json(
{ ok: false, error: error instanceof Error ? error.message : 'Invalid request' },
{ status: 400 },
);
}
}
export async function POST(request: Request): Promise<Response> {
return handleRuntimeLaunchPost(request);
}