feat(agent-api): POST /api/agent/cards/:cardId/subtasks

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
Dave 2026-09-26 09:44:24 +02:00
parent 0e74dbdf14
commit ded7ffbb1f

View file

@ -0,0 +1,68 @@
import { getAdminPb } from "@/lib/pb/admin";
import { requireAgentToken } from "@/lib/agent/auth";
import { positionBetween } from "@/lib/ordering/fractional";
import { jsonError, jsonOk } from "@/lib/http/json";
import type { CardRecord, SubtaskRecord } from "@/lib/pb/types";
/**
* POST /api/agent/cards/:cardId/subtasks — turn a plan into a checklist.
*
* Appends after the card's existing subtasks, in the order given, using the
* same fractional-position spacing every other subtask-creation path in this
* app uses (see addSubtask in src/app/actions/subtasks.ts).
*/
export async function POST(
request: Request,
context: { params: Promise<{ cardId: string }> }
): Promise<Response> {
const denied = requireAgentToken(request);
if (denied) return denied;
const { cardId } = await context.params;
let json: unknown;
try {
json = await request.json();
} catch {
return jsonError("Invalid request body", 400);
}
const titles = (json as { titles?: unknown } | null)?.titles;
if (!Array.isArray(titles)) {
return jsonError("titles must be an array of strings", 400);
}
const cleaned = titles
.filter((t): t is string => typeof t === "string")
.map((t) => t.trim().slice(0, 200))
.filter((t) => t.length > 0);
if (cleaned.length === 0) {
return jsonError("At least one non-empty title is required", 400);
}
const pb = await getAdminPb();
const card = await pb.collection("cards").getOne<CardRecord>(cardId).catch(() => null);
if (!card || card.archived) return jsonError("Card not found", 404);
const last = await pb
.collection("subtasks")
.getFirstListItem<SubtaskRecord>(`card = "${cardId}"`, { sort: "-position" })
.catch(() => null);
let position: number | null = last ? last.position : null;
const created: string[] = [];
for (const title of cleaned) {
position = positionBetween(position, null);
const subtask = await pb.collection("subtasks").create({
card: cardId,
title,
done: false,
position,
});
created.push(subtask.id);
}
return jsonOk({ created }, 201);
}