lark-remote 0.4.5 → 0.5.0

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 (124) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/dist/bridge/approval-coordinator.d.ts +1 -1
  3. package/dist/bridge/approval-coordinator.js +3 -3
  4. package/dist/bridge/inbound-media.js +10 -7
  5. package/dist/bridge/index.d.ts +9 -9
  6. package/dist/bridge/index.js +41 -41
  7. package/dist/bridge/queue-manager.d.ts +12 -12
  8. package/dist/bridge/queue-manager.js +19 -19
  9. package/dist/card/approval-render.d.ts +1 -1
  10. package/dist/card/approval-render.js +6 -6
  11. package/dist/card/bash-card-session.d.ts +3 -3
  12. package/dist/card/bash-card-session.js +3 -3
  13. package/dist/card/bash-renderer.js +1 -1
  14. package/dist/card/card-session.d.ts +4 -4
  15. package/dist/card/card-session.js +6 -6
  16. package/dist/card/run-card-session.js +2 -2
  17. package/dist/card/run-renderer.d.ts +1 -1
  18. package/dist/card/run-renderer.js +14 -14
  19. package/dist/card/run-state.d.ts +2 -2
  20. package/dist/card/run-state.js +3 -3
  21. package/dist/card/tool-render.d.ts +1 -1
  22. package/dist/card/tool-render.js +6 -6
  23. package/dist/clone.d.ts +5 -3
  24. package/dist/clone.js +8 -4
  25. package/dist/common/truncate.d.ts +1 -1
  26. package/dist/common/truncate.js +2 -2
  27. package/dist/common/ttl-cache.d.ts +2 -2
  28. package/dist/common/ttl-cache.js +2 -2
  29. package/dist/config/codex-config.d.ts +9 -9
  30. package/dist/config/codex-config.js +18 -18
  31. package/dist/config/dir.js +5 -2
  32. package/dist/config/index.d.ts +3 -3
  33. package/dist/config/index.js +6 -6
  34. package/dist/config/opencode-config.js +3 -3
  35. package/dist/connector/index.d.ts +5 -5
  36. package/dist/connector/index.js +24 -11
  37. package/dist/inbound/event.d.ts +1 -1
  38. package/dist/inbound/event.js +1 -1
  39. package/dist/inbound/placeholder.d.ts +2 -2
  40. package/dist/inbound/placeholder.js +2 -2
  41. package/dist/index.js +9 -9
  42. package/dist/instance-lock.js +4 -3
  43. package/dist/logger/index.d.ts +1 -1
  44. package/dist/logger/index.js +4 -4
  45. package/dist/persistence/atomic-write.d.ts +1 -1
  46. package/dist/persistence/atomic-write.js +6 -2
  47. package/dist/platform/agent-stopper.d.ts +1 -1
  48. package/dist/platform/identity.d.ts +7 -1
  49. package/dist/platform/identity.js +2 -2
  50. package/dist/platform/path.d.ts +6 -0
  51. package/dist/platform/path.js +14 -8
  52. package/dist/platform/select.d.ts +1 -1
  53. package/dist/platform/select.js +1 -1
  54. package/dist/platform/shell.d.ts +2 -3
  55. package/dist/platform/spawn.d.ts +2 -2
  56. package/dist/platform/spawn.js +2 -2
  57. package/dist/platform/terminator-posix.js +1 -1
  58. package/dist/platform/terminator-win32.js +2 -2
  59. package/dist/platform/terminator.d.ts +3 -3
  60. package/dist/platform/terminator.js +2 -2
  61. package/dist/platform/types.d.ts +1 -1
  62. package/dist/restart.d.ts +1 -1
  63. package/dist/restart.js +5 -3
  64. package/dist/router/config/codex.d.ts +1 -1
  65. package/dist/router/config/codex.js +2 -2
  66. package/dist/router/config/opencode.js +1 -1
  67. package/dist/router/index.d.ts +9 -9
  68. package/dist/router/index.js +34 -34
  69. package/dist/router/order-exec-dispatch.js +2 -2
  70. package/dist/runner/bash/runner.d.ts +2 -2
  71. package/dist/runner/bash/runner.js +6 -6
  72. package/dist/runner/claude/runner.js +1 -1
  73. package/dist/runner/claude/session.d.ts +2 -2
  74. package/dist/runner/claude/session.js +14 -14
  75. package/dist/runner/codex/app-server/runner.js +3 -3
  76. package/dist/runner/codex/app-server/translator.d.ts +2 -2
  77. package/dist/runner/codex/app-server/translator.js +5 -5
  78. package/dist/runner/common/acp/acp-approval.d.ts +2 -2
  79. package/dist/runner/common/acp/acp-approval.js +3 -3
  80. package/dist/runner/common/acp/base-acp-runner.js +1 -1
  81. package/dist/runner/common/acp/base-translator.d.ts +3 -3
  82. package/dist/runner/common/acp/base-translator.js +4 -4
  83. package/dist/runner/common/acp/protocol-types.js +1 -1
  84. package/dist/runner/common/connection-based-runner.d.ts +1 -1
  85. package/dist/runner/common/connection-based-runner.js +2 -2
  86. package/dist/runner/common/jsonl-stream.d.ts +2 -2
  87. package/dist/runner/common/jsonl-stream.js +12 -12
  88. package/dist/runner/common/jsonrpc/client.d.ts +1 -1
  89. package/dist/runner/common/jsonrpc/client.js +1 -1
  90. package/dist/runner/common/jsonrpc/connection-manager.d.ts +1 -1
  91. package/dist/runner/common/jsonrpc/connection-manager.js +1 -1
  92. package/dist/runner/common/jsonrpc/transport.d.ts +1 -1
  93. package/dist/runner/common/jsonrpc/transport.js +2 -2
  94. package/dist/runner/common/spawning-runner.d.ts +21 -8
  95. package/dist/runner/common/spawning-runner.js +41 -15
  96. package/dist/runner/dsh/runner.js +2 -2
  97. package/dist/runner/kimi/acp/runner.d.ts +3 -3
  98. package/dist/runner/kimi/acp/runner.js +9 -9
  99. package/dist/runner/kimi/acp/translator.d.ts +2 -2
  100. package/dist/runner/kimi/acp/translator.js +4 -4
  101. package/dist/runner/opencode/acp/runner.d.ts +2 -2
  102. package/dist/runner/opencode/acp/runner.js +3 -3
  103. package/dist/runner/opencode/acp/translator.js +1 -1
  104. package/dist/runner/pi/rpc/runner.js +2 -2
  105. package/dist/runner/pi/rpc/translator.d.ts +1 -1
  106. package/dist/runner/pi/rpc/translator.js +4 -4
  107. package/dist/runner/types.d.ts +1 -1
  108. package/dist/session/claude/session-index.d.ts +12 -0
  109. package/dist/session/claude/session-index.js +20 -5
  110. package/dist/session/claude/sessions.js +10 -10
  111. package/dist/session/codex/rollout-reader.d.ts +4 -4
  112. package/dist/session/codex/rollout-reader.js +12 -12
  113. package/dist/session/common/two-pass.js +2 -2
  114. package/dist/session/common/usage-accumulator.d.ts +2 -2
  115. package/dist/session/common/usage-accumulator.js +2 -2
  116. package/dist/session/dsh/sessions.js +2 -2
  117. package/dist/session/kimi/sessions.d.ts +2 -2
  118. package/dist/session/kimi/sessions.js +11 -11
  119. package/dist/session/opencode/sessions.d.ts +3 -3
  120. package/dist/session/opencode/sessions.js +12 -10
  121. package/dist/session/pi/sessions.js +13 -12
  122. package/dist/session/session-store.d.ts +1 -1
  123. package/dist/session/session-store.js +1 -1
  124. package/package.json +1 -1
@@ -104,7 +104,7 @@ export declare class KimiSessionReader implements AgentSessionReader {
104
104
  readCompactionRecords(sessionId: string, cwd: string): KimiCompactionRecord[];
105
105
  /**
106
106
  * 由 begin/terminal 记录重建压缩状态机:最后一次 begin 无更新的 terminal
107
- * 记录 = 在途(kimi-compact-wait-redesign §5.1)。崩溃墓碑由 kimi resume
107
+ * 记录 = 在途。崩溃墓碑由 kimi resume
108
108
  * 时补写 full_compaction.cancel,天然闭合。
109
109
  */
110
110
  readCompactionState(sessionId: string, cwd: string): {
@@ -114,7 +114,7 @@ export declare class KimiSessionReader implements AgentSessionReader {
114
114
  records: KimiCompactionRecord[];
115
115
  };
116
116
  /**
117
- * W2.5 单源:resolveSessionWirePath 与 isSessionActive 共用的 cwd 守卫
117
+ * 单源:resolveSessionWirePath 与 isSessionActive 共用的 cwd 守卫
118
118
  * (realpathSync → state.json workDir/cwd 三态 → index workDir 兜底 →
119
119
  * fail-closed)。返回 sessionDir;会话未知或守卫不过返回 null。
120
120
  */
@@ -78,7 +78,7 @@ function readJsonlLines(filePath) {
78
78
  try {
79
79
  const stat = fs.statSync(filePath);
80
80
  const mtime = stat.mtimeMs;
81
- // P1-17: TTL 由 TtlCache 按缓存写入时间判定(不是文件 mtime),命中即 LRU 刷新;
81
+ // TTL 由 TtlCache 按缓存写入时间判定(不是文件 mtime),命中即 LRU 刷新;
82
82
  // mtime 变化视为失效(文件被改写后不得返回旧行)。
83
83
  const cached = jsonlCache.get(filePath);
84
84
  if (cached && mtime === cached.mtime) {
@@ -204,7 +204,7 @@ export class KimiSessionReader {
204
204
  const realCwd = fs.realpathSync(cwd);
205
205
  const sessions = [];
206
206
  for (const entry of this.scanSessionIndex()) {
207
- // W2.7:state.json 一次读取共用(cwd 兜底 + summary),I/O 减半。
207
+ // state.json 一次读取共用(cwd 兜底 + summary),I/O 减半。
208
208
  // 两次 catch 语义保留:解析失败 = 无法判 cwd → 跳过(continue);
209
209
  // 解析成功但字段缺失 = summary 落 wire.jsonl 提取。
210
210
  const statePath = path.join(entry.sessionDir, 'state.json');
@@ -242,7 +242,7 @@ export class KimiSessionReader {
242
242
  const wirePath = path.join(entry.sessionDir, 'agents', 'main', 'wire.jsonl');
243
243
  summary = this.extractLastPromptFromWire(wirePath) || 'New Session';
244
244
  }
245
- // Get mtime. P1-16: the session DIRECTORY mtime only changes when
245
+ // Get mtime. the session DIRECTORY mtime only changes when
246
246
  // entries are created/deleted/renamed inside it — kimi appending to
247
247
  // agents/main/wire.jsonl during a run does NOT touch it, so dir-mtime
248
248
  // sorting lags real activity by minutes. Use the wire.jsonl mtime
@@ -332,7 +332,7 @@ export class KimiSessionReader {
332
332
  cacheCreation: inputCacheCreation,
333
333
  });
334
334
  if (updateContextLength) {
335
- // review P2-8 unified contract: input + cacheRead + cacheCreation
335
+ // unified contract: input + cacheRead + cacheCreation
336
336
  // (excludes output — generated, not part of the input window).
337
337
  mainContextLength = inputOther + inputCacheRead + inputCacheCreation;
338
338
  }
@@ -350,7 +350,7 @@ export class KimiSessionReader {
350
350
  // 展示计数只计 context.apply_compaction:一次手动 /compact 会同时写
351
351
  // full_compaction.complete + context.apply_compaction 两条(2026-08-16
352
352
  // 实弹 wire.jsonl),双计会把一次压缩虚报成 2 次。full_compaction.complete
353
- // 仅作 R2 runCompact 轮询的完成信号(readCompactionRecords 仍返回两种)。
353
+ // 仅作 runCompact 轮询的完成信号(readCompactionRecords 仍返回两种)。
354
354
  if (isCompactionComplete(entry) && entry.type === 'context.apply_compaction') {
355
355
  compactCount++;
356
356
  // Capture context length before this compaction as the pre-compact
@@ -360,7 +360,7 @@ export class KimiSessionReader {
360
360
  }
361
361
  continue;
362
362
  }
363
- // P2-7: displayTitle + display events now scan ALL lines (not a
363
+ // displayTitle + display events now scan ALL lines (not a
364
364
  // line-slice), then `events.slice(-maxEvents)` keeps the LAST N
365
365
  // EVENTS. Previously `lines.slice(-maxEvents)` cut raw lines, but
366
366
  // usage.record / step.begin / turn.prompt lines produce no display
@@ -402,7 +402,7 @@ export class KimiSessionReader {
402
402
  }
403
403
  else if (evt.type === 'tool.result') {
404
404
  // result is { output }, { output, note }, or { isError, output }
405
- // 对齐 opencode reader 的 L2 预折叠:单条 tool_result 上限
405
+ // 对齐 opencode reader 的预折叠:单条 tool_result 上限
406
406
  // TOOL_RESULT_MAX_BYTES,病理级输出(如 51KB 文件读取)不会
407
407
  // 撑爆 resume 卡,也约束 events[] 内存占用。
408
408
  const rawOut = evt.result?.output ?? `[tool result for ${evt.toolCallId}]`;
@@ -523,7 +523,7 @@ export class KimiSessionReader {
523
523
  }
524
524
  /**
525
525
  * 由 begin/terminal 记录重建压缩状态机:最后一次 begin 无更新的 terminal
526
- * 记录 = 在途(kimi-compact-wait-redesign §5.1)。崩溃墓碑由 kimi resume
526
+ * 记录 = 在途。崩溃墓碑由 kimi resume
527
527
  * 时补写 full_compaction.cancel,天然闭合。
528
528
  */
529
529
  readCompactionState(sessionId, cwd) {
@@ -545,7 +545,7 @@ export class KimiSessionReader {
545
545
  };
546
546
  }
547
547
  /**
548
- * W2.5 单源:resolveSessionWirePath 与 isSessionActive 共用的 cwd 守卫
548
+ * 单源:resolveSessionWirePath 与 isSessionActive 共用的 cwd 守卫
549
549
  * (realpathSync → state.json workDir/cwd 三态 → index workDir 兜底 →
550
550
  * fail-closed)。返回 sessionDir;会话未知或守卫不过返回 null。
551
551
  */
@@ -626,7 +626,7 @@ export class KimiSessionReader {
626
626
  * Check if a session is currently active
627
627
  */
628
628
  isSessionActive(sessionId, cwd) {
629
- // W2.5:cwd 守卫与 resolveSessionWirePath 共用 verifySessionCwd(单源)。
629
+ // cwd 守卫与 resolveSessionWirePath 共用 verifySessionCwd(单源)。
630
630
  const verified = this.verifySessionCwd(sessionId, cwd);
631
631
  if (!verified)
632
632
  return false;
@@ -644,7 +644,7 @@ export class KimiSessionReader {
644
644
  // Read the tail to check for active indicators. kimi appends
645
645
  // usage.record after step.end at turn completion, so the last loop
646
646
  // event (not the last line) decides whether the session is complete.
647
- // P2-5: `lastLoopEventIsStepEnd` only scans backwards up to
647
+ // `lastLoopEventIsStepEnd` only scans backwards up to
648
648
  // LOOP_EVENT_SCAN_LIMIT lines, so we read only that many trailing lines
649
649
  // via the tail-only helper instead of full-slurping the whole wire log
650
650
  // (which can be multi-MB) into a string[].
@@ -20,7 +20,7 @@ interface OpencodeSessionReaderOptions {
20
20
  /**
21
21
  * Override the raw `opencode export <id>` capture (returns the JSON string).
22
22
  * Default routes stdout to a temp file fd to bypass opencode's ~128KB pipe
23
- * truncation on large sessions (L1). Injectable for testing.
23
+ * truncation on large sessions. Injectable for testing.
24
24
  */
25
25
  captureExport?: (sessionId: string) => string;
26
26
  }
@@ -65,12 +65,12 @@ export declare class OpencodeSessionReader implements AgentSessionReader {
65
65
  /**
66
66
  * Capture raw `opencode export <sessionId>` output (JSON string). Injectable
67
67
  * via the constructor; the default routes stdout to a temp file fd to bypass
68
- * opencode's ~128KB pipe truncation on large sessions (L1).
68
+ * opencode's ~128KB pipe truncation on large sessions.
69
69
  */
70
70
  /** 导出会话内容(public:测试直接调用,替代 as unknown as)。 */
71
71
  captureExport(sessionId: string): string;
72
72
  /**
73
- * L1 default transport: run `opencode export` with stdout pointed at a
73
+ * default transport: run `opencode export` with stdout pointed at a
74
74
  * regular-file fd (NOT a pipe). opencode truncates piped stdout at ~128KB for
75
75
  * large sessions (huge tool_results), breaking JSON.parse; a file fd receives
76
76
  * the full output (verified: 1.3MB parses OK). execFileSync returns null when
@@ -57,7 +57,7 @@ export class OpencodeSessionReader {
57
57
  sessions: items.map((e) => ({
58
58
  sessionId: e.id,
59
59
  // CLI title 字段形状不保证恒为 string(null/缺字段时 router 的
60
- // s.summary.trim() 会 TypeError)——非 string 给空串(Review R3 P3-3)。
60
+ // s.summary.trim() 会 TypeError)——非 string 给空串(Review)。
61
61
  summary: typeof e.title === 'string' ? e.title : '',
62
62
  mtime: e.updated,
63
63
  })),
@@ -75,7 +75,7 @@ export class OpencodeSessionReader {
75
75
  */
76
76
  readSessionContent(sessionId, cwd, opts) {
77
77
  const realCwd = this.realpath(cwd);
78
- // L1/L3: capture raw export via the injectable seam, then parse. Distinguish
78
+ // capture raw export via the injectable seam, then parse. Distinguish
79
79
  // a truly-missing session (empty capture) from a truncated/corrupt one
80
80
  // (non-empty but unparseable) so we never show the misleading "未找到" for
81
81
  // a session whose content is merely too large to pipe through stdout.
@@ -100,7 +100,9 @@ export class OpencodeSessionReader {
100
100
  return { events: [] };
101
101
  }
102
102
  try {
103
- if (data.info.directory !== realCwd) {
103
+ // 与 listSessions 的过滤同口径(PathKit.samePath):export 里的 directory
104
+ // 形态由 opencode 自行记录,裸 !== 会让会话列得出却读不出(win32 常态)
105
+ if (!samePath(data.info.directory, realCwd)) {
104
106
  return { events: [] };
105
107
  }
106
108
  const events = [];
@@ -160,7 +162,7 @@ export class OpencodeSessionReader {
160
162
  const rawOut = isError
161
163
  ? (part.state.error ?? part.state.output)
162
164
  : (part.state.output ?? '');
163
- // L2: pre-fold pathological tool_results (e.g. a 500KB file
165
+ // pre-fold pathological tool_results (e.g. a 500KB file
164
166
  // listing) via the shared truncateUtf8 primitive, reusing the
165
167
  // same …(已截断) suffix as the live renderer / card budget.
166
168
  events.push({
@@ -183,7 +185,7 @@ export class OpencodeSessionReader {
183
185
  // ccusage-aligned: cache.write -> cacheCreationTokens.
184
186
  // contextLength = input + cacheRead + cacheCreation (excludes
185
187
  // output/reasoning) — the unified context-window occupancy
186
- // contract across all five readers (review P2-8).
188
+ // contract across all five readers.
187
189
  if ((part.tokens.total ?? 0) !== 0) {
188
190
  usage = {
189
191
  inputTokens: part.tokens.input,
@@ -317,7 +319,7 @@ export class OpencodeSessionReader {
317
319
  const res = spawnProcessSync(this.binary, ['session', 'list', '--format', 'json'], {
318
320
  encoding: 'utf-8',
319
321
  timeout: 10000,
320
- // P1-15: default maxBuffer is 1MiB — a large session list (>1MiB JSON)
322
+ // default maxBuffer is 1MiB — a large session list (>1MiB JSON)
321
323
  // throws ENOBUFS, which the catch below silently turns into [] and the
322
324
  // user sees "no sessions" even though the CLI returned healthy data.
323
325
  maxBuffer: 64 * 1024 * 1024,
@@ -345,7 +347,7 @@ export class OpencodeSessionReader {
345
347
  return data;
346
348
  }
347
349
  catch (err) {
348
- // P1-15: 区分「读取失败」与「真空/陈旧 cwd」。
350
+ // 区分「读取失败」与「真空/陈旧 cwd」。
349
351
  // - ENOENT(cwd 已删除或 binary 缺失):沿用既有契约返回 []——/resume 对
350
352
  // 陈旧 cwd 保持优雅(sessions.test.ts「Stale-cwd coverage gap」+ round10
351
353
  // 探针的跨 reader 空目录不变量都钉死此行为)。
@@ -362,7 +364,7 @@ export class OpencodeSessionReader {
362
364
  /**
363
365
  * Capture raw `opencode export <sessionId>` output (JSON string). Injectable
364
366
  * via the constructor; the default routes stdout to a temp file fd to bypass
365
- * opencode's ~128KB pipe truncation on large sessions (L1).
367
+ * opencode's ~128KB pipe truncation on large sessions.
366
368
  */
367
369
  /** 导出会话内容(public:测试直接调用,替代 as unknown as)。 */
368
370
  captureExport(sessionId) {
@@ -371,7 +373,7 @@ export class OpencodeSessionReader {
371
373
  return this.captureExportViaFileFd(sessionId);
372
374
  }
373
375
  /**
374
- * L1 default transport: run `opencode export` with stdout pointed at a
376
+ * default transport: run `opencode export` with stdout pointed at a
375
377
  * regular-file fd (NOT a pipe). opencode truncates piped stdout at ~128KB for
376
378
  * large sessions (huge tool_results), breaking JSON.parse; a file fd receives
377
379
  * the full output (verified: 1.3MB parses OK). execFileSync returns null when
@@ -386,7 +388,7 @@ export class OpencodeSessionReader {
386
388
  encoding: 'utf-8',
387
389
  timeout: 30000,
388
390
  stdio: ['ignore', fd, 'pipe'],
389
- // P1-15: stderr is piped here; without maxBuffer a chatty CLI (>1MiB
391
+ // stderr is piped here; without maxBuffer a chatty CLI (>1MiB
390
392
  // stderr) would throw ENOBUFS and lose the export. Keep the default
391
393
  // stdout file-fd transport unaffected by raising the pipe cap.
392
394
  maxBuffer: 64 * 1024 * 1024,
@@ -6,7 +6,7 @@ import { scanJsonlOnce, tailOffsetAfter, scanTailEvents } from '../common/two-pa
6
6
  import { extractContentBlocks } from '../common/content-blocks.js';
7
7
  import { UsageAccumulator, contextWindowOccupancy, cumulativeUsageFields, } from '../common/usage-accumulator.js';
8
8
  import { isStale } from '../common/constants.js';
9
- import { encodeProjectDirName } from '../../platform/path.js';
9
+ import { encodeProjectDirName, samePath } from '../../platform/path.js';
10
10
  import { paginate } from '../common/pagination.js';
11
11
  import { sortByRecencyDesc } from '../common/recency.js';
12
12
  import { TtlCache } from '../../common/ttl-cache.js';
@@ -26,7 +26,7 @@ function projectDirForCwd(cwd, sessionsDir) {
26
26
  return path.join(sessionsDir, encoded);
27
27
  }
28
28
  /**
29
- * P1-19: TTL cache for pi directory scans (mirror codex getSessionIndex's
29
+ * TTL cache for pi directory scans (mirror codex getSessionIndex's
30
30
  * 5s TTL). Repeated /resume pages re-scan the whole sessions dir per call.
31
31
  */
32
32
  const piListCache = new TtlCache(5_000, 32);
@@ -71,7 +71,7 @@ function compressSkillInjection(text) {
71
71
  }
72
72
  /** Get a one-line summary from a pi session JSONL (first user message text).
73
73
  *
74
- * P2-3 optimization: previously used `readJsonlLines` (full-file slurp)
74
+ * optimization: previously used `readJsonlLines` (full-file slurp)
75
75
  * just to get the first user message. Now uses `findJsonlLine` which
76
76
  * stops reading as soon as the predicate matches — typically only the
77
77
  * first few lines of the file, saving ~99% I/O on large sessions.
@@ -136,14 +136,14 @@ function findSessionFile(sessionId, cwd, sessionsDir) {
136
136
  return null;
137
137
  }
138
138
  /**
139
- * P2-6 + P2-5 first-pass scan: stream the file once via `scanJsonlLines`
139
+ * first-pass scan: stream the file once via `scanJsonlLines`
140
140
  * (no `string[]` materialized), parse each line exactly once, and collect
141
141
  * all metadata needed by readSessionContent (usage, tailOffset, displayTitle).
142
142
  * Does NOT retain parsed objects — the events tail is re-parsed separately
143
143
  * by `extractPiEventsFromTail` so memory for both raw line strings and
144
144
  * parsed objects is O(tail), not O(whole file).
145
145
  *
146
- * Mirrors claude's scalarScan (P2-2 + P2-5). Preserves the skill-signature
146
+ * Mirrors claude's scalarScan. Preserves the skill-signature
147
147
  * compression (`<skill>…</skill>` → `skill:x`) for displayTitle and the
148
148
  * "last turn" semantics for usage tokens.
149
149
  */
@@ -198,7 +198,7 @@ function piScalarScan(filePath) {
198
198
  * Build the AgentSessionUsage from an accumulator, preserving pi's
199
199
  * "last turn" semantics: inputTokens/outputTokens use the LAST turn's
200
200
  * values, contextLength = last turn's context-window occupancy
201
- * (input + cacheRead + cacheCreation, excludes output — review P2-8 unified
201
+ * (input + cacheRead + cacheCreation, excludes output —unified
202
202
  * contract across all five readers), cumulative = session-wide sum.
203
203
  * Returns undefined when no usage data was observed.
204
204
  */
@@ -221,10 +221,10 @@ function buildPiUsage(acc) {
221
221
  };
222
222
  }
223
223
  /**
224
- * P2-6 + P2-5 second-pass tail mapper: expand one parsed tail line into
224
+ * second-pass tail mapper: expand one parsed tail line into
225
225
  * content-block events. Re-parses only tail lines (scanTailEvents does the
226
226
  * offset re-read + line filtering), so both raw line-string memory and
227
- * parsed-object memory are O(tail), not O(whole file) — P2-6 + P2-5.
227
+ * parsed-object memory are O(tail), not O(whole file) —.
228
228
  * `maxEvents` capping is applied by scanTailEvents.
229
229
  */
230
230
  function mapPiTailLine(rawObj) {
@@ -285,12 +285,13 @@ export class PiSessionReader {
285
285
  if (!filePath) {
286
286
  return { events: [] };
287
287
  }
288
- // Verify cwd matches
288
+ // Verify cwd matches(PathKit.samePath:win32/darwin 大小写与分隔符不敏感,
289
+ // JSONL 里的 cwd 形态由写方决定,与请求 cwd 不保证逐字符一致)
289
290
  const fileCwd = readCwdFromPiJsonl(filePath);
290
- if (fileCwd && fileCwd !== cwd) {
291
+ if (fileCwd && !samePath(fileCwd, cwd)) {
291
292
  return { events: [] };
292
293
  }
293
- // P2-5 + P2-6: Two-pass scan (see `scanJsonlOnce` / `scanTailEvents` in
294
+ // Two-pass scan (see `scanJsonlOnce` / `scanTailEvents` in
294
295
  // session/common/two-pass.ts): pass 1 streams the file once collecting
295
296
  // scalars (usage, tailOffset, displayTitle) with O(1) parsed-object
296
297
  // retention; pass 2 re-reads ONLY the tail and re-parses it for events,
@@ -338,7 +339,7 @@ export class PiSessionReader {
338
339
  try {
339
340
  const st = fs.statSync(full);
340
341
  const fileCwd = readCwdFromPiJsonl(full);
341
- if (fileCwd && fileCwd !== cwd)
342
+ if (fileCwd && !samePath(fileCwd, cwd))
342
343
  continue;
343
344
  // Extract sessionId (UUID) from filename: <timestamp>_<uuid>.jsonl
344
345
  // The timestamp and uuid are separated by '_', and neither contains '_'
@@ -23,7 +23,7 @@ interface SessionEntry {
23
23
  * - Atomic write (temp + rename) to avoid truncated files on crash
24
24
  * - Corrupt files are treated as empty (with a warning)
25
25
  *
26
- * P3.3: sessions is Map<AgentKind, sessionId> (one session per agent), allowing
26
+ * 3: sessions is Map<AgentKind, sessionId> (one session per agent), allowing
27
27
  * each agent to maintain its own session context when switching between agents.
28
28
  */
29
29
  export declare class SessionStore {
@@ -13,7 +13,7 @@ import { atomicWriteJson } from '../persistence/atomic-write.js';
13
13
  * - Atomic write (temp + rename) to avoid truncated files on crash
14
14
  * - Corrupt files are treated as empty (with a warning)
15
15
  *
16
- * P3.3: sessions is Map<AgentKind, sessionId> (one session per agent), allowing
16
+ * 3: sessions is Map<AgentKind, sessionId> (one session per agent), allowing
17
17
  * each agent to maintain its own session context when switching between agents.
18
18
  */
19
19
  export class SessionStore {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lark-remote",
3
- "version": "0.4.5",
3
+ "version": "0.5.0",
4
4
  "description": "Feishu (Lark) private-chat bridge to local coding agents — Claude Code / Codex / opencode / pi / kimi, with live-streaming CardKit 2.0 cards",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",