3ed38c65ec
Adds `uncaged-workflow serve` command that exposes workflow data via a local HTTP API for the upcoming Web UI (RFC #118 Phase 1). Routes: - GET /healthz — health check - GET /api/workflows — list registered workflows - GET /api/workflows/:name — show workflow details - GET /api/workflows/:name/history — version history - GET /api/threads — list threads (optional ?workflow= filter) - GET /api/threads/running — list running threads - GET /api/threads/:id — show thread records (parsed JSONL) - GET /api/cas — list CAS hashes - GET /api/cas/:hash — get CAS content - POST /api/cas — store content, returns hash - DELETE /api/cas/:hash — remove CAS entry - POST /api/cas/gc — garbage collect Default: 127.0.0.1:7860, configurable via --port/-p and --host. Refs: #118
47 lines
1.3 KiB
TypeScript
47 lines
1.3 KiB
TypeScript
import { Hono } from "hono";
|
|
|
|
import { readTextFileIfExists } from "../../fs-utils.js";
|
|
import {
|
|
listHistoricalThreads,
|
|
listRunningThreads,
|
|
resolveThreadDataPath,
|
|
} from "../../thread-scan.js";
|
|
|
|
export function createThreadRoutes(storageRoot: string): Hono {
|
|
const app = new Hono();
|
|
|
|
app.get("/", async (c) => {
|
|
const nameFilter = c.req.query("workflow") ?? null;
|
|
const rows = await listHistoricalThreads(storageRoot, nameFilter);
|
|
return c.json({ threads: rows });
|
|
});
|
|
|
|
app.get("/running", async (c) => {
|
|
const rows = await listRunningThreads(storageRoot);
|
|
return c.json({ threads: rows });
|
|
});
|
|
|
|
app.get("/:threadId", async (c) => {
|
|
const threadId = c.req.param("threadId");
|
|
const dataPath = await resolveThreadDataPath(storageRoot, threadId);
|
|
if (dataPath === null) {
|
|
return c.json({ error: `thread not found: ${threadId}` }, 404);
|
|
}
|
|
const text = await readTextFileIfExists(dataPath);
|
|
if (text === null) {
|
|
return c.json({ error: `thread data missing: ${threadId}` }, 404);
|
|
}
|
|
const lines = text.trim().split("\n");
|
|
const records = lines.map((line) => {
|
|
try {
|
|
return JSON.parse(line) as unknown;
|
|
} catch {
|
|
return { raw: line };
|
|
}
|
|
});
|
|
return c.json({ threadId, records });
|
|
});
|
|
|
|
return app;
|
|
}
|