diff --git a/src/app/api/agent/cards/[cardId]/comments/route.ts b/src/app/api/agent/cards/[cardId]/comments/route.ts new file mode 100644 index 0000000..3b755b8 --- /dev/null +++ b/src/app/api/agent/cards/[cardId]/comments/route.ts @@ -0,0 +1,55 @@ +import { getAdminPb } from "@/lib/pb/admin"; +import { requireAgentToken } from "@/lib/agent/auth"; +import { getOwnerUser } from "@/lib/agent/owner"; +import { jsonError, jsonOk } from "@/lib/http/json"; +import type { CardRecord } from "@/lib/pb/types"; + +/** Matches the comments collection's own `body` field limit. */ +const MAX_BODY_LENGTH = 20000; + +/** + * POST /api/agent/cards/:cardId/comments — post a drafted plan as a comment. + * + * The stored body is always prefixed before being written, so no caller can + * accidentally or deliberately post something indistinguishable from the + * owner's own words. This prefix is the one thing this whole feature exists + * to guarantee — do not make it conditional or configurable. + */ +export async function POST( + request: Request, + context: { params: Promise<{ cardId: string }> } +): Promise { + 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 body = (json as { body?: unknown } | null)?.body; + if (typeof body !== "string" || !body.trim()) { + return jsonError("A non-empty body is required", 400); + } + + const pb = await getAdminPb(); + const card = await pb.collection("cards").getOne(cardId).catch(() => null); + if (!card || card.archived) return jsonError("Card not found", 404); + + const owner = await getOwnerUser(); + + const prefix = "🤖 Drafted by your agent:\n\n"; + const trimmed = body.trim().slice(0, MAX_BODY_LENGTH - prefix.length); + + const comment = await pb.collection("comments").create({ + card: cardId, + author: owner.id, + body: `${prefix}${trimmed}`, + }); + + return jsonOk({ id: comment.id }, 201); +}