From e18a1ef2f7e68bb9ef3f382d3ee95a8c908579d4 Mon Sep 17 00:00:00 2001 From: iamtoruk Date: Mon, 20 Apr 2026 15:52:18 -0700 Subject: [PATCH] fix: tighten types, remove dead exports, prevent FD leak --- src/discovery-cache.ts | 4 +--- src/fs-utils.ts | 2 ++ src/parse-progress.ts | 3 ++- src/parser.ts | 16 ++++++++-------- src/source-cache.ts | 26 ++++++++++++-------------- 5 files changed, 25 insertions(+), 26 deletions(-) diff --git a/src/discovery-cache.ts b/src/discovery-cache.ts index fcd9e4e..54fae29 100644 --- a/src/discovery-cache.ts +++ b/src/discovery-cache.ts @@ -143,9 +143,7 @@ async function atomicWriteJson(path: string, value: unknown): Promise { } catch (err) { try { await unlink(temp) - } catch { - // ignore cleanup failures - } + } catch {} throw err } } diff --git a/src/fs-utils.ts b/src/fs-utils.ts index bf25c50..b54dba0 100644 --- a/src/fs-utils.ts +++ b/src/fs-utils.ts @@ -117,5 +117,7 @@ export async function* readSessionLinesFromOffset(filePath: string, startOffset: for await (const line of rl) yield line } catch (err) { warn(`stream read failed for ${filePath}: ${(err as NodeJS.ErrnoException).code ?? 'unknown'}`) + } finally { + stream.destroy() } } diff --git a/src/parse-progress.ts b/src/parse-progress.ts index 3acb068..7d81c11 100644 --- a/src/parse-progress.ts +++ b/src/parse-progress.ts @@ -1,6 +1,7 @@ -import { Chalk } from 'chalk' import { stripVTControlCharacters } from 'node:util' +import { Chalk } from 'chalk' + import type { SourceProgressReporter } from './parser.js' import { providerColor, providerLabel } from './provider-colors.js' diff --git a/src/parser.ts b/src/parser.ts index e39872e..3a0eb77 100644 --- a/src/parser.ts +++ b/src/parser.ts @@ -655,19 +655,19 @@ async function evaluateSourceManifestState( if (!manifestEntry) { const state: SourceManifestState = { source, parserVersion, manifestEntry, action: 'refresh', reason: 'missing-entry' } - logCacheDebug(source.provider, source.path, state.reason) + logCacheDebug(source.provider, source.path, state.reason!) return state } if (manifestEntry.lastSeenParserVersion !== parserVersion) { const state: SourceManifestState = { source, parserVersion, manifestEntry, action: 'refresh', reason: 'parser-version' } - logCacheDebug(source.provider, source.path, state.reason) + logCacheDebug(source.provider, source.path, state.reason!) return state } if (source.cacheStrategy && manifestEntry.cacheStrategy && source.cacheStrategy !== manifestEntry.cacheStrategy) { const state: SourceManifestState = { source, parserVersion, manifestEntry, action: 'refresh', reason: 'parser-version' } - logCacheDebug(source.provider, source.path, state.reason) + logCacheDebug(source.provider, source.path, state.reason!) return state } @@ -678,14 +678,14 @@ async function evaluateSourceManifestState( if (!manifestEntry.fingerprint || manifestEntry.fingerprintPath !== fingerprintPath) { const state: SourceManifestState = { source, parserVersion, manifestEntry, action: 'refresh', reason: 'fingerprint-miss' } - logCacheDebug(source.provider, source.path, state.reason) + logCacheDebug(source.provider, source.path, state.reason!) return state } const currentFingerprint = await computeFileFingerprint(fingerprintPath).catch(() => null) if (!currentFingerprint) { const state: SourceManifestState = { source, parserVersion, manifestEntry, action: 'refresh', reason: 'fingerprint-miss' } - logCacheDebug(source.provider, source.path, state.reason) + logCacheDebug(source.provider, source.path, state.reason!) return state } @@ -720,7 +720,7 @@ async function evaluateSourceManifestState( } const state: SourceManifestState = { source, parserVersion, manifestEntry, action: 'refresh', reason: 'fingerprint-miss', currentFingerprint } - logCacheDebug(source.provider, source.path, state.reason) + logCacheDebug(source.provider, source.path, state.reason!) return state } @@ -779,7 +779,7 @@ async function refreshClaudeCacheUnit( && !!cached.appendState && cached.sessions.length > 0 && !!state.currentFingerprint - if (shouldUseAppendOnly && manifestAppendState) { + if (shouldUseAppendOnly && manifestAppendState && cached?.appendState) { if ( manifestAppendState.tailHash !== cached.appendState.tailHash || manifestAppendState.endOffset !== cached.appendState.endOffset @@ -789,7 +789,7 @@ async function refreshClaudeCacheUnit( } } - if (shouldUseAppendOnly && cached) { + if (shouldUseAppendOnly && cached && cached.appendState) { addSeenDeduplicationKeysFromSessions(cached.sessions, localSeenMsgIds) const appendedLines: string[] = [] for await (const line of readSessionLinesFromOffset(unit.path, cached.appendState.endOffset)) { diff --git a/src/source-cache.ts b/src/source-cache.ts index 450da2a..cfe5d83 100644 --- a/src/source-cache.ts +++ b/src/source-cache.ts @@ -16,14 +16,14 @@ function traceCacheRead(op: string, filePath: string, note?: string): void { const APPEND_TAIL_WINDOW_BYTES = 16 * 1024 -export type SourceCacheStrategy = 'full-reparse' | 'append-jsonl' +type SourceCacheStrategy = 'full-reparse' | 'append-jsonl' -export type SourceFingerprint = { +type SourceFingerprint = { mtimeMs: number sizeBytes: number } -export type AppendState = { +type AppendState = { endOffset: number tailHash: string lastEntryType?: string @@ -59,18 +59,16 @@ export type SourceCacheManifestEntry = { appendState?: AppendState } -export type ReadSourceCacheEntryOptions = { +type ReadSourceCacheEntryOptions = { allowStaleFingerprint?: boolean } -export type SourceRange = { +type SourceRange = { firstTimestamp?: string lastTimestamp?: string } -export type CachedSourcePlanHint = SourceCacheManifestEntry & SourceRange - -export function sourceCacheKey(provider: string, logicalPath: string): string { +function sourceCacheKey(provider: string, logicalPath: string): string { return `${provider}:${logicalPath}` } @@ -174,18 +172,20 @@ function isParsedTurn(value: unknown): boolean { && typeof value.sessionId === 'string' } -function isModelBreakdownEntry(value: unknown): boolean { +function isModelBreakdownEntry(value: unknown): value is { calls: number; costUSD: number; tokens: TokenUsage } { return isPlainObject(value) && isFiniteNumber(value.calls) && isFiniteNumber(value.costUSD) && isTokenUsage(value.tokens) } -function isCallsBreakdownEntry(value: unknown): boolean { +type TokenUsage = { inputTokens: number; outputTokens: number; cacheCreationInputTokens: number; cacheReadInputTokens: number; cachedInputTokens: number; reasoningTokens: number; webSearchRequests: number } + +function isCallsBreakdownEntry(value: unknown): value is { calls: number } { return isPlainObject(value) && isFiniteNumber(value.calls) } -function isCategoryBreakdownEntry(value: unknown): boolean { +function isCategoryBreakdownEntry(value: unknown): value is { turns: number; costUSD: number; retries: number; editTurns: number; oneShotTurns: number } { return isPlainObject(value) && isFiniteNumber(value.turns) && isFiniteNumber(value.costUSD) @@ -343,9 +343,7 @@ async function atomicWriteJson(path: string, value: unknown): Promise { } catch (err) { try { await unlink(temp) - } catch { - // ignore cleanup failures - } + } catch {} throw err } }