feat(agent-api): GET /api/agent/cards/:cardId

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
Dave 2026-09-26 09:37:19 +02:00
parent 9b6c031e60
commit a297fe5f15

View file

@ -0,0 +1,88 @@
import { getAdminPb } from "@/lib/pb/admin";
import { requireAgentToken } from "@/lib/agent/auth";
import { jsonError, jsonOk } from "@/lib/http/json";
import type {
CardRecord,
ColumnRecord,
CommentRecord,
CommitRecord,
SubtaskRecord,
UserRecord,
} from "@/lib/pb/types";
/**
* GET /api/agent/cards/:cardId — one card's full detail: everything the list
* endpoint returns, plus its existing checklist, existing comments (with
* author names resolved), and its 10 most recent linked commits — enough for
* an agent to know what has already touched this card before drafting a plan
* for it, without pulling full commit history.
*/
export async function GET(
request: Request,
context: { params: Promise<{ cardId: string }> }
): Promise<Response> {
const denied = requireAgentToken(request);
if (denied) return denied;
const { cardId } = await context.params;
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 column = await pb
.collection("columns")
.getOne<ColumnRecord>(card.column)
.catch(() => null);
const subtasks = await pb.collection("subtasks").getFullList<SubtaskRecord>({
filter: `card = "${cardId}"`,
sort: "position",
});
const comments = await pb.collection("comments").getFullList<CommentRecord>({
filter: `card = "${cardId}"`,
sort: "created",
});
const userIds = new Set(comments.map((c) => c.author).filter(Boolean));
const names: Record<string, string> = {};
for (const id of userIds) {
const user = await pb.collection("users").getOne<UserRecord>(id).catch(() => null);
names[id] = user?.name || user?.email || "Someone";
}
const recentCommits = await pb.collection("commits").getList<CommitRecord>(1, 10, {
filter: `card = "${cardId}" && is_merge = false`,
sort: "-authored_at",
});
return jsonOk({
id: card.id,
number: card.number,
title: card.title,
description: card.description,
priority: card.priority,
target_date: card.target_date,
size_band: card.size_band,
column: column
? {
id: column.id,
name: column.name,
is_inbox: column.is_inbox,
is_done: column.is_done,
}
: null,
subtasks: subtasks.map((s) => ({ id: s.id, title: s.title, done: s.done })),
comments: comments.map((c) => ({
id: c.id,
author: names[c.author] ?? "Someone",
body: c.body,
created: c.created,
})),
recentCommits: recentCommits.items.map((commit) => ({
summary: commit.summary || commit.subject,
authored_at: commit.authored_at,
})),
});
}