import { NextRequest, NextResponse } from "next/server"; import { requireRequestSession } from "@/lib/boss-auth"; import { appendProjectMessage, buildCollaborationGate, readState } from "@/lib/boss-data"; import { canAccessProject } from "@/lib/boss-permissions"; import { queueThreadForkTask, ThreadConversationExecutionConflictError, } from "@/lib/boss-master-agent"; function forbiddenResponse(message = "FORBIDDEN") { return NextResponse.json({ ok: false, message }, { status: 403 }); } function normalizeReason(value: unknown) { const trimmed = String(value ?? "").trim(); return trimmed ? trimmed : undefined; } export async function POST( request: NextRequest, context: { params: Promise<{ projectId: string }> }, ) { const session = await requireRequestSession(request); if (!session) { return NextResponse.json({ ok: false, message: "UNAUTHORIZED" }, { status: 401 }); } const { projectId } = await context.params; const body = (await request.json().catch(() => ({}))) as { reason?: unknown; ephemeral?: unknown; }; const reason = normalizeReason(body.reason); const ephemeral = body.ephemeral === true; const state = await readState(); const projectExists = state.projects.some((project) => project.id === projectId); if (!canAccessProject(state, session, projectId, "project.view")) { return forbiddenResponse(projectExists ? "FORBIDDEN" : "PROJECT_NOT_FOUND"); } if (!canAccessProject(state, session, projectId, "master_agent.ask")) { return forbiddenResponse("MASTER_AGENT_FORBIDDEN"); } try { const message = await appendProjectMessage({ projectId, account: session.account, senderLabel: session.displayName || "你", body: reason || "分叉当前 Codex 线程。", kind: "text", }); const task = await queueThreadForkTask({ projectId, requestMessageId: message.id, ephemeral, reason, requestedBy: session.displayName || session.account, requestedByAccount: session.account, }); const nextState = await readState(); const project = nextState.projects.find((item) => item.id === projectId); return NextResponse.json({ ok: true, message, task, collaborationGate: buildCollaborationGate(project), }); } catch (error) { if (error instanceof ThreadConversationExecutionConflictError) { return NextResponse.json( { ok: false, code: error.message, message: "THREAD_EXECUTION_CONFLICT", executionConflict: error.conflict, }, { status: 409 }, ); } return NextResponse.json( { ok: false, message: error instanceof Error ? error.message : "UNKNOWN_ERROR" }, { status: 400 }, ); } }