claude-simple 0.2.36 → 0.2.38

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.36.min.css">
7
+ <link rel="stylesheet" href="/style.0.2.38.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.36.min.js"></script>
14
+ <script type="module" src="/app.0.2.38.min.js"></script>
15
15
  </body>
16
16
  </html>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-simple",
3
- "version": "0.2.36",
3
+ "version": "0.2.38",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "claude-simple": "server.js",
@@ -12,6 +12,10 @@ import crypto from 'crypto';
12
12
  * result (usage), complete, error
13
13
  */
14
14
 
15
+ export function isTransientCodexNotice(msg) {
16
+ return /Reconnecting|Falling back|remote compact task/i.test(String(msg || ''));
17
+ }
18
+
15
19
  function mapPermissionToMode(permissionMode) {
16
20
  if (permissionMode == null) return 'yolo';
17
21
  switch (permissionMode) {
@@ -244,7 +248,7 @@ export function runCodex(command, options, send, { cliPath, activeSessions }) {
244
248
  }
245
249
  case 'error': {
246
250
  const msg = raw.message || 'codex error';
247
- if (!/Reconnecting|Falling back/i.test(msg)) {
251
+ if (!isTransientCodexNotice(msg)) {
248
252
  send({ type: 'error', message: msg, agent: 'codex' });
249
253
  }
250
254
  break;
@@ -313,36 +313,65 @@ async function findCodexRollouts(codexHome) {
313
313
  return files;
314
314
  }
315
315
 
316
+ const CODEX_CATALOG_FULL_SCAN_MAX = 2 * 1024 * 1024;
317
+ const CODEX_CATALOG_HEAD_BYTES = 256 * 1024;
318
+ // session_meta includes git + base_instructions and is often 20–40KB.
319
+ // Multi-MB tool outputs still exceed this and are skipped.
320
+ const CODEX_LINE_PARSE_MAX = 256 * 1024;
321
+
316
322
  const codexMetadata = new Map();
317
323
  async function readCodexMeta(filePath) {
318
324
  const stat = await fs.stat(filePath);
319
325
  const cached = codexMetadata.get(filePath);
320
326
  if (cached?.size === stat.size && cached?.mtimeMs === stat.mtimeMs) return cached.meta;
321
327
  let id = null, cwd = null, ts = null, turnCount = 0;
328
+ // Native rollouts keep every tool payload. AgentUI / Hub never show that
329
+ // body, so catalog only reads a short head (session_meta is line 0).
330
+ const limit = stat.size > CODEX_CATALOG_FULL_SCAN_MAX
331
+ ? Math.min(stat.size, CODEX_CATALOG_HEAD_BYTES)
332
+ : stat.size;
322
333
  try {
323
- // Full scan: meta is early; turnCount needs whole file
324
- const stream = fsSync.createReadStream(filePath);
325
- const rl = readline.createInterface({ input: stream, crlfDelay: Infinity });
326
- for await (const line of rl) {
327
- const head = line.slice(0, 400);
328
- if (!/"type"\s*:\s*"(?:session_meta|turn_context)"/.test(head) &&
329
- !/"(?:role|type)"\s*:\s*"(?:user|user_message)"/.test(head)) continue;
330
- try {
331
- const d = JSON.parse(line);
332
- if (d.type === 'session_meta' && d.payload) {
333
- id = d.payload.id || id;
334
- cwd = d.payload.cwd || cwd;
335
- ts = d.payload.timestamp || d.timestamp || ts;
334
+ if (limit > 0) {
335
+ const stream = fsSync.createReadStream(filePath, { start: 0, end: limit - 1 });
336
+ let pending = Buffer.alloc(0);
337
+ let skip = false;
338
+ for await (const chunk of stream) {
339
+ pending = pending.length ? Buffer.concat([pending, chunk]) : chunk;
340
+ let start = 0;
341
+ let end;
342
+ while ((end = pending.indexOf(10, start)) !== -1) {
343
+ const len = end - start;
344
+ const overflow = skip || len > CODEX_LINE_PARSE_MAX;
345
+ skip = false;
346
+ if (!overflow) {
347
+ const line = pending.subarray(start, end).toString('utf8');
348
+ const head = line.slice(0, 400);
349
+ if (/"type"\s*:\s*"(?:session_meta|turn_context)"/.test(head) ||
350
+ /"(?:role|type)"\s*:\s*"(?:user|user_message)"/.test(head)) {
351
+ try {
352
+ const d = JSON.parse(line);
353
+ if (d.type === 'session_meta' && d.payload) {
354
+ id = d.payload.id || id;
355
+ cwd = d.payload.cwd || cwd;
356
+ ts = d.payload.timestamp || d.timestamp || ts;
357
+ }
358
+ if (d.type === 'event_msg' && d.payload?.type === 'user_message') turnCount += 1;
359
+ else if (d.type === 'response_item' && d.payload?.role === 'user') turnCount += 1;
360
+ else if (d.type === 'turn_context' && d.payload?.turn_index != null) {
361
+ const idx = Number(d.payload.turn_index) + 1;
362
+ if (idx > turnCount) turnCount = idx;
363
+ }
364
+ } catch {}
365
+ }
366
+ }
367
+ start = end + 1;
336
368
  }
337
- // Codex user turns appear in a few event shapes across versions
338
- if (d.type === 'event_msg' && d.payload?.type === 'user_message') turnCount += 1;
339
- else if (d.type === 'response_item' && d.payload?.role === 'user') turnCount += 1;
340
- else if (d.type === 'turn_context' && d.payload?.turn_index != null) {
341
- // last turn_index + 1 is a better total; bump max
342
- const idx = Number(d.payload.turn_index) + 1;
343
- if (idx > turnCount) turnCount = idx;
369
+ pending = pending.subarray(start);
370
+ if (pending.length > CODEX_LINE_PARSE_MAX) {
371
+ skip = true;
372
+ pending = Buffer.alloc(0);
344
373
  }
345
- } catch {}
374
+ }
346
375
  }
347
376
  } catch {}
348
377
  // Fallback: parse id from filename rollout-...-<uuid>.jsonl
@@ -472,11 +501,13 @@ async function updateCodexTranscript(filePath, entry, stat) {
472
501
  let start = 0;
473
502
  let end;
474
503
  while ((end = pending.indexOf(10, start)) !== -1) {
475
- const line = pending.subarray(start, end).toString('utf8');
476
- entry.offset += end - start + 1;
504
+ const lineBytes = end - start;
505
+ entry.offset += lineBytes + 1;
477
506
  start = end + 1;
478
- // Reasoning and tool outputs dominate large rollouts. Do not JSON-parse
479
- // their multi-megabyte payloads when building the visible transcript.
507
+ // Tool outputs are multi-MB JSONL lines. AgentUI does not render them
508
+ // and Hub must not receive them — skip without materializing the body.
509
+ if (lineBytes > 64 * 1024) continue;
510
+ const line = pending.subarray(start - lineBytes - 1, end).toString('utf8');
480
511
  const head = line.slice(0, 400);
481
512
  if (!/"type"\s*:\s*"(?:response_item|event_msg)"/.test(head) ||
482
513
  !/"type"\s*:\s*"(?:message|agent_message|function_call|command_execution|custom_tool_call|task_started|task_complete|turn_aborted)"/.test(head)) continue;
File without changes