@threadbase-sh/scanner 0.14.6 → 0.15.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.
package/dist/index.cjs CHANGED
@@ -50,6 +50,7 @@ __export(index_exports, {
50
50
  getLogger: () => getLogger,
51
51
  getProjectsDir: () => getProjectsDir,
52
52
  loadProfiles: () => loadProfiles,
53
+ parseCodexJsonlLine: () => parseCodexJsonlLine,
53
54
  parseJsonlLine: () => parseJsonlLine,
54
55
  readGitBranch: () => readGitBranch,
55
56
  readSidecar: () => readSidecar,
@@ -1057,6 +1058,26 @@ function extractCodexText(content) {
1057
1058
  return "";
1058
1059
  }).filter(Boolean).map(cleanSystemTags).join(" ");
1059
1060
  }
1061
+ function parseCodexJsonlLine(line) {
1062
+ if (!line.trim()) return null;
1063
+ let entry;
1064
+ try {
1065
+ entry = JSON.parse(line);
1066
+ } catch {
1067
+ return null;
1068
+ }
1069
+ return codexEntryToMessage(entry);
1070
+ }
1071
+ function codexEntryToMessage(entry) {
1072
+ const payload = entry.payload;
1073
+ if (!payload || typeof payload !== "object") return null;
1074
+ if (entry.type !== "response_item" || payload.type !== "message") return null;
1075
+ const role = payload.role;
1076
+ if (role !== "user" && role !== "assistant") return null;
1077
+ const text = extractCodexText(payload.content);
1078
+ if (!text) return null;
1079
+ return { role, text, timestamp: asString(entry.timestamp) };
1080
+ }
1060
1081
  function reduceCodexEntry(acc, entry, tier) {
1061
1082
  const ts = asString(entry.timestamp);
1062
1083
  if (ts && (!acc.latestTimestamp || ts > acc.latestTimestamp)) acc.latestTimestamp = ts;
@@ -1167,14 +1188,11 @@ async function parseCodexConversation(filePath, account) {
1167
1188
  if (!cwd) cwd = asString(payload.cwd);
1168
1189
  continue;
1169
1190
  }
1170
- if (entry.type !== "response_item" || payload.type !== "message") continue;
1171
- const role = payload.role;
1172
- if (role !== "user" && role !== "assistant") continue;
1173
- const text = extractCodexText(payload.content);
1174
- if (!text) continue;
1175
- messages.push({ role, text, timestamp: ts });
1176
- textParts.push(text);
1177
- if (role === "user") lastUserText = text;
1191
+ const message = codexEntryToMessage(entry);
1192
+ if (!message) continue;
1193
+ messages.push(message);
1194
+ textParts.push(message.text);
1195
+ if (message.role === "user") lastUserText = message.text;
1178
1196
  }
1179
1197
  } catch (err) {
1180
1198
  log.warn({ filePath, err }, "parseCodexConversation: read failed");
@@ -3522,7 +3540,8 @@ var ConversationScanner = class {
3522
3540
  // feeds the conversation's account field; "default" is the single-profile
3523
3541
  // fallback, matching refreshFile.
3524
3542
  async parseSingleFilePage(filePath, account, options) {
3525
- const conversation = await parseConversation(filePath, account ?? "default");
3543
+ const provider = await this.resolveProviderForFile(filePath, null);
3544
+ const conversation = provider?.name === CODEX_CLI_PROVIDER ? await parseCodexConversation(filePath, account ?? "default") : await parseConversation(filePath, account ?? "default");
3526
3545
  if (!conversation) return null;
3527
3546
  const { messages } = conversation;
3528
3547
  const total = messages.length;
@@ -3566,7 +3585,7 @@ var ConversationScanner = class {
3566
3585
  const engine = this.engine();
3567
3586
  const previous2 = engine.getByIdOrSession(filePath);
3568
3587
  const resolvedAccount2 = account ?? previous2?.account ?? "default";
3569
- const provider = await this.resolveProviderForFile(filePath, previous2);
3588
+ const provider2 = await this.resolveProviderForFile(filePath, previous2);
3570
3589
  const { meta: meta2, change } = await engine.indexFile(
3571
3590
  filePath,
3572
3591
  resolvedAccount2,
@@ -3574,7 +3593,7 @@ var ConversationScanner = class {
3574
3593
  void 0,
3575
3594
  readGitBranch,
3576
3595
  false,
3577
- provider
3596
+ provider2
3578
3597
  );
3579
3598
  const cacheKeys = /* @__PURE__ */ new Set();
3580
3599
  for (const m of [previous2, meta2]) {
@@ -3595,10 +3614,12 @@ var ConversationScanner = class {
3595
3614
  const resolvedAccount = account ?? previous?.account ?? "default";
3596
3615
  let meta = null;
3597
3616
  let searchDoc = emptySearchDocument();
3617
+ const onEntry = (entry) => {
3618
+ searchDoc = appendSearchDelta(searchDoc, extractSearchDelta(entry));
3619
+ };
3620
+ const provider = await this.resolveProviderForFile(filePath, previous ?? null);
3598
3621
  try {
3599
- meta = await parseMeta(filePath, resolvedAccount, this.lastTier, (entry) => {
3600
- searchDoc = appendSearchDelta(searchDoc, extractSearchDelta(entry));
3601
- });
3622
+ meta = provider ? await parseMetaWithProvider(provider, filePath, resolvedAccount, this.lastTier, onEntry) : await parseMeta(filePath, resolvedAccount, this.lastTier, onEntry);
3602
3623
  } catch (err) {
3603
3624
  log.warn({ filePath, err }, "refreshFile: parseMeta threw");
3604
3625
  meta = null;
@@ -3975,6 +3996,7 @@ async function getConversation(id, options, scanner) {
3975
3996
  getLogger,
3976
3997
  getProjectsDir,
3977
3998
  loadProfiles,
3999
+ parseCodexJsonlLine,
3978
4000
  parseJsonlLine,
3979
4001
  readGitBranch,
3980
4002
  readSidecar,