@threadbase-sh/streamer 1.24.1 → 1.24.3

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
@@ -1197,14 +1197,41 @@ function scrapePermissionGate(lines) {
1197
1197
  }
1198
1198
  if (options.length === 0) return null;
1199
1199
  let prompt;
1200
+ let promptLine = -1;
1200
1201
  for (let i = firstOptionLine - 1; i >= 0; i--) {
1201
1202
  const t = stripGutter(lines[i]).trim();
1202
1203
  if (t.length === 0) continue;
1203
1204
  if (BOX_ONLY_RE.test(lines[i].trim()) || FOOTER_RE.test(t) || PROMPT_ARROW_RE.test(t)) continue;
1204
1205
  prompt = t || void 0;
1206
+ promptLine = i;
1205
1207
  break;
1206
1208
  }
1207
- return { ...prompt ? { prompt } : {}, options, ...cursor !== void 0 ? { cursor } : {} };
1209
+ const detail = promptLine > 0 ? scrapeDetail(lines, promptLine) : void 0;
1210
+ return {
1211
+ ...prompt ? { prompt } : {},
1212
+ ...detail ? { detail } : {},
1213
+ options,
1214
+ ...cursor !== void 0 ? { cursor } : {}
1215
+ };
1216
+ }
1217
+ var MAX_DETAIL_LINES = 6;
1218
+ function scrapeDetail(lines, promptLine) {
1219
+ const collected = [];
1220
+ let blankRun = 0;
1221
+ for (let i = promptLine - 1; i >= 0; i--) {
1222
+ const t = stripGutter(lines[i]).trim();
1223
+ if (BOX_ONLY_RE.test(t)) break;
1224
+ if (t.length === 0) {
1225
+ blankRun++;
1226
+ if (blankRun >= 2) break;
1227
+ continue;
1228
+ }
1229
+ blankRun = 0;
1230
+ if (FOOTER_RE.test(t) || PROMPT_ARROW_RE.test(t)) continue;
1231
+ collected.push(t);
1232
+ if (collected.length >= MAX_DETAIL_LINES) break;
1233
+ }
1234
+ return collected.length > 0 ? collected.reverse().join("\n") : void 0;
1208
1235
  }
1209
1236
 
1210
1237
  // src/services/questions/detectQuestionFromScreen.ts
@@ -4827,6 +4854,11 @@ var StreamerServer = class {
4827
4854
  // /input { keys }. Cleared when the gate closes.
4828
4855
  pendingPermission = /* @__PURE__ */ new Map();
4829
4856
  scanner = null;
4857
+ // Set when better-sqlite3 is unusable (e.g. node ABI mismatch made
4858
+ // ConversationCache.open throw). All scanners are then built with
4859
+ // persistent: false so requests serve from disk instead of 500ing on
4860
+ // every touch of the scanner's own SQLite index.
4861
+ scannerPersistenceDisabled = false;
4830
4862
  // Tracks every ConversationScanner ever created so close() can shut them all
4831
4863
  // down and release SQLite handles (open handles block temp-dir deletion on Windows).
4832
4864
  allScanners = /* @__PURE__ */ new Set();
@@ -5326,11 +5358,12 @@ var StreamerServer = class {
5326
5358
  const message = err instanceof Error ? err.message : String(err);
5327
5359
  const abiMismatch = message.includes("NODE_MODULE_VERSION") || message.includes("was compiled against a different Node.js version");
5328
5360
  this.log.error(
5329
- `ConversationCache failed to open \u2014 running WITHOUT cache; /api/conversations, /api/conversations/count and /project-chats will 500.` + (abiMismatch ? ` Fix: npm rebuild better-sqlite3` : "") + ` (${message})`,
5361
+ `ConversationCache failed to open \u2014 running WITHOUT cache; /api/conversations, /api/conversations/count and /project-chats serve from disk (degraded).` + (abiMismatch ? ` Fix: npm rebuild better-sqlite3` : "") + ` (${message})`,
5330
5362
  { error: message, abiMismatch, event: "cache.open_failed" }
5331
5363
  );
5364
+ this.scannerPersistenceDisabled = true;
5332
5365
  }
5333
- const warmupScanner = new import_scanner2.ConversationScanner();
5366
+ const warmupScanner = this.newScanner();
5334
5367
  this.allScanners.add(warmupScanner);
5335
5368
  const warmupStatCache = this.buildStatCache(null);
5336
5369
  const shouldEmitProgress = createScanProgressThrottle();
@@ -5347,6 +5380,10 @@ var StreamerServer = class {
5347
5380
  }
5348
5381
  }
5349
5382
  }).then(async () => {
5383
+ if (!this.scannerReady && !this.scanner) {
5384
+ this.scanner = warmupScanner;
5385
+ this.scannerReady = Promise.resolve();
5386
+ }
5350
5387
  if (!this.cache) return;
5351
5388
  const metas = [...warmupScanner.getMetadataCache().values()];
5352
5389
  const upsertedIds = new Set(this.cache.upsertFromScannerMeta(metas));
@@ -5395,10 +5432,6 @@ var StreamerServer = class {
5395
5432
  event: "cache.warmup_failed"
5396
5433
  });
5397
5434
  }).finally(() => {
5398
- if (!this.scannerReady && !this.scanner) {
5399
- this.scanner = warmupScanner;
5400
- this.scannerReady = Promise.resolve();
5401
- }
5402
5435
  this.cacheReady = true;
5403
5436
  this.wsHub.broadcast({ type: "cache_ready" });
5404
5437
  resolveWarm();
@@ -5781,6 +5814,11 @@ var StreamerServer = class {
5781
5814
  // this — its per-file refreshFile (in findConversationByUuid) already
5782
5815
  // reconciles the one conversation being requested, so paying a full-tree
5783
5816
  // rescan just because some OTHER file changed is the stall this avoids.
5817
+ newScanner() {
5818
+ return new import_scanner2.ConversationScanner(
5819
+ this.scannerPersistenceDisabled ? { persistent: false } : void 0
5820
+ );
5821
+ }
5784
5822
  async getScanner(skipStaleRescan = false) {
5785
5823
  if (this.scannerReady) {
5786
5824
  await this.scannerReady;
@@ -5797,14 +5835,20 @@ var StreamerServer = class {
5797
5835
  }
5798
5836
  this.scannerStale = false;
5799
5837
  const statCache = this.buildStatCache(this.scanner);
5800
- this.scanner = new import_scanner2.ConversationScanner();
5838
+ this.scanner = this.newScanner();
5801
5839
  this.allScanners.add(this.scanner);
5802
5840
  this.scannerReady = this.scanner.scan({
5803
5841
  ...this.scanProfiles ? { profiles: this.scanProfiles } : {},
5804
5842
  ...this.codexScanOpts(),
5805
5843
  ...statCache ? { statCache } : {}
5806
5844
  });
5807
- await this.scannerReady;
5845
+ try {
5846
+ await this.scannerReady;
5847
+ } catch (err) {
5848
+ this.scanner = null;
5849
+ this.scannerReady = null;
5850
+ throw err;
5851
+ }
5808
5852
  const scanner = this.scanner;
5809
5853
  if (!scanner) return this.getScanner();
5810
5854
  return scanner;
@@ -5859,7 +5903,7 @@ var StreamerServer = class {
5859
5903
  const filePath2 = this.findJsonlPath(uuid);
5860
5904
  if (filePath2) {
5861
5905
  const account = this.cache?.getMetaById(uuid)?.account ?? void 0;
5862
- const coldScanner = this.scanner ?? new import_scanner2.ConversationScanner();
5906
+ const coldScanner = this.scanner ?? this.newScanner();
5863
5907
  const page = await coldScanner.parseSingleFilePage(filePath2, account, {
5864
5908
  limit: Number.MAX_SAFE_INTEGER
5865
5909
  });
@@ -6341,6 +6385,7 @@ var StreamerServer = class {
6341
6385
  type: "permission",
6342
6386
  sessionId,
6343
6387
  ...gate.prompt ? { prompt: gate.prompt } : {},
6388
+ ...gate.detail ? { detail: gate.detail } : {},
6344
6389
  options: gate.options,
6345
6390
  ...gate.cursor !== void 0 ? { cursor: gate.cursor } : {}
6346
6391
  });