Add Claude observability tracing and diagnostics UI

This commit is contained in:
2026-02-24 12:50:31 -05:00
parent 6863c1da0b
commit 691591d279
22 changed files with 1898 additions and 32 deletions

View File

@@ -6,6 +6,7 @@ import { buildSessionGraphInsight, buildSessionSummaries } from "./session-insig
import { UiConfigStore, type LimitSettings, type RuntimeNotificationSettings, type SecurityPolicySettings } from "./config-store.js";
import { ManifestStore } from "./manifest-store.js";
import { filterRuntimeEvents, readRuntimeEvents } from "./runtime-events-store.js";
import { filterClaudeTraceEvents, readClaudeTraceEvents } from "./claude-trace-store.js";
import { parseJsonBody, sendJson, methodNotAllowed, notFound, serveStaticFile } from "./http-utils.js";
import { readRunMetaBySession, UiRunService, type RunExecutionMode } from "./run-service.js";
import type { RunProvider } from "./provider-executor.js";
@@ -120,11 +121,13 @@ function ensureNonEmptyString(value: unknown, field: string): string {
async function readRuntimePaths(configStore: UiConfigStore, workspaceRoot: string): Promise<{
stateRoot: string;
runtimeEventLogPath: string;
claudeTraceLogPath: string;
}> {
const snapshot = await configStore.readSnapshot();
return {
stateRoot: resolve(workspaceRoot, snapshot.paths.stateRoot),
runtimeEventLogPath: resolve(workspaceRoot, snapshot.paths.runtimeEventLogPath),
claudeTraceLogPath: resolve(workspaceRoot, snapshot.paths.claudeTraceLogPath),
};
}
@@ -313,6 +316,27 @@ async function handleApiRequest(input: {
return true;
}
if (pathname === "/api/claude-trace") {
if (method !== "GET") {
methodNotAllowed(response);
return true;
}
const { claudeTraceLogPath } = await readRuntimePaths(configStore, workspaceRoot);
const limit = parseLimit(requestUrl.searchParams.get("limit"), 200);
const sessionId = requestUrl.searchParams.get("sessionId") ?? undefined;
const events = filterClaudeTraceEvents(await readClaudeTraceEvents(claudeTraceLogPath), {
...(sessionId ? { sessionId } : {}),
limit,
});
sendJson(response, 200, {
ok: true,
events,
});
return true;
}
if (pathname === "/api/sessions") {
if (method === "POST") {
const body = await parseJsonBody<CreateSessionRequest>(request);