@supen-ai/cli 1.4.1 → 1.4.2

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.
Files changed (203) hide show
  1. package/README.md +1 -1
  2. package/daemon/dist/agent-sdk/app-server-stream.js +5 -5
  3. package/daemon/dist/agent-sdk/app-server-stream.js.map +1 -1
  4. package/daemon/dist/agent-sdk/drivers/codex-app-server-driver.d.ts +3 -2
  5. package/daemon/dist/agent-sdk/drivers/codex-app-server-driver.d.ts.map +1 -1
  6. package/daemon/dist/agent-sdk/drivers/codex-app-server-driver.js +72 -49
  7. package/daemon/dist/agent-sdk/drivers/codex-app-server-driver.js.map +1 -1
  8. package/daemon/dist/agent-sdk/drivers/driver.d.ts +8 -8
  9. package/daemon/dist/agent-sdk/drivers/driver.d.ts.map +1 -1
  10. package/daemon/dist/agent-sdk/index.d.ts +4 -4
  11. package/daemon/dist/agent-sdk/index.d.ts.map +1 -1
  12. package/daemon/dist/agent-sdk/index.js +2 -2
  13. package/daemon/dist/agent-sdk/index.js.map +1 -1
  14. package/daemon/dist/agent-sdk/intelligence/contracts.d.ts +2 -2
  15. package/daemon/dist/agent-sdk/intelligence/contracts.d.ts.map +1 -1
  16. package/daemon/dist/agent-sdk/memory/subsystem.d.ts +1 -1
  17. package/daemon/dist/agent-sdk/memory/subsystem.d.ts.map +1 -1
  18. package/daemon/dist/agent-sdk/{session-events.d.ts → thread-events.d.ts} +18 -18
  19. package/daemon/dist/agent-sdk/thread-events.d.ts.map +1 -0
  20. package/daemon/dist/agent-sdk/{session-events.js → thread-events.js} +15 -15
  21. package/daemon/dist/agent-sdk/thread-events.js.map +1 -0
  22. package/daemon/dist/agent-sdk/{session-manager.d.ts → thread-manager.d.ts} +9 -9
  23. package/daemon/dist/agent-sdk/thread-manager.d.ts.map +1 -0
  24. package/daemon/dist/agent-sdk/{session-manager.js → thread-manager.js} +7 -7
  25. package/daemon/dist/agent-sdk/thread-manager.js.map +1 -0
  26. package/daemon/dist/agent-sdk/types.d.ts +18 -18
  27. package/daemon/dist/agent-sdk/types.d.ts.map +1 -1
  28. package/daemon/dist/automation-event-listener.js +6 -6
  29. package/daemon/dist/automation-event-listener.js.map +1 -1
  30. package/daemon/dist/automation-runner.d.ts +1 -1
  31. package/daemon/dist/automation-runner.d.ts.map +1 -1
  32. package/daemon/dist/automation-runner.js +24 -24
  33. package/daemon/dist/automation-runner.js.map +1 -1
  34. package/daemon/dist/autonomy/memory-rules.d.ts +2 -2
  35. package/daemon/dist/autonomy/memory-rules.d.ts.map +1 -1
  36. package/daemon/dist/autonomy/memory-rules.js +1 -1
  37. package/daemon/dist/autonomy/memory-rules.js.map +1 -1
  38. package/daemon/dist/autonomy/session-autonomy.d.ts +4 -4
  39. package/daemon/dist/autonomy/session-autonomy.d.ts.map +1 -1
  40. package/daemon/dist/autonomy/session-autonomy.js +5 -5
  41. package/daemon/dist/autonomy/session-autonomy.js.map +1 -1
  42. package/daemon/dist/bin/mcp-os.js +1 -1
  43. package/daemon/dist/bin/mcp-os.js.map +1 -1
  44. package/daemon/dist/bin/mcp-scheduler.js +1 -1
  45. package/daemon/dist/bin/mcp-scheduler.js.map +1 -1
  46. package/daemon/dist/bin/supen-sys.js +1 -1
  47. package/daemon/dist/bin/supen-sys.js.map +1 -1
  48. package/daemon/dist/bootstrap/hub-bootstrap.js +1 -1
  49. package/daemon/dist/bootstrap/hub-bootstrap.js.map +1 -1
  50. package/daemon/dist/channels/http-routes.d.ts.map +1 -1
  51. package/daemon/dist/channels/http-routes.js +54 -60
  52. package/daemon/dist/channels/http-routes.js.map +1 -1
  53. package/daemon/dist/channels/http.js +2 -2
  54. package/daemon/dist/channels/http.js.map +1 -1
  55. package/daemon/dist/channels/index.d.ts +0 -1
  56. package/daemon/dist/channels/index.d.ts.map +1 -1
  57. package/daemon/dist/channels/index.js +0 -2
  58. package/daemon/dist/channels/index.js.map +1 -1
  59. package/daemon/dist/channels/registry.d.ts +1 -1
  60. package/daemon/dist/channels/registry.d.ts.map +1 -1
  61. package/daemon/dist/commands/builtin.d.ts +1 -1
  62. package/daemon/dist/commands/builtin.d.ts.map +1 -1
  63. package/daemon/dist/commands/builtin.js +2 -2
  64. package/daemon/dist/commands/builtin.js.map +1 -1
  65. package/daemon/dist/commands/catalog.js +3 -3
  66. package/daemon/dist/commands/catalog.js.map +1 -1
  67. package/daemon/dist/core/config.d.ts +0 -2
  68. package/daemon/dist/core/config.d.ts.map +1 -1
  69. package/daemon/dist/core/config.js +0 -5
  70. package/daemon/dist/core/config.js.map +1 -1
  71. package/daemon/dist/core/control-commands.d.ts +3 -3
  72. package/daemon/dist/core/control-commands.d.ts.map +1 -1
  73. package/daemon/dist/core/control-commands.js +6 -6
  74. package/daemon/dist/core/control-commands.js.map +1 -1
  75. package/daemon/dist/core/control-log.d.ts +4 -4
  76. package/daemon/dist/core/control-log.d.ts.map +1 -1
  77. package/daemon/dist/core/control-log.js +12 -12
  78. package/daemon/dist/core/control-log.js.map +1 -1
  79. package/daemon/dist/core/cortex.d.ts +4 -4
  80. package/daemon/dist/core/cortex.d.ts.map +1 -1
  81. package/daemon/dist/core/cortex.js +98 -117
  82. package/daemon/dist/core/cortex.js.map +1 -1
  83. package/daemon/dist/core/dispatcher.d.ts +3 -3
  84. package/daemon/dist/core/dispatcher.js +18 -18
  85. package/daemon/dist/core/dispatcher.js.map +1 -1
  86. package/daemon/dist/core/gateway-protocol.d.ts +0 -1
  87. package/daemon/dist/core/gateway-protocol.d.ts.map +1 -1
  88. package/daemon/dist/core/gateway.d.ts +3 -3
  89. package/daemon/dist/core/gateway.d.ts.map +1 -1
  90. package/daemon/dist/core/gateway.js +26 -26
  91. package/daemon/dist/core/gateway.js.map +1 -1
  92. package/daemon/dist/core/hub-snapshot.d.ts +1 -1
  93. package/daemon/dist/core/hub-snapshot.d.ts.map +1 -1
  94. package/daemon/dist/core/hub-snapshot.js +1 -1
  95. package/daemon/dist/core/hub-snapshot.js.map +1 -1
  96. package/daemon/dist/core/pairing.d.ts +2 -2
  97. package/daemon/dist/core/pairing.js +3 -3
  98. package/daemon/dist/core/pairing.js.map +1 -1
  99. package/daemon/dist/core/store.d.ts +38 -38
  100. package/daemon/dist/core/store.d.ts.map +1 -1
  101. package/daemon/dist/core/store.js +285 -289
  102. package/daemon/dist/core/store.js.map +1 -1
  103. package/daemon/dist/core/task-artifacts.d.ts +4 -4
  104. package/daemon/dist/core/task-artifacts.d.ts.map +1 -1
  105. package/daemon/dist/core/task-artifacts.js +10 -10
  106. package/daemon/dist/core/task-artifacts.js.map +1 -1
  107. package/daemon/dist/core/thread-context.js +1 -1
  108. package/daemon/dist/core/thread-context.js.map +1 -1
  109. package/daemon/dist/core/types.d.ts +28 -28
  110. package/daemon/dist/core/types.d.ts.map +1 -1
  111. package/daemon/dist/core/utils.js +1 -1
  112. package/daemon/dist/core/utils.js.map +1 -1
  113. package/daemon/dist/http/router.d.ts +2 -2
  114. package/daemon/dist/http/router.d.ts.map +1 -1
  115. package/daemon/dist/http/router.js +5 -5
  116. package/daemon/dist/http/router.js.map +1 -1
  117. package/daemon/dist/http/routes/agents.js +3 -3
  118. package/daemon/dist/http/routes/agents.js.map +1 -1
  119. package/daemon/dist/http/routes/automations.d.ts +2 -2
  120. package/daemon/dist/http/routes/automations.d.ts.map +1 -1
  121. package/daemon/dist/http/routes/automations.js +23 -23
  122. package/daemon/dist/http/routes/automations.js.map +1 -1
  123. package/daemon/dist/http/routes/chat-input.d.ts +1 -1
  124. package/daemon/dist/http/routes/chat-input.d.ts.map +1 -1
  125. package/daemon/dist/http/routes/chat-input.js +2 -2
  126. package/daemon/dist/http/routes/chat-input.js.map +1 -1
  127. package/daemon/dist/http/routes/plugins.d.ts.map +1 -1
  128. package/daemon/dist/http/routes/plugins.js +6 -74
  129. package/daemon/dist/http/routes/plugins.js.map +1 -1
  130. package/daemon/dist/http/routes/rpc.d.ts +3 -3
  131. package/daemon/dist/http/routes/rpc.d.ts.map +1 -1
  132. package/daemon/dist/http/routes/rpc.js +91 -92
  133. package/daemon/dist/http/routes/rpc.js.map +1 -1
  134. package/daemon/dist/http/routes/system.d.ts +7 -7
  135. package/daemon/dist/http/routes/system.d.ts.map +1 -1
  136. package/daemon/dist/http/routes/system.js +211 -105
  137. package/daemon/dist/http/routes/system.js.map +1 -1
  138. package/daemon/dist/http/routes/threads.d.ts +11 -0
  139. package/daemon/dist/http/routes/threads.d.ts.map +1 -0
  140. package/daemon/dist/http/routes/{sessions.js → threads.js} +157 -157
  141. package/daemon/dist/http/routes/threads.js.map +1 -0
  142. package/daemon/dist/http/stream.d.ts +2 -2
  143. package/daemon/dist/http/stream.d.ts.map +1 -1
  144. package/daemon/dist/http/stream.js +3 -3
  145. package/daemon/dist/http/stream.js.map +1 -1
  146. package/daemon/dist/http/thread-title.d.ts +1 -1
  147. package/daemon/dist/http/thread-title.d.ts.map +1 -1
  148. package/daemon/dist/http/thread-title.js +6 -6
  149. package/daemon/dist/http/thread-title.js.map +1 -1
  150. package/daemon/dist/http/websocket.d.ts +2 -2
  151. package/daemon/dist/http/websocket.d.ts.map +1 -1
  152. package/daemon/dist/http/websocket.js +11 -11
  153. package/daemon/dist/http/websocket.js.map +1 -1
  154. package/daemon/dist/index.d.ts +3 -3
  155. package/daemon/dist/index.d.ts.map +1 -1
  156. package/daemon/dist/index.js +64 -81
  157. package/daemon/dist/index.js.map +1 -1
  158. package/daemon/dist/mcp/aggregate-config.d.ts +1 -1
  159. package/daemon/dist/mcp/index.js +1 -1
  160. package/daemon/dist/mcp/index.js.map +1 -1
  161. package/daemon/dist/mcp/tools.d.ts +1 -1
  162. package/daemon/dist/mcp/tools.js +1 -1
  163. package/daemon/dist/plugins/hub.d.ts +2 -8
  164. package/daemon/dist/plugins/hub.d.ts.map +1 -1
  165. package/daemon/dist/plugins/hub.js +63 -214
  166. package/daemon/dist/plugins/hub.js.map +1 -1
  167. package/daemon/dist/plugins/types.d.ts +10 -0
  168. package/daemon/dist/plugins/types.d.ts.map +1 -1
  169. package/daemon/dist/sub-agent.d.ts +3 -3
  170. package/daemon/dist/sub-agent.d.ts.map +1 -1
  171. package/daemon/dist/sub-agent.js +8 -8
  172. package/daemon/dist/sub-agent.js.map +1 -1
  173. package/daemon/dist/sync/supabase-sync.js +18 -18
  174. package/daemon/dist/sync/supabase-sync.js.map +1 -1
  175. package/daemon/dist/task-executor.js +1 -1
  176. package/daemon/dist/task-executor.js.map +1 -1
  177. package/daemon/dist/tools/shell.js +1 -1
  178. package/daemon/dist/tools/shell.js.map +1 -1
  179. package/daemon/dist/tools/types.d.ts +1 -1
  180. package/daemon/dist/tools/types.d.ts.map +1 -1
  181. package/daemon/package.json +1 -1
  182. package/dist/computer.js +1 -1
  183. package/dist/index.js +1 -1
  184. package/package.json +1 -1
  185. package/daemon/dist/acp-client.d.ts +0 -42
  186. package/daemon/dist/acp-client.d.ts.map +0 -1
  187. package/daemon/dist/acp-client.js +0 -149
  188. package/daemon/dist/acp-client.js.map +0 -1
  189. package/daemon/dist/acp-types.d.ts +0 -98
  190. package/daemon/dist/acp-types.d.ts.map +0 -1
  191. package/daemon/dist/acp-types.js +0 -2
  192. package/daemon/dist/acp-types.js.map +0 -1
  193. package/daemon/dist/agent-sdk/session-events.d.ts.map +0 -1
  194. package/daemon/dist/agent-sdk/session-events.js.map +0 -1
  195. package/daemon/dist/agent-sdk/session-manager.d.ts.map +0 -1
  196. package/daemon/dist/agent-sdk/session-manager.js.map +0 -1
  197. package/daemon/dist/channels/acp.d.ts +0 -23
  198. package/daemon/dist/channels/acp.d.ts.map +0 -1
  199. package/daemon/dist/channels/acp.js +0 -915
  200. package/daemon/dist/channels/acp.js.map +0 -1
  201. package/daemon/dist/http/routes/sessions.d.ts +0 -11
  202. package/daemon/dist/http/routes/sessions.d.ts.map +0 -1
  203. package/daemon/dist/http/routes/sessions.js.map +0 -1
@@ -14,7 +14,7 @@ import { collectOsTelemetryFields } from '../../core/os-info.js';
14
14
  import { getCodingCliStatusResponse, startCodingCliStatusCache, } from '../../core/coding-cli-status-cache.js';
15
15
  import { getGatewayInstance, getLlmToken } from '../../core/gateway.js';
16
16
  import { normalizeGatewayUplinkUrl, readGatewayConfig, writeGatewayConfig, } from '../../core/gateway-config.js';
17
- import { ensureSession, getAllAgents, getDailyUsage, getGlobalUsage, getSessionsForAgent, getSessionUiEvents, updateSessionBackendDriverId, updateSessionSdkId, } from '../../core/store.js';
17
+ import { ensureThread, getAllAgents, getDailyUsage, getGlobalUsage, getThreadsForAgent, getThreadUiEvents, updateThreadBackendDriverId, updateThreadSdkSessionId, } from '../../core/store.js';
18
18
  import { listMcpEnvKeys, listMcpServers } from '../../mcp/default-servers.js';
19
19
  import { getMcpEnvOverrides, updateMcpEnvOverrides } from '../../mcp/settings.js';
20
20
  import { getMcpManager } from '../../mcp/index.js';
@@ -32,6 +32,9 @@ const SPACE_LOG_STREAM_PING_MS = 15000;
32
32
  const MIRRORED_THREAD_LIMIT = 80;
33
33
  const MIRRORED_THREAD_HISTORY_LIMIT = 200;
34
34
  const MIRRORED_THREAD_HISTORY_MAX_BYTES = 256 * 1024 * 1024;
35
+ const MIRRORED_THREAD_HISTORY_FAST_MAX_BYTES = 8 * 1024 * 1024;
36
+ const MIRRORED_THREAD_HISTORY_FAST_MAX_LINES = 2_000;
37
+ const MIRRORED_THREAD_JSONL_CACHE_LIMIT = 64;
35
38
  const MIRRORED_THREAD_PROJECTION_VERSION = 2;
36
39
  const MIRRORED_THREAD_TEXT_LIMIT = 48_000;
37
40
  const MIRRORED_THREAD_INLINE_DATA_URL_LIMIT = 120_000;
@@ -114,6 +117,9 @@ function truncateStreamDelta(value, max = 160) {
114
117
  function currentSpaceId() {
115
118
  return (process.env.SUPEN_SPACE_ID || '').trim() || 'local';
116
119
  }
120
+ const recentJsonlLineCache = new Map();
121
+ const recentCodexHistoryLineCache = new Map();
122
+ const mirroredFileTextCache = new Map();
117
123
  function summarizeStreamEvent(raw) {
118
124
  const inner = raw.event && typeof raw.event === 'object'
119
125
  ? raw.event
@@ -384,13 +390,13 @@ function extractQuotaEvent(event) {
384
390
  };
385
391
  }
386
392
  function readLatestSpaceQuotaStatus() {
387
- const sessions = getAllAgents()
388
- .flatMap((agent) => getSessionsForAgent(agent.agent_id).map((session) => ({
393
+ const threads = getAllAgents()
394
+ .flatMap((agent) => getThreadsForAgent(agent.agent_id).map((thread) => ({
389
395
  agent_id: agent.agent_id,
390
- session_id: session.session_id,
396
+ thread_id: thread.thread_id,
391
397
  })));
392
- const latest = sessions
393
- .flatMap((session) => getSessionUiEvents(session.agent_id, session.session_id, 200)
398
+ const latest = threads
399
+ .flatMap((thread) => getThreadUiEvents(thread.agent_id, thread.thread_id, 200)
394
400
  .map((event) => extractQuotaEvent(event)))
395
401
  .filter((entry) => Boolean(entry))
396
402
  .sort((a, b) => a.updated_at.localeCompare(b.updated_at))
@@ -414,17 +420,84 @@ function parseJsonLine(line) {
414
420
  return null;
415
421
  }
416
422
  }
417
- export function readRecentJsonlLines(filePath, maxBytes = MIRRORED_THREAD_HISTORY_MAX_BYTES) {
418
- const safeMaxBytes = Math.max(1, Math.min(Math.floor(maxBytes), MIRRORED_THREAD_HISTORY_MAX_BYTES));
419
- const size = fs.statSync(filePath).size;
420
- if (size <= safeMaxBytes) {
421
- return fs.readFileSync(filePath, 'utf-8').split(/\r?\n/).filter(Boolean);
423
+ function jsonlCacheKey(parts) {
424
+ return parts.map((part) => part === undefined ? '' : String(part)).join('\u0000');
425
+ }
426
+ function getCachedJsonlLines(cache, key, stat) {
427
+ const cached = cache.get(key);
428
+ if (!cached)
429
+ return null;
430
+ if (cached.size !== stat.size || cached.mtimeMs !== stat.mtimeMs) {
431
+ cache.delete(key);
432
+ return null;
433
+ }
434
+ cached.accessedAt = Date.now();
435
+ return cached.lines;
436
+ }
437
+ function setCachedJsonlLines(cache, key, entry) {
438
+ if (cache.size >= MIRRORED_THREAD_JSONL_CACHE_LIMIT && !cache.has(key)) {
439
+ let oldestKey = null;
440
+ let oldestAccess = Number.POSITIVE_INFINITY;
441
+ for (const [candidateKey, candidate] of cache) {
442
+ if (candidate.accessedAt < oldestAccess) {
443
+ oldestAccess = candidate.accessedAt;
444
+ oldestKey = candidateKey;
445
+ }
446
+ }
447
+ if (oldestKey)
448
+ cache.delete(oldestKey);
449
+ }
450
+ cache.set(key, {
451
+ ...entry,
452
+ accessedAt: Date.now(),
453
+ });
454
+ return entry.lines;
455
+ }
456
+ function getCachedFileText(key, stat) {
457
+ const cached = mirroredFileTextCache.get(key);
458
+ if (!cached)
459
+ return null;
460
+ if (cached.size !== stat.size || cached.mtimeMs !== stat.mtimeMs) {
461
+ mirroredFileTextCache.delete(key);
462
+ return null;
422
463
  }
464
+ cached.accessedAt = Date.now();
465
+ return cached.text;
466
+ }
467
+ function setCachedFileText(key, stat, text) {
468
+ if (mirroredFileTextCache.size >= MIRRORED_THREAD_JSONL_CACHE_LIMIT && !mirroredFileTextCache.has(key)) {
469
+ let oldestKey = null;
470
+ let oldestAccess = Number.POSITIVE_INFINITY;
471
+ for (const [candidateKey, candidate] of mirroredFileTextCache) {
472
+ if (candidate.accessedAt < oldestAccess) {
473
+ oldestAccess = candidate.accessedAt;
474
+ oldestKey = candidateKey;
475
+ }
476
+ }
477
+ if (oldestKey)
478
+ mirroredFileTextCache.delete(oldestKey);
479
+ }
480
+ mirroredFileTextCache.set(key, {
481
+ size: stat.size,
482
+ mtimeMs: stat.mtimeMs,
483
+ text,
484
+ accessedAt: Date.now(),
485
+ });
486
+ return text;
487
+ }
488
+ export function readRecentJsonlLines(filePath, maxBytes = MIRRORED_THREAD_HISTORY_FAST_MAX_BYTES) {
489
+ const safeMaxBytes = Math.max(1, Math.min(Math.floor(maxBytes), MIRRORED_THREAD_HISTORY_MAX_BYTES));
490
+ const stat = fs.statSync(filePath);
491
+ const cachedKey = jsonlCacheKey(['recent', filePath, safeMaxBytes]);
492
+ const cachedLines = getCachedJsonlLines(recentJsonlLineCache, cachedKey, stat);
493
+ if (cachedLines)
494
+ return cachedLines;
495
+ const size = stat.size;
423
496
  const readLength = Math.min(size, safeMaxBytes);
424
497
  const start = size - readLength;
425
498
  const fd = fs.openSync(filePath, 'r');
426
499
  try {
427
- const buffer = Buffer.alloc(readLength);
500
+ const buffer = Buffer.allocUnsafe(readLength);
428
501
  const bytesRead = fs.readSync(fd, buffer, 0, readLength, start);
429
502
  let text = buffer.subarray(0, bytesRead).toString('utf-8');
430
503
  if (start > 0) {
@@ -433,7 +506,14 @@ export function readRecentJsonlLines(filePath, maxBytes = MIRRORED_THREAD_HISTOR
433
506
  return [];
434
507
  text = text.slice(firstLineEnd + 1);
435
508
  }
436
- return text.split(/\r?\n/).filter(Boolean);
509
+ const lines = text.split(/\r?\n/).filter(Boolean);
510
+ return setCachedJsonlLines(recentJsonlLineCache, cachedKey, {
511
+ filePath,
512
+ size: stat.size,
513
+ mtimeMs: stat.mtimeMs,
514
+ maxBytes: safeMaxBytes,
515
+ lines,
516
+ });
437
517
  }
438
518
  finally {
439
519
  fs.closeSync(fd);
@@ -520,10 +600,15 @@ function codexAppServerEventChunk(method, params = {}) {
520
600
  },
521
601
  };
522
602
  }
523
- function readRecentCodexHistoryLines(filePath, targetMessages, maxBytes = MIRRORED_THREAD_HISTORY_MAX_BYTES) {
603
+ function readRecentCodexHistoryLines(filePath, targetMessages, maxBytes = MIRRORED_THREAD_HISTORY_FAST_MAX_BYTES) {
524
604
  const safeTargetMessages = Math.max(1, Math.min(Math.floor(targetMessages), 5_000));
525
605
  const safeMaxBytes = Math.max(1, Math.min(Math.floor(maxBytes), MIRRORED_THREAD_HISTORY_MAX_BYTES));
526
- const size = fs.statSync(filePath).size;
606
+ const stat = fs.statSync(filePath);
607
+ const cachedKey = jsonlCacheKey(['codex-history', filePath, safeTargetMessages, safeMaxBytes]);
608
+ const cachedLines = getCachedJsonlLines(recentCodexHistoryLineCache, cachedKey, stat);
609
+ if (cachedLines)
610
+ return cachedLines;
611
+ const size = stat.size;
527
612
  const fd = fs.openSync(filePath, 'r');
528
613
  try {
529
614
  let position = size;
@@ -531,7 +616,10 @@ function readRecentCodexHistoryLines(filePath, targetMessages, maxBytes = MIRROR
531
616
  let leadingPartial = '';
532
617
  let messageCount = 0;
533
618
  let collected = [];
534
- while (position > 0 && scannedBytes < safeMaxBytes && messageCount < safeTargetMessages) {
619
+ while (position > 0 &&
620
+ scannedBytes < safeMaxBytes &&
621
+ messageCount < safeTargetMessages &&
622
+ collected.length < MIRRORED_THREAD_HISTORY_FAST_MAX_LINES) {
535
623
  const readLength = Math.min(MIRRORED_THREAD_HISTORY_CHUNK_BYTES, position, safeMaxBytes - scannedBytes);
536
624
  position -= readLength;
537
625
  scannedBytes += readLength;
@@ -548,17 +636,25 @@ function readRecentCodexHistoryLines(filePath, targetMessages, maxBytes = MIRROR
548
636
  messageCount += historyLines.filter(isCodexVisibleUserHistoryLine).length;
549
637
  collected = [...historyLines, ...collected];
550
638
  }
551
- return collected.filter(Boolean);
639
+ const lines = collected.filter(Boolean);
640
+ return setCachedJsonlLines(recentCodexHistoryLineCache, cachedKey, {
641
+ filePath,
642
+ size: stat.size,
643
+ mtimeMs: stat.mtimeMs,
644
+ maxBytes: safeMaxBytes,
645
+ targetMessages: safeTargetMessages,
646
+ lines,
647
+ });
552
648
  }
553
649
  finally {
554
650
  fs.closeSync(fd);
555
651
  }
556
652
  }
557
653
  function readThreadIndex(limit) {
558
- const indexPath = path.join(localAgentHome(), 'session_index.jsonl');
654
+ const indexPath = path.join(localAgentHome(), 'thread_index.jsonl');
559
655
  if (!fs.existsSync(indexPath))
560
656
  return [];
561
- const lines = fs.readFileSync(indexPath, 'utf-8').split(/\r?\n/).filter(Boolean);
657
+ const lines = readRecentJsonlLines(indexPath);
562
658
  const byId = new Map();
563
659
  for (const line of lines) {
564
660
  const parsed = parseJsonLine(line);
@@ -651,8 +747,8 @@ function readThreadStateEntries(limit) {
651
747
  return [];
652
748
  }
653
749
  }
654
- let mirroredSessionFileIndexCache = null;
655
- function walkSessionFilesUncached(dir, out = new Map()) {
750
+ let mirroredThreadFileIndexCache = null;
751
+ function walkThreadFilesUncached(dir, out = new Map()) {
656
752
  if (!fs.existsSync(dir))
657
753
  return out;
658
754
  let entries;
@@ -665,7 +761,7 @@ function walkSessionFilesUncached(dir, out = new Map()) {
665
761
  for (const entry of entries) {
666
762
  const fullPath = path.join(dir, entry.name);
667
763
  if (entry.isDirectory()) {
668
- walkSessionFilesUncached(fullPath, out);
764
+ walkThreadFilesUncached(fullPath, out);
669
765
  continue;
670
766
  }
671
767
  if (!entry.isFile() || !entry.name.endsWith('.jsonl'))
@@ -676,15 +772,15 @@ function walkSessionFilesUncached(dir, out = new Map()) {
676
772
  }
677
773
  return out;
678
774
  }
679
- function walkSessionFiles(dir) {
775
+ function walkThreadFiles(dir) {
680
776
  const now = Date.now();
681
- if (mirroredSessionFileIndexCache &&
682
- mirroredSessionFileIndexCache.root === dir &&
683
- now - mirroredSessionFileIndexCache.indexedAt <= MIRRORED_THREAD_SESSION_FILE_INDEX_TTL_MS) {
684
- return new Map(mirroredSessionFileIndexCache.files);
777
+ if (mirroredThreadFileIndexCache &&
778
+ mirroredThreadFileIndexCache.root === dir &&
779
+ now - mirroredThreadFileIndexCache.indexedAt <= MIRRORED_THREAD_SESSION_FILE_INDEX_TTL_MS) {
780
+ return new Map(mirroredThreadFileIndexCache.files);
685
781
  }
686
- const files = walkSessionFilesUncached(dir);
687
- mirroredSessionFileIndexCache = {
782
+ const files = walkThreadFilesUncached(dir);
783
+ mirroredThreadFileIndexCache = {
688
784
  root: dir,
689
785
  indexedAt: now,
690
786
  files: new Map(files),
@@ -692,24 +788,33 @@ function walkSessionFiles(dir) {
692
788
  return files;
693
789
  }
694
790
  function readFileHead(filePath, maxBytes = 64 * 1024) {
791
+ const stat = fs.statSync(filePath);
792
+ const cacheKey = jsonlCacheKey(['head', filePath, maxBytes]);
793
+ const cached = getCachedFileText(cacheKey, stat);
794
+ if (cached !== null)
795
+ return cached;
695
796
  const fd = fs.openSync(filePath, 'r');
696
797
  try {
697
798
  const buffer = Buffer.alloc(maxBytes);
698
799
  const bytesRead = fs.readSync(fd, buffer, 0, maxBytes, 0);
699
- return buffer.subarray(0, bytesRead).toString('utf-8');
800
+ return setCachedFileText(cacheKey, stat, buffer.subarray(0, bytesRead).toString('utf-8'));
700
801
  }
701
802
  finally {
702
803
  fs.closeSync(fd);
703
804
  }
704
805
  }
705
806
  function readFileTail(filePath, maxBytes = 256 * 1024) {
807
+ const stat = fs.statSync(filePath);
808
+ const cacheKey = jsonlCacheKey(['tail', filePath, maxBytes]);
809
+ const cached = getCachedFileText(cacheKey, stat);
810
+ if (cached !== null)
811
+ return cached;
706
812
  const fd = fs.openSync(filePath, 'r');
707
813
  try {
708
- const stat = fs.fstatSync(fd);
709
814
  const length = Math.min(maxBytes, stat.size);
710
815
  const buffer = Buffer.alloc(length);
711
816
  fs.readSync(fd, buffer, 0, length, Math.max(0, stat.size - length));
712
- return buffer.toString('utf-8');
817
+ return setCachedFileText(cacheKey, stat, buffer.toString('utf-8'));
713
818
  }
714
819
  finally {
715
820
  fs.closeSync(fd);
@@ -752,7 +857,7 @@ function readThreadWorkspacePath(filePath) {
752
857
  if (!line.trim())
753
858
  continue;
754
859
  const parsed = parseJsonLine(line);
755
- if (parsed?.type !== 'session_meta')
860
+ if (parsed?.type !== 'thread_meta')
756
861
  continue;
757
862
  const payload = parsed.payload && typeof parsed.payload === 'object'
758
863
  ? parsed.payload
@@ -1009,7 +1114,7 @@ function readMirroredThreadStatus(threadId, filePath) {
1009
1114
  return 'running';
1010
1115
  }
1011
1116
  catch {
1012
- // Fall back to the Codex session file status below.
1117
+ // Fall back to the Codex thread file status below.
1013
1118
  }
1014
1119
  return readThreadStatus(filePath);
1015
1120
  }
@@ -1106,18 +1211,19 @@ function readMirroredTaskProjects(limit = MIRRORED_THREAD_LIMIT) {
1106
1211
  const safeLimit = Math.max(1, Math.min(limit, 200));
1107
1212
  const stateEntries = readThreadStateEntries(safeLimit);
1108
1213
  const indexEntries = readThreadIndex(safeLimit);
1109
- const sessionFiles = walkSessionFiles(path.join(localAgentHome(), 'sessions'));
1214
+ const indexEntriesById = new Map(indexEntries.map((entry) => [entry.id, entry]));
1215
+ const threadFiles = walkThreadFiles(path.join(localAgentHome(), 'threads'));
1110
1216
  const projects = new Map();
1111
1217
  if (stateEntries.length > 0) {
1112
1218
  for (const entry of stateEntries) {
1113
- const sessionPath = sessionFiles.get(entry.id) || null;
1114
- if (!sessionPath)
1219
+ const threadPath = threadFiles.get(entry.id) || null;
1220
+ if (!threadPath)
1115
1221
  continue;
1116
- const workspacePath = entry.cwd || readThreadWorkspacePath(sessionPath);
1222
+ const workspacePath = entry.cwd || readThreadWorkspacePath(threadPath);
1117
1223
  if (!isMirrorableCodexWorkspace(workspacePath))
1118
1224
  continue;
1119
1225
  const projectId = workspacePath || 'no-workspace';
1120
- const indexEntry = readThreadIndexEntry(entry.id);
1226
+ const indexEntry = indexEntriesById.get(entry.id) || null;
1121
1227
  const title = indexEntry?.thread_name || entry.title;
1122
1228
  if (isAutomationRunThreadTitle(title))
1123
1229
  continue;
@@ -1131,8 +1237,8 @@ function readMirroredTaskProjects(limit = MIRRORED_THREAD_LIMIT) {
1131
1237
  id: entry.id,
1132
1238
  title,
1133
1239
  updated_at: entry.updated_at,
1134
- status: readMirroredThreadStatus(entry.id, sessionPath),
1135
- session_path: sessionPath,
1240
+ status: readMirroredThreadStatus(entry.id, threadPath),
1241
+ thread_path: threadPath,
1136
1242
  });
1137
1243
  projects.set(projectId, project);
1138
1244
  }
@@ -1145,8 +1251,8 @@ function readMirroredTaskProjects(limit = MIRRORED_THREAD_LIMIT) {
1145
1251
  };
1146
1252
  }
1147
1253
  for (const entry of indexEntries) {
1148
- const sessionPath = sessionFiles.get(entry.id) || null;
1149
- const workspacePath = readThreadWorkspacePath(sessionPath);
1254
+ const threadPath = threadFiles.get(entry.id) || null;
1255
+ const workspacePath = readThreadWorkspacePath(threadPath);
1150
1256
  if (!isMirrorableCodexWorkspace(workspacePath))
1151
1257
  continue;
1152
1258
  if (isAutomationRunThreadTitle(entry.thread_name))
@@ -1162,8 +1268,8 @@ function readMirroredTaskProjects(limit = MIRRORED_THREAD_LIMIT) {
1162
1268
  id: entry.id,
1163
1269
  title: entry.thread_name,
1164
1270
  updated_at: entry.updated_at,
1165
- status: readMirroredThreadStatus(entry.id, sessionPath),
1166
- session_path: sessionPath,
1271
+ status: readMirroredThreadStatus(entry.id, threadPath),
1272
+ thread_path: threadPath,
1167
1273
  });
1168
1274
  projects.set(projectId, project);
1169
1275
  }
@@ -1298,10 +1404,10 @@ function isMirroredGoalContextMessage(text) {
1298
1404
  const trimmed = text.trim();
1299
1405
  return trimmed.startsWith('<goal_context>') && trimmed.endsWith('</goal_context>');
1300
1406
  }
1301
- function mirroredThreadWorkspacePath(sessionPath, stateEntry) {
1407
+ function mirroredThreadWorkspacePath(threadPath, stateEntry) {
1302
1408
  const stateCwd = typeof stateEntry?.cwd === 'string' ? stateEntry.cwd : null;
1303
- const sessionWorkspace = readThreadWorkspacePath(sessionPath);
1304
- for (const candidate of [stateCwd, sessionWorkspace]) {
1409
+ const threadWorkspace = readThreadWorkspacePath(threadPath);
1410
+ for (const candidate of [stateCwd, threadWorkspace]) {
1305
1411
  if (candidate && isMirrorableCodexWorkspace(candidate))
1306
1412
  return candidate;
1307
1413
  }
@@ -1356,16 +1462,16 @@ function collapseCompletedAssistantProgressMessages(input) {
1356
1462
  }
1357
1463
  export function readCodexThreadHistory(threadId, limit = MIRRORED_THREAD_HISTORY_LIMIT, options = {}) {
1358
1464
  const safeLimit = Math.max(1, Math.min(limit, 1000));
1359
- const sessionPath = walkSessionFiles(path.join(localAgentHome(), 'sessions')).get(threadId);
1360
- if (!sessionPath)
1465
+ const threadPath = walkThreadFiles(path.join(localAgentHome(), 'threads')).get(threadId);
1466
+ if (!threadPath)
1361
1467
  return null;
1362
1468
  const eventLogThreadId = options.eventLogThreadId || threadId;
1363
1469
  const stateEntry = readThreadStateEntry(threadId);
1364
- const workspacePath = mirroredThreadWorkspacePath(sessionPath, stateEntry);
1470
+ const workspacePath = mirroredThreadWorkspacePath(threadPath, stateEntry);
1365
1471
  const indexEntry = readThreadIndexEntry(threadId);
1366
1472
  const eventLogHead = readThreadEventLogHead(eventLogThreadId);
1367
1473
  const historyLineTarget = Math.min(250, Math.max(3, Math.ceil(safeLimit / 4)));
1368
- const lines = readRecentCodexHistoryLines(sessionPath, historyLineTarget);
1474
+ const lines = readRecentCodexHistoryLines(threadPath, historyLineTarget);
1369
1475
  const messages = [];
1370
1476
  const events = [];
1371
1477
  let messageIndex = 0;
@@ -1573,7 +1679,7 @@ export function readCodexThreadHistory(threadId, limit = MIRRORED_THREAD_HISTORY
1573
1679
  const collapsedMessages = collapseCompletedAssistantProgressMessages(messages);
1574
1680
  const slicedMessages = collapsedMessages.slice(-safeLimit);
1575
1681
  const slicedEvents = events.slice(-safeLimit * 8);
1576
- const status = readMirroredThreadStatus(eventLogThreadId, sessionPath);
1682
+ const status = readMirroredThreadStatus(eventLogThreadId, threadPath);
1577
1683
  const latestGoalContext = recentGoalContext;
1578
1684
  const context = readThreadContext({
1579
1685
  threadId,
@@ -1581,7 +1687,7 @@ export function readCodexThreadHistory(threadId, limit = MIRRORED_THREAD_HISTORY
1581
1687
  workspace: workspacePath,
1582
1688
  });
1583
1689
  return {
1584
- session: {
1690
+ thread: {
1585
1691
  task_id: threadId,
1586
1692
  agent_id: 'codex',
1587
1693
  channel: 'local-agent',
@@ -1611,19 +1717,19 @@ export function readCodexThreadHistory(threadId, limit = MIRRORED_THREAD_HISTORY
1611
1717
  ...(latestGoalContext ? { goal_context: latestGoalContext } : {}),
1612
1718
  };
1613
1719
  }
1614
- function serializeAdoptedMirroredThread(session) {
1720
+ function serializeAdoptedMirroredThread(thread) {
1615
1721
  return {
1616
- id: session.session_id,
1617
- taskId: session.session_id,
1618
- agentId: session.agent_id,
1619
- status: session.status || 'idle',
1620
- title: session.title,
1621
- createdAt: session.created_at,
1622
- updatedAt: session.updated_at,
1722
+ id: thread.thread_id,
1723
+ taskId: thread.thread_id,
1724
+ agentId: thread.agent_id,
1725
+ status: thread.status || 'idle',
1726
+ title: thread.title,
1727
+ createdAt: thread.created_at,
1728
+ updatedAt: thread.updated_at,
1623
1729
  supen: {
1624
- channel: session.channel,
1625
- sourceRef: session.source_ref,
1626
- taskWorkspaceFolder: session.task_workspace_folder,
1730
+ channel: thread.channel,
1731
+ sourceRef: thread.source_ref,
1732
+ taskWorkspaceFolder: thread.task_workspace_folder,
1627
1733
  },
1628
1734
  };
1629
1735
  }
@@ -1631,23 +1737,23 @@ function adoptMirroredThread(threadId, agentId) {
1631
1737
  const history = readCodexThreadHistory(threadId, 1);
1632
1738
  if (!history)
1633
1739
  return null;
1634
- const historySession = history.session;
1635
- const session = ensureSession({
1740
+ const historyThread = history.thread;
1741
+ const thread = ensureThread({
1636
1742
  agent_id: agentId,
1637
- session_id: threadId,
1743
+ thread_id: threadId,
1638
1744
  channel: 'http',
1639
1745
  agent_name: agentId,
1640
1746
  source_ref: `local-agent:${threadId}`,
1641
- title: typeof historySession.title === 'string' ? historySession.title : undefined,
1642
- status: historySession.status === 'running' ? 'running' : 'idle',
1747
+ title: typeof historyThread.title === 'string' ? historyThread.title : undefined,
1748
+ status: historyThread.status === 'running' ? 'running' : 'idle',
1643
1749
  backend_driver_id: 'codex-app-server',
1644
- task_workspace_folder: typeof historySession.task_workspace_folder === 'string'
1645
- ? historySession.task_workspace_folder
1750
+ task_workspace_folder: typeof historyThread.task_workspace_folder === 'string'
1751
+ ? historyThread.task_workspace_folder
1646
1752
  : null,
1647
1753
  });
1648
- updateSessionSdkId(agentId, threadId, threadId);
1649
- updateSessionBackendDriverId(agentId, threadId, 'codex-app-server');
1650
- return session;
1754
+ updateThreadSdkSessionId(agentId, threadId, threadId);
1755
+ updateThreadBackendDriverId(agentId, threadId, 'codex-app-server');
1756
+ return thread;
1651
1757
  }
1652
1758
  function coerceSingleQueryParam(value) {
1653
1759
  if (Array.isArray(value))
@@ -1670,24 +1776,24 @@ function collectSpaceLogEntries(filters = {}) {
1670
1776
  const agents = getAllAgents()
1671
1777
  // Single-Computer runtime: include all agents in this mounted volume.
1672
1778
  .sort((a, b) => (a.name || a.agent_id).localeCompare(b.name || b.agent_id));
1673
- const sessions = agents.flatMap((agent) => getSessionsForAgent(agent.agent_id)
1674
- .map((session) => ({
1779
+ const threads = agents.flatMap((agent) => getThreadsForAgent(agent.agent_id)
1780
+ .map((thread) => ({
1675
1781
  agent_id: agent.agent_id,
1676
1782
  agent_name: agent.name || null,
1677
- session_id: session.session_id,
1678
- status: session.status,
1679
- updated_at: session.updated_at,
1680
- title: session.title || null,
1783
+ thread_id: thread.thread_id,
1784
+ status: thread.status,
1785
+ updated_at: thread.updated_at,
1786
+ title: thread.title || null,
1681
1787
  })));
1682
- const filteredSessions = sessions.filter((session) => {
1683
- if (filters.agentId && session.agent_id !== filters.agentId)
1788
+ const filteredThreads = threads.filter((thread) => {
1789
+ if (filters.agentId && thread.agent_id !== filters.agentId)
1684
1790
  return false;
1685
- if (filters.sessionId && session.session_id !== filters.sessionId)
1791
+ if (filters.threadId && thread.thread_id !== filters.threadId)
1686
1792
  return false;
1687
1793
  return true;
1688
1794
  });
1689
- const entries = filteredSessions
1690
- .flatMap((session) => getSessionUiEvents(session.agent_id, session.session_id, limit).map((event) => {
1795
+ const entries = filteredThreads
1796
+ .flatMap((thread) => getThreadUiEvents(thread.agent_id, thread.thread_id, limit).map((event) => {
1691
1797
  const logSummary = event.chunk && typeof event.chunk === 'object'
1692
1798
  ? summarizeUiChunk(event.chunk)
1693
1799
  : null;
@@ -1695,10 +1801,10 @@ function collectSpaceLogEntries(filters = {}) {
1695
1801
  ? {
1696
1802
  id: event.id,
1697
1803
  timestamp: event.timestamp,
1698
- agent_id: session.agent_id,
1699
- agent_name: session.agent_name,
1700
- session_id: session.session_id,
1701
- session_title: session.title,
1804
+ agent_id: thread.agent_id,
1805
+ agent_name: thread.agent_name,
1806
+ thread_id: thread.thread_id,
1807
+ thread_title: thread.title,
1702
1808
  task_id: event.task_id || null,
1703
1809
  category: logSummary.category,
1704
1810
  summary: logSummary.summary,
@@ -1713,11 +1819,11 @@ function collectSpaceLogEntries(filters = {}) {
1713
1819
  generated_at: new Date().toISOString(),
1714
1820
  timezone: resolveHostTimeZone(),
1715
1821
  agents,
1716
- sessions,
1822
+ threads,
1717
1823
  entries,
1718
1824
  filters: {
1719
1825
  agent_id: filters.agentId || null,
1720
- session_id: filters.sessionId || null,
1826
+ thread_id: filters.threadId || null,
1721
1827
  },
1722
1828
  };
1723
1829
  }
@@ -2581,24 +2687,24 @@ export async function handleSystemRoutes(req, res, url, pathname, method) {
2581
2687
  }
2582
2688
  if (pathname === '/api/computers/{computer_id}/logs' && method === 'GET') {
2583
2689
  const agentId = coerceSingleQueryParam(url.searchParams.get('agent_id'));
2584
- const sessionId = coerceSingleQueryParam(url.searchParams.get('session_id'));
2690
+ const threadId = coerceSingleQueryParam(url.searchParams.get('thread_id'));
2585
2691
  const limitRaw = coerceSingleQueryParam(url.searchParams.get('limit'));
2586
2692
  const limit = limitRaw ? Number.parseInt(limitRaw, 10) : SPACE_LOG_EVENT_LIMIT;
2587
2693
  writeJson(res, 200, collectSpaceLogEntries({
2588
2694
  agentId: agentId?.trim() || null,
2589
- sessionId: sessionId?.trim() || null,
2695
+ threadId: threadId?.trim() || null,
2590
2696
  limit: Number.isFinite(limit) ? limit : SPACE_LOG_EVENT_LIMIT,
2591
2697
  }));
2592
2698
  return true;
2593
2699
  }
2594
2700
  if (pathname === '/api/computers/{computer_id}/logs/stream' && method === 'GET') {
2595
2701
  const agentId = coerceSingleQueryParam(url.searchParams.get('agent_id'));
2596
- const sessionId = coerceSingleQueryParam(url.searchParams.get('session_id'));
2702
+ const threadId = coerceSingleQueryParam(url.searchParams.get('thread_id'));
2597
2703
  const limitRaw = coerceSingleQueryParam(url.searchParams.get('limit'));
2598
2704
  const limit = limitRaw ? Number.parseInt(limitRaw, 10) : SPACE_LOG_EVENT_LIMIT;
2599
2705
  const filters = {
2600
2706
  agentId: agentId?.trim() || null,
2601
- sessionId: sessionId?.trim() || null,
2707
+ threadId: threadId?.trim() || null,
2602
2708
  limit: Number.isFinite(limit) ? limit : SPACE_LOG_EVENT_LIMIT,
2603
2709
  };
2604
2710
  res.writeHead(200, {
@@ -2881,7 +2987,7 @@ export async function handleSystemRoutes(req, res, url, pathname, method) {
2881
2987
  });
2882
2988
  return true;
2883
2989
  }
2884
- if (pathname === '/api/computers/{computer_id}/agents/codex/session' && method === 'DELETE') {
2990
+ if (pathname === '/api/computers/{computer_id}/agents/codex/thread' && method === 'DELETE') {
2885
2991
  const cmd = spawnSync('codex', ['logout'], {
2886
2992
  encoding: 'utf8',
2887
2993
  timeout: 15_000,
@@ -2976,10 +3082,10 @@ export async function handleSystemRoutes(req, res, url, pathname, method) {
2976
3082
  numericQueryParam(coerceSingleQueryParam(url.searchParams.get('after')));
2977
3083
  const replayAfter = afterSequence ?? readThreadEventLogHead(threadId);
2978
3084
  addThreadStreamClient(threadId, res);
2979
- const sessionPath = walkSessionFiles(path.join(localAgentHome(), 'sessions')).get(threadId);
2980
- let jsonlOffset = sessionPath && fs.existsSync(sessionPath) ? fs.statSync(sessionPath).size : 0;
3085
+ const threadPath = walkThreadFiles(path.join(localAgentHome(), 'threads')).get(threadId);
3086
+ let jsonlOffset = threadPath && fs.existsSync(threadPath) ? fs.statSync(threadPath).size : 0;
2981
3087
  let jsonlEventIndex = 0;
2982
- const workspacePath = readThreadWorkspacePath(sessionPath) || process.cwd();
3088
+ const workspacePath = readThreadWorkspacePath(threadPath) || process.cwd();
2983
3089
  const withThreadContext = (chunk) => attachThreadContextToChunk(chunk, readThreadContext({ threadId, workspace: workspacePath }));
2984
3090
  const stopCodexObserver = process.env.NODE_ENV === 'test'
2985
3091
  ? () => { }
@@ -2993,9 +3099,9 @@ export async function handleSystemRoutes(req, res, url, pathname, method) {
2993
3099
  res.flush?.();
2994
3100
  }, SPACE_LOG_STREAM_PING_MS);
2995
3101
  pingTimer.unref?.();
2996
- const jsonlPollTimer = sessionPath
3102
+ const jsonlPollTimer = threadPath
2997
3103
  ? setInterval(() => {
2998
- const read = readAppendedJsonlLines(sessionPath, jsonlOffset);
3104
+ const read = readAppendedJsonlLines(threadPath, jsonlOffset);
2999
3105
  jsonlOffset = read.offset;
3000
3106
  for (const line of read.lines) {
3001
3107
  if (!isCodexHistoryTranscriptLine(line))
@@ -3062,12 +3168,12 @@ export async function handleSystemRoutes(req, res, url, pathname, method) {
3062
3168
  : '';
3063
3169
  const fallbackAgentId = getAllAgents()[0]?.agent_id || 'codex';
3064
3170
  const agentId = requestedAgentId || fallbackAgentId;
3065
- const session = threadId ? adoptMirroredThread(threadId, agentId) : null;
3066
- if (!session) {
3171
+ const thread = threadId ? adoptMirroredThread(threadId, agentId) : null;
3172
+ if (!thread) {
3067
3173
  writeProtocolError(res, 404, 'not_found', 'mirrored_thread_not_found', 'Mirrored task history was not found.');
3068
3174
  return true;
3069
3175
  }
3070
- writeJson(res, 200, { thread: serializeAdoptedMirroredThread(session) });
3176
+ writeJson(res, 200, { thread: serializeAdoptedMirroredThread(thread) });
3071
3177
  return true;
3072
3178
  }
3073
3179
  if (codexProjectsOpenRoute(pathname) && method === 'POST') {