/** * claude-code.ts — WatcherAdapter para Claude Code * * Claude Code escribe trazas JSONL en ~/.claude/projects/{hash}/{session-id}.jsonl * Cada línea "assistant" contiene usage tokens y modelo. */ import { type WatcherAdapter } from './adapter'; import type { BlockCostEntry } from '../db'; export declare const claudeCodeAdapter: WatcherAdapter; export interface AssistantTurn { turn_index: number; ts?: number; text_preview: string; tool_calls: string[]; error_count: number; output_chars: number; context_used: number; model?: string; effort?: string; stop_reason?: string; stop_sequence?: string; turnEnd?: boolean; } export interface SemanticData { turns: AssistantTurn[]; avg_output_chars: number; error_block_count: number; } export declare function findJSONLForSession(sessionId: string): Promise; export declare function extractSemanticData(filePath: string): Promise; export declare function getAllBlockCostsForSession(sessionId: string): Promise; export interface SessionPrompt { index: number; ts: number; text: string; } /** * Calcula los Stops sintéticos pendientes para una sesión de Claude Code. * * Problema que resuelve: Claude Code emite un hook `Stop` real ~1 vez por respuesta * completa al usuario, pero un mismo turno JSONL (`AssistantTurn`) se genera por cada * llamada a herramienta intermedia (Bash, Grep, Read...), no solo al final. Sintetizar * un Stop entre *cada* turno agrupaba erróneamente un bloque de ejecución por * herramienta individual en vez de por respuesta completa. OpenCode, en cambio, * sintetiza un `Stop` por turno de usuario y se ve "correcto". * * Aquí se generan Stops sintéticos solo para los turnos marcados `turnEnd` (el último * turno antes de un prompt real del usuario — mismo criterio que * getAllBlockCostsForSession()) cuyo límite NO esté ya cubierto por un Stop real del * hook (dedupe por límite: un Stop real con ts en [turno[i].ts, turno[i+1].ts) cierra * ese límite). Los Stops sintéticos solo viajan por SSE / polling del dashboard — * nunca se insertan en la base de datos — para no contaminar métricas de sesión. * * Determinista: misma entrada → misma salida (usado en events.ts y misc.ts). */ export declare function syntheticStopsFor(sessionId: string, turns: AssistantTurn[], realStopTs: number[]): Array<{ type: 'Stop'; session_id: string; ts: number; synthetic: true; }>; export declare function getSessionPrompts(sessionId: string): Promise;