claude-simple 0.2.37 → 0.2.39
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.html
CHANGED
|
@@ -4,13 +4,13 @@
|
|
|
4
4
|
<meta charset="UTF-8">
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0">
|
|
6
6
|
<title>Claude Code</title>
|
|
7
|
-
<link rel="stylesheet" href="/style.0.2.
|
|
7
|
+
<link rel="stylesheet" href="/style.0.2.39.min.css">
|
|
8
8
|
<link rel="stylesheet" href="/highlight.min.css">
|
|
9
9
|
<script src="/marked.min.js"></script>
|
|
10
10
|
<script src="/highlight.min.js"></script>
|
|
11
11
|
</head>
|
|
12
12
|
<body class="h-dvh overflow-hidden flex flex-col bg-base-100 text-base-content">
|
|
13
13
|
<div id="root" class="flex flex-col flex-1 overflow-hidden"></div>
|
|
14
|
-
<script type="module" src="/app.0.2.
|
|
14
|
+
<script type="module" src="/app.0.2.39.min.js"></script>
|
|
15
15
|
</body>
|
|
16
16
|
</html>
|
package/package.json
CHANGED
package/src/agents/sessions.js
CHANGED
|
@@ -5,6 +5,7 @@ import path from 'path';
|
|
|
5
5
|
import os from 'os';
|
|
6
6
|
import crypto from 'crypto';
|
|
7
7
|
import { pathsEqual } from '../platform.js';
|
|
8
|
+
import { JSONL_LINE_PARSE_MAX, scanJsonlFile } from '../jsonl-scan.js';
|
|
8
9
|
|
|
9
10
|
// ─── Claude ───────────────────────────────────────────────────────────────────
|
|
10
11
|
|
|
@@ -315,7 +316,10 @@ async function findCodexRollouts(codexHome) {
|
|
|
315
316
|
|
|
316
317
|
const CODEX_CATALOG_FULL_SCAN_MAX = 2 * 1024 * 1024;
|
|
317
318
|
const CODEX_CATALOG_HEAD_BYTES = 256 * 1024;
|
|
318
|
-
|
|
319
|
+
// session_meta includes git + base_instructions and is often 20–40KB.
|
|
320
|
+
// Multi-MB tool outputs still exceed this and are skipped.
|
|
321
|
+
const CODEX_LINE_PARSE_MAX = 256 * 1024;
|
|
322
|
+
const CODEX_TRANSCRIPT_CACHE_MAX = 64;
|
|
319
323
|
|
|
320
324
|
const codexMetadata = new Map();
|
|
321
325
|
async function readCodexMeta(filePath) {
|
|
@@ -443,7 +447,9 @@ export async function parseCodexMessages(filePath) {
|
|
|
443
447
|
}
|
|
444
448
|
codexTranscripts.delete(filePath);
|
|
445
449
|
codexTranscripts.set(filePath, entry);
|
|
446
|
-
while (codexTranscripts.size >
|
|
450
|
+
while (codexTranscripts.size > CODEX_TRANSCRIPT_CACHE_MAX) {
|
|
451
|
+
codexTranscripts.delete(codexTranscripts.keys().next().value);
|
|
452
|
+
}
|
|
447
453
|
if (entry.size === stat.size && entry.mtimeMs === stat.mtimeMs) return entry.messages;
|
|
448
454
|
const loading = updateCodexTranscript(filePath, entry, stat);
|
|
449
455
|
entry.loading = loading;
|
|
@@ -492,25 +498,16 @@ async function updateCodexTranscript(filePath, entry, stat) {
|
|
|
492
498
|
|
|
493
499
|
try {
|
|
494
500
|
if (stat.size <= entry.offset) return;
|
|
495
|
-
const
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
let end;
|
|
501
|
-
while ((end = pending.indexOf(10, start)) !== -1) {
|
|
502
|
-
const lineBytes = end - start;
|
|
503
|
-
entry.offset += lineBytes + 1;
|
|
504
|
-
start = end + 1;
|
|
505
|
-
// Tool outputs are multi-MB JSONL lines. AgentUI does not render them
|
|
506
|
-
// and Hub must not receive them — skip without materializing the body.
|
|
507
|
-
if (lineBytes > 64 * 1024) continue;
|
|
508
|
-
const line = pending.subarray(start - lineBytes - 1, end).toString('utf8');
|
|
501
|
+
const scanned = await scanJsonlFile(filePath, {
|
|
502
|
+
start: entry.offset,
|
|
503
|
+
end: stat.size,
|
|
504
|
+
maxLineBytes: JSONL_LINE_PARSE_MAX,
|
|
505
|
+
onLine: (line) => {
|
|
509
506
|
const head = line.slice(0, 400);
|
|
510
507
|
if (!/"type"\s*:\s*"(?:response_item|event_msg)"/.test(head) ||
|
|
511
|
-
!/"type"\s*:\s*"(?:message|agent_message|function_call|command_execution|custom_tool_call|task_started|task_complete|turn_aborted)"/.test(head))
|
|
508
|
+
!/"type"\s*:\s*"(?:message|agent_message|function_call|command_execution|custom_tool_call|task_started|task_complete|turn_aborted)"/.test(head)) return;
|
|
512
509
|
let d;
|
|
513
|
-
try { d = JSON.parse(line); } catch {
|
|
510
|
+
try { d = JSON.parse(line); } catch { return; }
|
|
514
511
|
|
|
515
512
|
if (d.type === 'event_msg' && d.payload) {
|
|
516
513
|
const p = d.payload;
|
|
@@ -542,13 +539,13 @@ async function updateCodexTranscript(filePath, entry, stat) {
|
|
|
542
539
|
.filter(Boolean);
|
|
543
540
|
pushAssistant(texts.join('\n'), d.timestamp);
|
|
544
541
|
} else if (p.type === 'function_call') {
|
|
545
|
-
if (p.call_id && entry.seenCalls.has(p.call_id))
|
|
542
|
+
if (p.call_id && entry.seenCalls.has(p.call_id)) return;
|
|
546
543
|
if (p.call_id) entry.seenCalls.add(p.call_id);
|
|
547
544
|
let input = p.arguments;
|
|
548
545
|
try { input = typeof input === 'string' ? JSON.parse(input) : input; } catch {}
|
|
549
546
|
messages.push({ role: 'tool', type: 'tool_use', name: p.name || 'function', id: p.call_id, input: input ?? {}, ts: d.timestamp });
|
|
550
547
|
} else if (p.type === 'command_execution' || p.type === 'custom_tool_call') {
|
|
551
|
-
if (p.call_id && entry.seenCalls.has(p.call_id))
|
|
548
|
+
if (p.call_id && entry.seenCalls.has(p.call_id)) return;
|
|
552
549
|
if (p.call_id) entry.seenCalls.add(p.call_id);
|
|
553
550
|
let input = p.input;
|
|
554
551
|
try { input = typeof input === 'string' ? JSON.parse(input) : input; } catch {}
|
|
@@ -568,9 +565,9 @@ async function updateCodexTranscript(filePath, entry, stat) {
|
|
|
568
565
|
const text = d.payload.message || d.payload.text;
|
|
569
566
|
pushAssistant(text, d.timestamp);
|
|
570
567
|
}
|
|
571
|
-
}
|
|
572
|
-
|
|
573
|
-
|
|
568
|
+
},
|
|
569
|
+
});
|
|
570
|
+
entry.offset = scanned.offset;
|
|
574
571
|
entry.size = stat.size;
|
|
575
572
|
entry.mtimeMs = stat.mtimeMs;
|
|
576
573
|
} catch (error) {
|
|
@@ -1920,15 +1917,11 @@ export async function loadSessionJsonl(sessionId, agent, { claudeConfigDirs, cod
|
|
|
1920
1917
|
const budget = Math.min(Math.max(1000, Number(maxChars) || 24000), 64000);
|
|
1921
1918
|
const lines = [];
|
|
1922
1919
|
let n = 0, chars = 0, hasMore = false, clipped = false;
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
try {
|
|
1926
|
-
for await (const line of rl) {
|
|
1920
|
+
await scanJsonlFile(file, {
|
|
1921
|
+
onLine: (line) => {
|
|
1927
1922
|
const index = n++;
|
|
1928
|
-
if (!tail && index < start)
|
|
1929
|
-
if (!tail && (lines.length >= limit || chars >= budget)) { hasMore = true;
|
|
1930
|
-
// Bound huge tool output rows as well as total response size. Clipping
|
|
1931
|
-
// is explicit: a clipped line must not be mistaken for complete JSON.
|
|
1923
|
+
if (!tail && index < start) return;
|
|
1924
|
+
if (!tail && (lines.length >= limit || chars >= budget)) { hasMore = true; return; }
|
|
1932
1925
|
const cap = tail ? budget : budget - chars;
|
|
1933
1926
|
const text = line.slice(0, cap);
|
|
1934
1927
|
if (text.length < line.length) clipped = true;
|
|
@@ -1936,8 +1929,8 @@ export async function loadSessionJsonl(sessionId, agent, { claudeConfigDirs, cod
|
|
|
1936
1929
|
if (tail) while (lines.length > limit || (chars > budget && lines.length > 1)) {
|
|
1937
1930
|
chars -= lines.shift().length;
|
|
1938
1931
|
}
|
|
1939
|
-
}
|
|
1940
|
-
}
|
|
1932
|
+
},
|
|
1933
|
+
});
|
|
1941
1934
|
const stat = await fs.stat(file).catch(() => null);
|
|
1942
1935
|
const actualOffset = tail ? Math.max(0, n - lines.length) : start;
|
|
1943
1936
|
return { agent: a, fileName: path.basename(file), offset: actualOffset, lines,
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import fsSync from 'node:fs';
|
|
2
|
+
import fs from 'node:fs/promises';
|
|
3
|
+
|
|
4
|
+
export const JSONL_LINE_PARSE_MAX = 64 * 1024;
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Sequential JSONL reader. Oversize records are skipped by searching for the
|
|
8
|
+
* next newline without keeping the body in a JS string.
|
|
9
|
+
*/
|
|
10
|
+
export async function scanJsonlFile(filePath, {
|
|
11
|
+
start = 0,
|
|
12
|
+
end = null,
|
|
13
|
+
maxLineBytes = JSONL_LINE_PARSE_MAX,
|
|
14
|
+
onLine,
|
|
15
|
+
} = {}) {
|
|
16
|
+
const stat = await fs.stat(filePath);
|
|
17
|
+
const stop = end == null ? stat.size : Math.min(end, stat.size);
|
|
18
|
+
let offset = Math.max(0, start);
|
|
19
|
+
let skippedLines = 0;
|
|
20
|
+
if (offset >= stop) return { offset, skippedLines, size: stat.size };
|
|
21
|
+
|
|
22
|
+
const stream = fsSync.createReadStream(filePath, {
|
|
23
|
+
start: offset,
|
|
24
|
+
end: stop - 1,
|
|
25
|
+
highWaterMark: 64 * 1024,
|
|
26
|
+
});
|
|
27
|
+
let pending = Buffer.alloc(0);
|
|
28
|
+
let skip = false;
|
|
29
|
+
try {
|
|
30
|
+
for await (const chunk of stream) {
|
|
31
|
+
let buf = skip ? chunk : (pending.length ? Buffer.concat([pending, chunk]) : chunk);
|
|
32
|
+
pending = Buffer.alloc(0);
|
|
33
|
+
let pos = 0;
|
|
34
|
+
if (skip) {
|
|
35
|
+
const nl = buf.indexOf(10);
|
|
36
|
+
if (nl === -1) {
|
|
37
|
+
offset += buf.length;
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
offset += nl + 1;
|
|
41
|
+
skippedLines += 1;
|
|
42
|
+
skip = false;
|
|
43
|
+
pos = nl + 1;
|
|
44
|
+
}
|
|
45
|
+
while (pos < buf.length) {
|
|
46
|
+
const nl = buf.indexOf(10, pos);
|
|
47
|
+
if (nl === -1) break;
|
|
48
|
+
const len = nl - pos;
|
|
49
|
+
offset += len + 1;
|
|
50
|
+
if (len > maxLineBytes) {
|
|
51
|
+
skippedLines += 1;
|
|
52
|
+
} else if (typeof onLine === 'function') {
|
|
53
|
+
onLine(buf.subarray(pos, nl).toString('utf8'), { pendingBytes: buf.length, offset });
|
|
54
|
+
}
|
|
55
|
+
pos = nl + 1;
|
|
56
|
+
}
|
|
57
|
+
if (pos < buf.length) {
|
|
58
|
+
const leftover = buf.subarray(pos);
|
|
59
|
+
if (leftover.length > maxLineBytes) {
|
|
60
|
+
skip = true;
|
|
61
|
+
offset += leftover.length;
|
|
62
|
+
} else {
|
|
63
|
+
pending = leftover;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
} finally {
|
|
68
|
+
stream.destroy();
|
|
69
|
+
}
|
|
70
|
+
return { offset, skippedLines, size: stat.size };
|
|
71
|
+
}
|
|
File without changes
|
|
File without changes
|