@threadbase-sh/streamer 1.67.0 → 1.67.1

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.js CHANGED
@@ -6477,7 +6477,7 @@ import {
6477
6477
  search
6478
6478
  } from "@threadbase-sh/scanner";
6479
6479
  import { createReadStream, existsSync as existsSync8, readdirSync as readdirSync3 } from "fs";
6480
- import { join as join12 } from "path";
6480
+ import { basename as basename5, join as join12 } from "path";
6481
6481
  import { createInterface } from "readline";
6482
6482
 
6483
6483
  // src/conversation-cache.ts
@@ -8644,6 +8644,64 @@ var ConversationHandlers = class {
8644
8644
  }
8645
8645
  return null;
8646
8646
  }
8647
+ /**
8648
+ * Resolve a conversation id to a JSONL path, in order of authority.
8649
+ *
8650
+ * `findJsonlPath` alone answers 64.0% of this machine's 961 conversations and
8651
+ * 0 of 343 Codex ones — it reconstructs `<projectsDir>/<dir>/<uuid>.jsonl`,
8652
+ * which is Claude Code's layout, and a Codex rollout is
8653
+ * `rollout-<ts>-<uuid>.jsonl` under a date path, so that walk cannot match one
8654
+ * by construction. The ladder below answers 99.7%, leaving only the three
8655
+ * whose file is genuinely gone.
8656
+ */
8657
+ async locateJsonlPath(uuid, lookupId) {
8658
+ const live = this.deps.findLiveSessionFilePath(uuid) ?? this.deps.findLiveSessionFilePath(lookupId);
8659
+ if (live) return live;
8660
+ const cached3 = this.cache?.getMetaById(lookupId)?.filePath;
8661
+ if (cached3 && await this.isJsonlPathFor(cached3, lookupId)) return cached3;
8662
+ return this.findJsonlPath(lookupId);
8663
+ }
8664
+ /**
8665
+ * Does `filePath` actually hold the conversation `requestedId` names?
8666
+ *
8667
+ * The filename settles it for both providers: Claude writes `<uuid>.jsonl`
8668
+ * (or `agent-<agentId>.jsonl`), Codex writes `rollout-<ts>-<uuid>.jsonl`.
8669
+ * Only when the name says nothing do we open the file — and there the naive
8670
+ * rule is wrong, because **a Claude subagent transcript carries the PARENT's
8671
+ * `sessionId`**. Matching on `sessionId` alone therefore verifies exactly the
8672
+ * file this check exists to reject, so a sidechain is refused outright unless
8673
+ * it was asked for by its own `agent-<agentId>` name, which the filename
8674
+ * branch above already covers.
8675
+ */
8676
+ async isJsonlPathFor(filePath, requestedId) {
8677
+ if (!existsSync8(filePath)) return false;
8678
+ const stem = basename5(filePath).replace(/\.jsonl$/, "");
8679
+ if (stem === requestedId || stem.includes(requestedId)) return true;
8680
+ const first = await this.readFirstJsonlEntry(filePath);
8681
+ if (!first || first.isSidechain === true) return false;
8682
+ return first.sessionId === requestedId;
8683
+ }
8684
+ /** First parseable JSONL line, for identity checks. Null on an empty or unreadable file. */
8685
+ async readFirstJsonlEntry(filePath) {
8686
+ return new Promise((resolve2) => {
8687
+ const rl = createInterface({ input: createReadStream(filePath), crlfDelay: Infinity });
8688
+ let done = false;
8689
+ rl.on("line", (line) => {
8690
+ if (done) return;
8691
+ try {
8692
+ const entry = JSON.parse(line);
8693
+ done = true;
8694
+ rl.close();
8695
+ resolve2(entry);
8696
+ } catch {
8697
+ }
8698
+ });
8699
+ rl.on("close", () => {
8700
+ if (!done) resolve2(null);
8701
+ });
8702
+ rl.on("error", () => resolve2(null));
8703
+ });
8704
+ }
8647
8705
  async readCwdFromJsonl(filePath) {
8648
8706
  return new Promise((resolve2) => {
8649
8707
  const rl = createInterface({ input: createReadStream(filePath), crlfDelay: Infinity });
@@ -8669,7 +8727,7 @@ var ConversationHandlers = class {
8669
8727
  async findConversationByUuid(uuid) {
8670
8728
  const lookupId = this.deps.resolveConversationLookupId(uuid);
8671
8729
  if (!this.scannerManager.ready && !this.scanProfiles) {
8672
- const filePath2 = this.findJsonlPath(lookupId) ?? this.deps.findLiveSessionFilePath(uuid) ?? this.deps.findLiveSessionFilePath(lookupId);
8730
+ const filePath2 = await this.locateJsonlPath(uuid, lookupId);
8673
8731
  if (filePath2) {
8674
8732
  const account = this.cache?.getMetaById(lookupId)?.account ?? void 0;
8675
8733
  const coldScanner = this.scannerManager.current ?? this.scannerManager.newScanner();
@@ -8721,7 +8779,7 @@ var ConversationHandlers = class {
8721
8779
  return fromIndex;
8722
8780
  }
8723
8781
  if (this.scanProfiles) return null;
8724
- const filePath = this.findJsonlPath(lookupId) ?? this.deps.findLiveSessionFilePath(uuid) ?? this.deps.findLiveSessionFilePath(lookupId);
8782
+ const filePath = await this.locateJsonlPath(uuid, lookupId);
8725
8783
  if (!filePath) return null;
8726
8784
  if (this.scannerManager.ready) {
8727
8785
  const account = this.cache?.getMetaById(lookupId)?.account ?? void 0;
@@ -9135,7 +9193,7 @@ var ConversationHandlers = class {
9135
9193
 
9136
9194
  // src/api/handlers/sessions.handlers.ts
9137
9195
  import { existsSync as existsSync10 } from "fs";
9138
- import { basename as basename5, dirname as dirname9, join as join16 } from "path";
9196
+ import { basename as basename6, dirname as dirname9, join as join16 } from "path";
9139
9197
 
9140
9198
  // node_modules/nanoid/index.js
9141
9199
  import crypto2 from "crypto";
@@ -10659,7 +10717,7 @@ var SessionHandlers = class {
10659
10717
  const jsonlCwd = jsonlPath ? await this.deps.readCwdFromJsonl(jsonlPath) : null;
10660
10718
  if (jsonlCwd) {
10661
10719
  projectPath = jsonlCwd;
10662
- projectName = projectName || basename5(jsonlCwd);
10720
+ projectName = projectName || basename6(jsonlCwd);
10663
10721
  }
10664
10722
  }
10665
10723
  if (!projectPath) {
@@ -15256,7 +15314,7 @@ function discoveredToResponse(d, conversationId) {
15256
15314
  // src/session-watchers.ts
15257
15315
  import { existsSync as existsSync15, watch as fsWatch, readdirSync as readdirSync7, readFileSync as readFileSync10, statSync as statSync13 } from "fs";
15258
15316
  import { homedir as homedir13 } from "os";
15259
- import { basename as basename6, join as join24 } from "path";
15317
+ import { basename as basename7, join as join24 } from "path";
15260
15318
  var SessionWatchers = class {
15261
15319
  constructor(deps) {
15262
15320
  this.deps = deps;
@@ -15362,7 +15420,7 @@ var SessionWatchers = class {
15362
15420
  try {
15363
15421
  const now = Date.now();
15364
15422
  const match = readdirSync7(projectsDir).filter((f) => f.endsWith(".jsonl")).map((f) => ({ f, mtime: statSync13(join24(projectsDir, f)).mtimeMs })).filter(({ mtime }) => now - mtime < 5e3).filter(
15365
- ({ f }) => basename6(f, ".jsonl") === sessionId || this.readFirstLineSessionId(join24(projectsDir, f)) === sessionId
15423
+ ({ f }) => basename7(f, ".jsonl") === sessionId || this.readFirstLineSessionId(join24(projectsDir, f)) === sessionId
15366
15424
  ).sort((a, b) => b.mtime - a.mtime)[0];
15367
15425
  if (match) resolvedFilePath = join24(projectsDir, match.f);
15368
15426
  } catch {