feat: Add transcript-debug page with multi-agent support, hooks approval, and message selection

- Transcript debug: JSONL viewer, parsed chat view, realtime WebSocket updates, session selector
- Multi-agent: ejecutor, nucleo000, and claude (global ~/.claude/projects/) with agent switcher
- Hooks approval: permission/plan request forwarding via PowerShell hooks, long-poll API, UI modals
- Chat features: session ID copy, select mode with checkboxes, multi-select copy, select all/deselect all
- File watchers for all agent transcript directories with polling fallback on Windows
This commit is contained in:
2026-02-18 23:55:09 -06:00
parent d0fdd04132
commit 9bd6123f97
37 changed files with 5663 additions and 30 deletions

View File

@@ -22,6 +22,12 @@ import {
handleAgentsConfigPermissions, handleAgentsConfigHooks, handleAgentsConfigMcp
} from './agents'
import { handleTranscript, handleTranscriptSessions, handleTranscriptActive, handleClaudeStats, handleClaudeUsage } from './transcript'
import { handleTranscriptDebugSessions, handleTranscriptDebugRaw, handleTranscriptDebugSend, handleTranscriptDebugStatus } from './transcript-debug'
import {
handleHooksApprovalPermission, handleHooksApprovalPlan,
handleHooksApprovalRespond, handleHooksApprovalRespondPlan,
handleHooksApprovalList
} from './hooks-approval'
export async function handleRequest(req: Request): Promise<Response> {
const url = new URL(req.url)
@@ -319,6 +325,52 @@ export async function handleRequest(req: Request): Promise<Response> {
return handleTranscript(req, url, transcriptMatch[1])
}
// Transcript Debug
if (path === '/api/transcript-debug/sessions' && req.method === 'GET') {
return handleTranscriptDebugSessions(url)
}
if (path === '/api/transcript-debug/send' && req.method === 'POST') {
return handleTranscriptDebugSend(req)
}
if (path === '/api/transcript-debug/status' && req.method === 'GET') {
return handleTranscriptDebugStatus(url)
}
const transcriptDebugRawMatch = path.match(/^\/api\/transcript-debug\/([a-f0-9-]+)\/raw$/)
if (transcriptDebugRawMatch && req.method === 'GET') {
return handleTranscriptDebugRaw(transcriptDebugRawMatch[1], url)
}
// Hooks Approval (long-poll for permission/plan decisions)
if (path === '/api/hooks-approval') {
if (req.method === 'GET') {
const res = await handleHooksApprovalList(req)
if (res) return res
}
}
if (path === '/api/hooks-approval/permission' && req.method === 'POST') {
const res = await handleHooksApprovalPermission(req)
if (res) return res
}
if (path === '/api/hooks-approval/plan' && req.method === 'POST') {
const res = await handleHooksApprovalPlan(req)
if (res) return res
}
if (path === '/api/hooks-approval/respond' && req.method === 'POST') {
const res = await handleHooksApprovalRespond(req)
if (res) return res
}
if (path === '/api/hooks-approval/respond-plan' && req.method === 'POST') {
const res = await handleHooksApprovalRespondPlan(req)
if (res) return res
}
// Agents
if (path === '/api/agents' && req.method === 'GET') {
return handleAgents(req)