From 7dc60076ec9052b598752f621736fb5734354175 Mon Sep 17 00:00:00 2001 From: RagavRida Date: Fri, 24 Apr 2026 00:08:28 +0530 Subject: [PATCH] fix(global-discover): stop dropping sessions when header >8KB extractCwdFromJsonl() reads the first 8KB of each JSONL session file and runs JSON.parse on every newline-split line. When a session record happens to straddle the 8KB cap, the last line ends in a truncated JSON fragment, JSON.parse throws, the catch block 'continue's silently, and if that was the only line carrying 'cwd' the whole project gets dropped from the discovery output without a warning. Two independent hardening steps: 1. Raise the read cap to 64KB. Session headers observed in Claude Code / Codex / Gemini transcripts fit comfortably; this just moves the cliff out of the normal range. 2. Drop the final segment after splitting on '\\n'. If the read hit the cap mid-line, that segment is guaranteed incomplete; if the file ended inside the buffer, the split produces an empty final segment and dropping it is a no-op. Together these make the parser robust regardless of how verbose the leading records are. --- bin/gstack-global-discover.ts | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/bin/gstack-global-discover.ts b/bin/gstack-global-discover.ts index 4e1445b37..7f0714100 100644 --- a/bin/gstack-global-discover.ts +++ b/bin/gstack-global-discover.ts @@ -274,15 +274,22 @@ function resolveClaudeCodeCwd( } function extractCwdFromJsonl(filePath: string): string | null { + // Read a capped prefix so huge JSONL files don't blow up memory. 64KB + // comfortably fits the largest observed session headers; the old 8KB cap + // would sometimes fall inside a single long line and silently drop the + // project (JSON.parse failure on the truncated tail). + const MAX_BYTES = 64 * 1024; + const MAX_LINES = 30; try { - // Read only the first 8KB to avoid loading huge JSONL files into memory const fd = openSync(filePath, "r"); - const buf = Buffer.alloc(8192); - const bytesRead = readSync(fd, buf, 0, 8192, 0); + const buf = Buffer.alloc(MAX_BYTES); + const bytesRead = readSync(fd, buf, 0, MAX_BYTES, 0); closeSync(fd); const text = buf.toString("utf-8", 0, bytesRead); - const lines = text.split("\n").slice(0, 15); - for (const line of lines) { + // Drop the final segment — it may be an incomplete line at the cap boundary. + const parts = text.split("\n"); + const completeLines = parts.length > 1 ? parts.slice(0, -1) : parts; + for (const line of completeLines.slice(0, MAX_LINES)) { if (!line.trim()) continue; try { const obj = JSON.parse(line);