feat(rails): GET /api/sub-tasks/:id — node detail with parents/events
This commit is contained in:
0
sister-agent/.claude/state/session-events.lock
Normal file
0
sister-agent/.claude/state/session-events.lock
Normal file
0
sister-agent/.claude/state/session.events.jsonl
Normal file
0
sister-agent/.claude/state/session.events.jsonl
Normal file
0
sister-agent/.claude/state/session.json
Normal file
0
sister-agent/.claude/state/session.json
Normal file
@@ -127,6 +127,74 @@ export async function recordSubTaskEvent(
|
||||
}
|
||||
}
|
||||
|
||||
function tryParseJson(s: string): unknown {
|
||||
try {
|
||||
return JSON.parse(s);
|
||||
} catch {
|
||||
return s;
|
||||
}
|
||||
}
|
||||
|
||||
export async function getSubTaskDetail(id: string): Promise<unknown | null> {
|
||||
const prisma = getPrisma();
|
||||
const node = await prisma.subTask.findUnique({
|
||||
where: { id },
|
||||
include: {
|
||||
events: {
|
||||
orderBy: { timestamp: "asc" },
|
||||
select: {
|
||||
id: true,
|
||||
eventType: true,
|
||||
payloadJson: true,
|
||||
timestamp: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
if (!node) return null;
|
||||
|
||||
// Walk up parent chain
|
||||
const parents: Array<{ id: string; role: string; title: string }> = [];
|
||||
let cursor: string | null = node.parentId;
|
||||
while (cursor) {
|
||||
const p = await prisma.subTask.findUnique({
|
||||
where: { id: cursor },
|
||||
select: { id: true, parentId: true, role: true, title: true },
|
||||
});
|
||||
if (!p) break;
|
||||
parents.unshift({ id: p.id, role: p.role, title: p.title });
|
||||
cursor = p.parentId;
|
||||
}
|
||||
|
||||
// Direct children list
|
||||
const children = await prisma.subTask.findMany({
|
||||
where: { parentId: id },
|
||||
orderBy: { createdAt: "asc" },
|
||||
select: {
|
||||
id: true,
|
||||
role: true,
|
||||
agentName: true,
|
||||
title: true,
|
||||
state: true,
|
||||
model: true,
|
||||
startedAt: true,
|
||||
completedAt: true,
|
||||
},
|
||||
});
|
||||
|
||||
return {
|
||||
...node,
|
||||
parents,
|
||||
childrenList: children,
|
||||
events: node.events.map((e) => ({
|
||||
id: e.id,
|
||||
eventType: e.eventType,
|
||||
payload: tryParseJson(e.payloadJson),
|
||||
timestamp: e.timestamp,
|
||||
})),
|
||||
};
|
||||
}
|
||||
|
||||
export async function getSubTaskTree(pipelineId: string): Promise<unknown> {
|
||||
const prisma = getPrisma();
|
||||
const all = await prisma.subTask.findMany({
|
||||
|
||||
@@ -18,6 +18,7 @@ import {
|
||||
recordSubTaskEvent,
|
||||
updateSubTask,
|
||||
getSubTaskTree,
|
||||
getSubTaskDetail,
|
||||
} from "../hierarchy/store.js";
|
||||
import { childLogger } from "../logger.js";
|
||||
|
||||
@@ -191,6 +192,15 @@ export async function startHttpServer(opts: ServerOpts): Promise<{
|
||||
return sendJson(res, 200, { pipelineId: pid, tree });
|
||||
}
|
||||
|
||||
// ── Single sub-task detail ──
|
||||
const detailMatch = path.match(/^\/api\/sub-tasks\/([^/]+)$/);
|
||||
if (method === "GET" && detailMatch) {
|
||||
const id = detailMatch[1]!;
|
||||
const detail = await getSubTaskDetail(id);
|
||||
if (!detail) return sendJson(res, 404, { error: "not_found" });
|
||||
return sendJson(res, 200, detail);
|
||||
}
|
||||
|
||||
return sendJson(res, 404, { error: "not_found", path });
|
||||
} catch (err) {
|
||||
log.error(
|
||||
|
||||
Reference in New Issue
Block a user