@threadbase-sh/streamer 1.27.2 → 1.28.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/cli.cjs CHANGED
@@ -30931,7 +30931,7 @@ var require_websocket = __commonJS({
30931
30931
  var http = require("http");
30932
30932
  var net = require("net");
30933
30933
  var tls = require("tls");
30934
- var { randomBytes: randomBytes4, createHash: createHash4 } = require("crypto");
30934
+ var { randomBytes: randomBytes4, createHash: createHash5 } = require("crypto");
30935
30935
  var { Duplex, Readable: Readable3 } = require("stream");
30936
30936
  var { URL: URL2 } = require("url");
30937
30937
  var PerMessageDeflate2 = require_permessage_deflate();
@@ -31599,7 +31599,7 @@ var require_websocket = __commonJS({
31599
31599
  abortHandshake(websocket, socket, "Invalid Upgrade header");
31600
31600
  return;
31601
31601
  }
31602
- const digest = createHash4("sha1").update(key + GUID).digest("base64");
31602
+ const digest = createHash5("sha1").update(key + GUID).digest("base64");
31603
31603
  if (res.headers["sec-websocket-accept"] !== digest) {
31604
31604
  abortHandshake(websocket, socket, "Invalid Sec-WebSocket-Accept header");
31605
31605
  return;
@@ -31968,7 +31968,7 @@ var require_websocket_server = __commonJS({
31968
31968
  var EventEmitter6 = require("events");
31969
31969
  var http = require("http");
31970
31970
  var { Duplex } = require("stream");
31971
- var { createHash: createHash4 } = require("crypto");
31971
+ var { createHash: createHash5 } = require("crypto");
31972
31972
  var extension2 = require_extension();
31973
31973
  var PerMessageDeflate2 = require_permessage_deflate();
31974
31974
  var subprotocol2 = require_subprotocol();
@@ -32275,7 +32275,7 @@ var require_websocket_server = __commonJS({
32275
32275
  );
32276
32276
  }
32277
32277
  if (this._state > RUNNING) return abortHandshake(socket, 503);
32278
- const digest = createHash4("sha1").update(key + GUID).digest("base64");
32278
+ const digest = createHash5("sha1").update(key + GUID).digest("base64");
32279
32279
  const headers = [
32280
32280
  "HTTP/1.1 101 Switching Protocols",
32281
32281
  "Upgrade: websocket",
@@ -100397,11 +100397,11 @@ var require_out = __commonJS({
100397
100397
  async.read(path2, getSettings(optionsOrSettingsOrCallback), callback);
100398
100398
  }
100399
100399
  exports2.stat = stat10;
100400
- function statSync9(path2, optionsOrSettings) {
100400
+ function statSync10(path2, optionsOrSettings) {
100401
100401
  const settings = getSettings(optionsOrSettings);
100402
100402
  return sync.read(path2, settings);
100403
100403
  }
100404
- exports2.statSync = statSync9;
100404
+ exports2.statSync = statSync10;
100405
100405
  function getSettings(settingsOrOptions = {}) {
100406
100406
  if (settingsOrOptions instanceof settings_1.default) {
100407
100407
  return settingsOrOptions;
@@ -123750,14 +123750,14 @@ __export(prompt_exports, {
123750
123750
  interactivePermissionModePrompt: () => interactivePermissionModePrompt,
123751
123751
  interactivePrompt: () => interactivePrompt
123752
123752
  });
123753
- var import_node_process2, import_promises20, interactivePrompt, interactivePermissionModePrompt;
123753
+ var import_node_process2, import_promises22, interactivePrompt, interactivePermissionModePrompt;
123754
123754
  var init_prompt = __esm({
123755
123755
  "src/lifecycle/prompt.ts"() {
123756
123756
  "use strict";
123757
123757
  import_node_process2 = require("process");
123758
- import_promises20 = require("readline/promises");
123758
+ import_promises22 = require("readline/promises");
123759
123759
  interactivePrompt = async ({ prodPort, suggestedAltPort, prodActive }) => {
123760
- const rl = (0, import_promises20.createInterface)({ input: import_node_process2.stdin, output: import_node_process2.stdout });
123760
+ const rl = (0, import_promises22.createInterface)({ input: import_node_process2.stdin, output: import_node_process2.stdout });
123761
123761
  try {
123762
123762
  if (!prodActive) {
123763
123763
  import_node_process2.stdout.write(
@@ -123792,7 +123792,7 @@ The supervised prod streamer is already holding port ${prodPort}.
123792
123792
  }
123793
123793
  };
123794
123794
  interactivePermissionModePrompt = async () => {
123795
- const rl = (0, import_promises20.createInterface)({ input: import_node_process2.stdin, output: import_node_process2.stdout });
123795
+ const rl = (0, import_promises22.createInterface)({ input: import_node_process2.stdin, output: import_node_process2.stdout });
123796
123796
  try {
123797
123797
  import_node_process2.stdout.write(
123798
123798
  "\nWhich permission mode should spawned Claude Code sessions use?\n [a] acceptEdits \u2014 auto-approve file edits, still prompt for shell commands (default)\n [m] manual \u2014 prompt for every edit and command\n"
@@ -128554,9 +128554,10 @@ var import_promises8 = require("timers/promises");
128554
128554
  var import_crypto2 = require("crypto");
128555
128555
  var import_fs11 = require("fs");
128556
128556
  var import_fs12 = require("fs");
128557
+ var import_fs13 = require("fs");
128557
128558
  var import_readline3 = require("readline");
128558
128559
  var import_better_sqlite3 = __toESM(require("better-sqlite3"), 1);
128559
- var import_fs13 = require("fs");
128560
+ var import_fs14 = require("fs");
128560
128561
  var import_path9 = require("path");
128561
128562
  var import_promises9 = require("fs/promises");
128562
128563
  var import_path10 = require("path");
@@ -130939,6 +130940,17 @@ function reduceConvLine(state, entry) {
130939
130940
  attachment: entry.attachment !== void 0 ? entry.attachment : void 0
130940
130941
  };
130941
130942
  }
130943
+ function parseJsonlLine(line, state = initialConvState()) {
130944
+ const text = line.trimEnd();
130945
+ if (text.trim().length === 0) return null;
130946
+ let entry;
130947
+ try {
130948
+ entry = JSON.parse(text);
130949
+ } catch {
130950
+ return null;
130951
+ }
130952
+ return reduceConvLine(state, entry);
130953
+ }
130942
130954
  function applyTeamInfo(messages, state) {
130943
130955
  if (Object.keys(state.teamInfo).length === 0) return;
130944
130956
  for (const m2 of messages) {
@@ -131600,7 +131612,7 @@ async function parseMetaWithProvider(provider, filePath, account, tier) {
131600
131612
  const log8 = getLogger2();
131601
131613
  const acc = provider.createEmptyAccumulator();
131602
131614
  const rl = (0, import_readline3.createInterface)({
131603
- input: (0, import_fs12.createReadStream)(filePath),
131615
+ input: (0, import_fs13.createReadStream)(filePath),
131604
131616
  crlfDelay: Infinity
131605
131617
  });
131606
131618
  try {
@@ -131823,7 +131835,7 @@ function hasColumn(db, table, column) {
131823
131835
  }
131824
131836
  function openDatabase(dbPath) {
131825
131837
  if (dbPath !== ":memory:") {
131826
- (0, import_fs13.mkdirSync)((0, import_path9.dirname)(dbPath), { recursive: true });
131838
+ (0, import_fs14.mkdirSync)((0, import_path9.dirname)(dbPath), { recursive: true });
131827
131839
  }
131828
131840
  const db = new import_better_sqlite3.default(dbPath);
131829
131841
  db.pragma("journal_mode = WAL");
@@ -132623,7 +132635,13 @@ var PersistentEngine = class {
132623
132635
  await this.ensureCheckpoints(filePath, total);
132624
132636
  const beforeIndex = options.beforeIndex ?? total;
132625
132637
  const fromIndex = Math.max(0, beforeIndex - options.limit);
132626
- const floor = this.checkpoints.floor(filePath, fromIndex);
132638
+ let floor = this.checkpoints.floor(filePath, fromIndex);
132639
+ if (floor) {
132640
+ try {
132641
+ if (floor.byteOffset > (0, import_fs12.statSync)(filePath).size) floor = null;
132642
+ } catch {
132643
+ }
132644
+ }
132627
132645
  return readPage(filePath, total, options, floor);
132628
132646
  }
132629
132647
  // Build or extend the checkpoint chain so it covers `total` messages. Cold
@@ -133512,8 +133530,8 @@ async function search(query, options, scanner) {
133512
133530
 
133513
133531
  // src/server.ts
133514
133532
  var import_events3 = require("events");
133515
- var import_fs24 = require("fs");
133516
- var import_promises17 = require("fs/promises");
133533
+ var import_fs25 = require("fs");
133534
+ var import_promises19 = require("fs/promises");
133517
133535
  var import_http = require("http");
133518
133536
  var import_os10 = require("os");
133519
133537
  var import_path22 = require("path");
@@ -136658,11 +136676,13 @@ async function createDirectory(parentAbsolutePath, name) {
136658
136676
 
136659
136677
  // src/conversation-cache.ts
136660
136678
  var import_better_sqlite32 = __toESM(require("better-sqlite3"), 1);
136661
- var import_fs16 = require("fs");
136679
+ var import_fs17 = require("fs");
136680
+ var import_promises12 = require("fs/promises");
136662
136681
  var import_path13 = require("path");
136682
+ var import_promises13 = require("timers/promises");
136663
136683
 
136664
136684
  // src/db/sqlite-migrate.ts
136665
- var import_fs14 = require("fs");
136685
+ var import_fs15 = require("fs");
136666
136686
  var import_path12 = require("path");
136667
136687
  var import_url6 = require("url");
136668
136688
  var import_meta = {};
@@ -136681,7 +136701,7 @@ CREATE TABLE IF NOT EXISTS schema_migrations (
136681
136701
  function runSqliteMigrations(db, migrationsDir) {
136682
136702
  db.exec(SCHEMA_MIGRATIONS_SQL);
136683
136703
  const dir = migrationsDir ?? (0, import_path12.join)(getMigrationsDir(), "migrations");
136684
- const files = (0, import_fs14.readdirSync)(dir).filter((f2) => f2.endsWith(".sql")).sort();
136704
+ const files = (0, import_fs15.readdirSync)(dir).filter((f2) => f2.endsWith(".sql")).sort();
136685
136705
  const appliedRows = db.prepare("SELECT id FROM schema_migrations").all();
136686
136706
  const appliedSet = new Set(appliedRows.map((r) => r.id));
136687
136707
  const recordApplied = db.prepare("INSERT INTO schema_migrations (id, applied_at) VALUES (?, ?)");
@@ -136692,7 +136712,7 @@ function runSqliteMigrations(db, migrationsDir) {
136692
136712
  skipped.push(file2);
136693
136713
  continue;
136694
136714
  }
136695
- const sql = (0, import_fs14.readFileSync)((0, import_path12.join)(dir, file2), "utf-8");
136715
+ const sql = (0, import_fs15.readFileSync)((0, import_path12.join)(dir, file2), "utf-8");
136696
136716
  const tx = db.transaction(() => {
136697
136717
  db.exec(sql);
136698
136718
  recordApplied.run(file2, (/* @__PURE__ */ new Date()).toISOString());
@@ -136717,7 +136737,7 @@ function isProviderResumable(_provider, availabilityResumable) {
136717
136737
  }
136718
136738
 
136719
136739
  // src/services/conversations/isAgentConversation.ts
136720
- var import_fs15 = require("fs");
136740
+ var import_fs16 = require("fs");
136721
136741
  var DEFAULT_AGENT_ENTRYPOINTS = /* @__PURE__ */ new Set(["sdk-cli", "claude-vscode"]);
136722
136742
  var CHUNK_BYTES = 64 * 1024;
136723
136743
  var ENTRYPOINT_PROBE = `"entrypoint":`;
@@ -136739,12 +136759,12 @@ function isAgentFile(filePath, entrypoints = DEFAULT_AGENT_ENTRYPOINTS) {
136739
136759
  if (cached3 !== void 0) return cached3;
136740
136760
  let fd;
136741
136761
  try {
136742
- fd = (0, import_fs15.openSync)(filePath, "r");
136762
+ fd = (0, import_fs16.openSync)(filePath, "r");
136743
136763
  } catch {
136744
136764
  return false;
136745
136765
  }
136746
136766
  try {
136747
- const fileSize = (0, import_fs15.statSync)(filePath).size;
136767
+ const fileSize = (0, import_fs16.statSync)(filePath).size;
136748
136768
  if (fileSize === 0) {
136749
136769
  fileDecisionCache.set(key, false);
136750
136770
  return false;
@@ -136755,7 +136775,7 @@ function isAgentFile(filePath, entrypoints = DEFAULT_AGENT_ENTRYPOINTS) {
136755
136775
  let carry = "";
136756
136776
  while (offset < fileSize) {
136757
136777
  const toRead = Math.min(CHUNK_BYTES, fileSize - offset);
136758
- const got = (0, import_fs15.readSync)(fd, buf, 0, toRead, offset);
136778
+ const got = (0, import_fs16.readSync)(fd, buf, 0, toRead, offset);
136759
136779
  if (got <= 0) break;
136760
136780
  const chunk = carry + buf.toString("utf8", 0, got);
136761
136781
  for (const marker of markers) {
@@ -136776,7 +136796,7 @@ function isAgentFile(filePath, entrypoints = DEFAULT_AGENT_ENTRYPOINTS) {
136776
136796
  } catch {
136777
136797
  return false;
136778
136798
  } finally {
136779
- (0, import_fs15.closeSync)(fd);
136799
+ (0, import_fs16.closeSync)(fd);
136780
136800
  }
136781
136801
  }
136782
136802
  function parseAgentEntrypointsEnv(raw2) {
@@ -136785,6 +136805,33 @@ function parseAgentEntrypointsEnv(raw2) {
136785
136805
  return new Set(parts);
136786
136806
  }
136787
136807
 
136808
+ // src/utils/fileIdentity.ts
136809
+ var import_crypto5 = require("crypto");
136810
+ function fileIdentity(stat10, headBytes) {
136811
+ if (stat10.ino && stat10.ino > 0) return `inode:${stat10.dev}:${stat10.ino}`;
136812
+ const head = headBytes ?? Buffer.alloc(0);
136813
+ return `fp:${(0, import_crypto5.createHash)("sha1").update(head).digest("hex")}`;
136814
+ }
136815
+ function splitCompleteLines(buf, baseOffset) {
136816
+ const spans = [];
136817
+ let lineStart = 0;
136818
+ let consumed = 0;
136819
+ for (let i = 0; i < buf.length; i++) {
136820
+ if (buf[i] !== 10) continue;
136821
+ const lineLen = i - lineStart;
136822
+ if (lineLen > 0) {
136823
+ spans.push({
136824
+ byteOffset: baseOffset + lineStart,
136825
+ byteLength: lineLen,
136826
+ text: buf.toString("utf-8", lineStart, i)
136827
+ });
136828
+ }
136829
+ lineStart = i + 1;
136830
+ consumed = lineStart;
136831
+ }
136832
+ return { spans, consumed };
136833
+ }
136834
+
136788
136835
  // src/conversation-cache.ts
136789
136836
  function shortProjectName(fullPath) {
136790
136837
  const parts = fullPath.split(/[/\\]/).filter(Boolean);
@@ -136833,6 +136880,14 @@ var ConversationCache = class _ConversationCache {
136833
136880
  tailSize;
136834
136881
  fileIndex = /* @__PURE__ */ new Map();
136835
136882
  fileIndexLoaded = false;
136883
+ // Per-file scanner parse state for the incremental offset-index writer. The
136884
+ // reducer is stateful across lines (pending tool_uses, latest timestamp), so
136885
+ // it must persist between watcher reads of the same file. Cleared on
136886
+ // truncation/backfill.
136887
+ indexParseState = /* @__PURE__ */ new Map();
136888
+ // Single-flight guard for backfillIndex — concurrent detail requests for the
136889
+ // same cold file await one walk, not N. Entry dropped on settle.
136890
+ backfillInFlight = /* @__PURE__ */ new Map();
136836
136891
  // Monotonically increasing counter for tail updated_at — guarantees strict
136837
136892
  // ordering even when multiple updateFromLine() calls land within the same ms.
136838
136893
  tailSeq = Date.now();
@@ -136996,6 +137051,42 @@ var ConversationCache = class _ConversationCache {
136996
137051
  GROUP BY project_path
136997
137052
  ORDER BY cnt DESC
136998
137053
  LIMIT ?`
137054
+ ),
137055
+ getFileState: db.prepare("SELECT * FROM conversation_file_state WHERE path = ?"),
137056
+ upsertFileState: db.prepare(
137057
+ `INSERT INTO conversation_file_state
137058
+ (path, identity, size, mtime_ms, byte_offset, last_message_index)
137059
+ VALUES (@path, @identity, @size, @mtime_ms, @byte_offset, @last_message_index)
137060
+ ON CONFLICT(path) DO UPDATE SET
137061
+ identity = excluded.identity,
137062
+ size = excluded.size,
137063
+ mtime_ms = excluded.mtime_ms,
137064
+ byte_offset = excluded.byte_offset,
137065
+ last_message_index = excluded.last_message_index`
137066
+ ),
137067
+ deleteFileState: db.prepare("DELETE FROM conversation_file_state WHERE path = ?"),
137068
+ deleteMessageIndex: db.prepare(
137069
+ "DELETE FROM conversation_message_index WHERE conversation_id = ?"
137070
+ ),
137071
+ insertMessageIndexRow: db.prepare(
137072
+ `INSERT INTO conversation_message_index
137073
+ (conversation_id, message_index, byte_offset, byte_length, uuid, role, ts)
137074
+ VALUES (@conversation_id, @message_index, @byte_offset, @byte_length, @uuid, @role, @ts)
137075
+ ON CONFLICT(conversation_id, message_index) DO UPDATE SET
137076
+ byte_offset = excluded.byte_offset,
137077
+ byte_length = excluded.byte_length,
137078
+ uuid = excluded.uuid,
137079
+ role = excluded.role,
137080
+ ts = excluded.ts`
137081
+ ),
137082
+ getMessageIndexWindow: db.prepare(
137083
+ `SELECT message_index, byte_offset, byte_length, uuid, role, ts
137084
+ FROM conversation_message_index
137085
+ WHERE conversation_id = ? AND message_index >= ? AND message_index < ?
137086
+ ORDER BY message_index ASC`
137087
+ ),
137088
+ getIndexedMessageCount: db.prepare(
137089
+ "SELECT COUNT(*) as cnt FROM conversation_message_index WHERE conversation_id = ?"
136999
137090
  )
137000
137091
  };
137001
137092
  }
@@ -137006,6 +137097,258 @@ var ConversationCache = class _ConversationCache {
137006
137097
  getDatabase() {
137007
137098
  return this.db;
137008
137099
  }
137100
+ // ── Offset index (design 1b) ────────────────────────────────────────────
137101
+ // conversation_file_state + conversation_message_index back the windowed
137102
+ // detail read path (SQL window select + pread of byte ranges). All methods
137103
+ // are thin wrappers over the prepared statements above.
137104
+ getFileState(path2) {
137105
+ return this.stmts.getFileState.get(path2) ?? null;
137106
+ }
137107
+ upsertFileState(row) {
137108
+ this.stmts.upsertFileState.run(row);
137109
+ }
137110
+ /** Drop a file's index rows + file_state (truncation / identity change). */
137111
+ deleteFileIndex(path2, conversationId) {
137112
+ const tx = this.db.transaction(() => {
137113
+ this.stmts.deleteMessageIndex.run(conversationId);
137114
+ this.stmts.deleteFileState.run(path2);
137115
+ });
137116
+ tx();
137117
+ this.indexParseState.delete(path2);
137118
+ }
137119
+ /** Append/replace index rows in one transaction. */
137120
+ appendMessageIndexRows(rows) {
137121
+ const tx = this.db.transaction((batch) => {
137122
+ for (const r of batch) this.stmts.insertMessageIndexRow.run(r);
137123
+ });
137124
+ tx(rows);
137125
+ }
137126
+ /** Rows for message_index in [fromIndex, toIndex), ordered ascending. */
137127
+ getMessageIndexWindow(conversationId, fromIndex, toIndex) {
137128
+ return this.stmts.getMessageIndexWindow.all(
137129
+ conversationId,
137130
+ fromIndex,
137131
+ toIndex
137132
+ );
137133
+ }
137134
+ getIndexedMessageCount(conversationId) {
137135
+ return this.stmts.getIndexedMessageCount.get(conversationId).cnt;
137136
+ }
137137
+ /**
137138
+ * Conversation id for a JSONL path — the filename stem (matches the pseudo-id
137139
+ * updateFromLine derives and the uuid the detail read path resolves). The
137140
+ * offset index keys on this so the window select and the cursor agree.
137141
+ */
137142
+ static conversationIdForFile(filePath) {
137143
+ return filePath.split(/[/\\]/).pop()?.replace(/\.jsonl$/, "") ?? filePath;
137144
+ }
137145
+ /**
137146
+ * Incremental offset-index writer: extend the index for a burst of appended
137147
+ * lines (one watcher read) using their byte spans. Each line is classified
137148
+ * with the scanner's parseJsonlLine (a running per-file reducer state), so the
137149
+ * message ordering can never drift from the scanner's. Message lines get an
137150
+ * index row at the next message_index; non-message lines (summary/sidecar)
137151
+ * get no row but still advance byte_offset. file_state is updated to the end
137152
+ * of the last consumed span.
137153
+ *
137154
+ * Requires an up-to-date `stat` (identity/size/mtime) for the file so the read
137155
+ * path can detect truncation/replacement.
137156
+ *
137157
+ * `readFrom` is the absolute byte offset the watcher read started at, and
137158
+ * `endOffset` is where it ended (readFrom + consumed, i.e. the watcher's new
137159
+ * entry.offset). CONTIGUITY GUARD: the read must begin exactly where the index
137160
+ * left off (`readFrom === existing.byte_offset`, or 0 with no state). If it
137161
+ * doesn't — the watcher attached at EOF after the server was down, or an
137162
+ * append raced an in-flight backfill — extending would assign wrong
137163
+ * message_index values over a hole. In that case this writes nothing and
137164
+ * returns null so the caller drops the index and backfills.
137165
+ *
137166
+ * On success returns the message_index assigned to each input span (null for a
137167
+ * non-message line) so the caller can stamp WS `seq`. Empty array when spans
137168
+ * is empty. `endOffset` is stored verbatim as byte_offset so the watcher's
137169
+ * offset and file_state.byte_offset are the same number by construction.
137170
+ */
137171
+ extendMessageIndex(filePath, spans, stat10, readFrom, endOffset) {
137172
+ const existing = this.getFileState(filePath);
137173
+ const expectedStart = existing?.byte_offset ?? 0;
137174
+ if (readFrom !== expectedStart) return null;
137175
+ if (spans.length === 0) return [];
137176
+ const convId = _ConversationCache.conversationIdForFile(filePath);
137177
+ let state = this.indexParseState.get(filePath);
137178
+ if (!state) {
137179
+ state = initialConvState();
137180
+ this.indexParseState.set(filePath, state);
137181
+ }
137182
+ let nextIndex = existing ? existing.last_message_index + 1 : 0;
137183
+ const rows = [];
137184
+ const seqs = [];
137185
+ for (const span of spans) {
137186
+ const msg = parseJsonlLine(span.text, state);
137187
+ if (!msg) {
137188
+ seqs.push(null);
137189
+ continue;
137190
+ }
137191
+ rows.push({
137192
+ conversation_id: convId,
137193
+ message_index: nextIndex,
137194
+ byte_offset: span.byteOffset,
137195
+ byte_length: span.byteLength,
137196
+ uuid: msg.uuid ?? null,
137197
+ role: msg.role ?? null,
137198
+ ts: msg.timestamp ? Date.parse(msg.timestamp) || null : null
137199
+ });
137200
+ seqs.push(nextIndex);
137201
+ nextIndex++;
137202
+ }
137203
+ const tx = this.db.transaction(() => {
137204
+ for (const r of rows) this.stmts.insertMessageIndexRow.run(r);
137205
+ this.stmts.upsertFileState.run({
137206
+ path: filePath,
137207
+ identity: fileIdentity(stat10),
137208
+ size: stat10.size,
137209
+ mtime_ms: Math.round(stat10.mtimeMs),
137210
+ // Store the watcher's end offset verbatim — same number as entry.offset,
137211
+ // so the next read's contiguity check compares like-for-like (never
137212
+ // false-positive on a read that ended in trailing empty lines).
137213
+ byte_offset: endOffset,
137214
+ last_message_index: nextIndex - 1
137215
+ });
137216
+ });
137217
+ tx();
137218
+ return seqs;
137219
+ }
137220
+ clearIndexParseState(filePath) {
137221
+ this.indexParseState.delete(filePath);
137222
+ }
137223
+ /**
137224
+ * On-demand full backfill of the offset index for a file with no/stale
137225
+ * file_state (cold conversation, or after a truncation/replacement). Rebuilds
137226
+ * from byte 0: drops any existing rows, walks the whole file in chunks with a
137227
+ * running parse state, yields to the event loop every ~1000 lines so a large
137228
+ * file never blocks, and writes index rows + file_state.
137229
+ *
137230
+ * Single-flighted per path: concurrent callers await the same walk. The
137231
+ * triggering detail request is served by the scanner fallback while this runs.
137232
+ */
137233
+ backfillIndex(filePath) {
137234
+ const inFlight = this.backfillInFlight.get(filePath);
137235
+ if (inFlight) return inFlight;
137236
+ const walk = this.runBackfill(filePath).finally(() => {
137237
+ this.backfillInFlight.delete(filePath);
137238
+ });
137239
+ this.backfillInFlight.set(filePath, walk);
137240
+ return walk;
137241
+ }
137242
+ async runBackfill(filePath) {
137243
+ const convId = _ConversationCache.conversationIdForFile(filePath);
137244
+ this.deleteFileIndex(filePath, convId);
137245
+ this.indexParseState.delete(filePath);
137246
+ const CHUNK = 256 * 1024;
137247
+ const YIELD_EVERY = 1e3;
137248
+ const state = initialConvState();
137249
+ const fh = await (0, import_promises12.open)(filePath, "r");
137250
+ let fileOffset = 0;
137251
+ let carry = Buffer.alloc(0);
137252
+ let nextIndex = 0;
137253
+ let linesSinceYield = 0;
137254
+ let lastConsumedEnd = 0;
137255
+ let stat10;
137256
+ try {
137257
+ stat10 = await fh.stat();
137258
+ const buf = Buffer.alloc(CHUNK);
137259
+ for (; ; ) {
137260
+ const { bytesRead } = await fh.read(buf, 0, CHUNK, null);
137261
+ if (bytesRead === 0) break;
137262
+ const combined = carry.length > 0 ? Buffer.concat([carry, buf.subarray(0, bytesRead)]) : buf.subarray(0, bytesRead);
137263
+ const { spans, consumed } = splitCompleteLines(combined, fileOffset);
137264
+ const rows = [];
137265
+ for (const span of spans) {
137266
+ const msg = parseJsonlLine(span.text, state);
137267
+ linesSinceYield++;
137268
+ if (msg) {
137269
+ rows.push({
137270
+ conversation_id: convId,
137271
+ message_index: nextIndex,
137272
+ byte_offset: span.byteOffset,
137273
+ byte_length: span.byteLength,
137274
+ uuid: msg.uuid ?? null,
137275
+ role: msg.role ?? null,
137276
+ ts: msg.timestamp ? Date.parse(msg.timestamp) || null : null
137277
+ });
137278
+ nextIndex++;
137279
+ }
137280
+ if (linesSinceYield >= YIELD_EVERY) {
137281
+ linesSinceYield = 0;
137282
+ await (0, import_promises13.setImmediate)();
137283
+ }
137284
+ }
137285
+ if (rows.length > 0) this.appendMessageIndexRows(rows);
137286
+ lastConsumedEnd = fileOffset + consumed;
137287
+ carry = Buffer.from(combined.subarray(consumed));
137288
+ fileOffset += consumed;
137289
+ }
137290
+ } finally {
137291
+ await fh.close();
137292
+ }
137293
+ this.upsertFileState({
137294
+ path: filePath,
137295
+ identity: fileIdentity(stat10),
137296
+ size: stat10.size,
137297
+ mtime_ms: Math.round(stat10.mtimeMs),
137298
+ byte_offset: lastConsumedEnd,
137299
+ last_message_index: nextIndex - 1
137300
+ });
137301
+ this.indexParseState.set(filePath, state);
137302
+ }
137303
+ /**
137304
+ * Windowed detail read straight from the offset index — the hot path.
137305
+ * Returns the parsed messages for message_index in [fromIndex, toIndex) plus
137306
+ * the total indexed count, or null when the index can't serve this file (no
137307
+ * file_state, identity/size mismatch = truncation/replacement, or cold index)
137308
+ * so the caller falls back to the scanner and enqueues a backfill.
137309
+ *
137310
+ * On a match it SQL-selects the window's byte ranges and preads exactly those
137311
+ * ranges from the JSONL (never the whole file), parsing only the sliced lines.
137312
+ * Returns messages in the same ConversationMessage shape parseJsonlLine
137313
+ * produces during a scan, so the payload is identical to the scanner path.
137314
+ */
137315
+ readMessageWindow(filePath, fromIndex, toIndex) {
137316
+ const fileState = this.getFileState(filePath);
137317
+ if (!fileState) return null;
137318
+ let stat10;
137319
+ try {
137320
+ stat10 = (0, import_fs17.statSync)(filePath);
137321
+ } catch {
137322
+ return null;
137323
+ }
137324
+ if (fileIdentity(stat10) !== fileState.identity || stat10.size !== fileState.byte_offset) {
137325
+ return null;
137326
+ }
137327
+ const total = fileState.last_message_index + 1;
137328
+ const from = Math.max(0, fromIndex);
137329
+ const to2 = Math.min(toIndex, total);
137330
+ if (to2 <= from) return { messages: [], total, fromIndex: from };
137331
+ const rows = this.getMessageIndexWindow(
137332
+ _ConversationCache.conversationIdForFile(filePath),
137333
+ from,
137334
+ to2
137335
+ );
137336
+ if (rows.length === 0) return { messages: [], total, fromIndex: from };
137337
+ const messages = [];
137338
+ const fd = (0, import_fs17.openSync)(filePath, "r");
137339
+ try {
137340
+ const state = initialConvState();
137341
+ for (const row of rows) {
137342
+ const buf = Buffer.alloc(row.byte_length);
137343
+ (0, import_fs17.readSync)(fd, buf, 0, row.byte_length, row.byte_offset);
137344
+ const msg = parseJsonlLine(buf.toString("utf-8"), state);
137345
+ if (msg) messages.push(msg);
137346
+ }
137347
+ } finally {
137348
+ (0, import_fs17.closeSync)(fd);
137349
+ }
137350
+ return { messages, total, fromIndex: from };
137351
+ }
137009
137352
  agentEntrypointsKey() {
137010
137353
  return [...this.agentEntrypoints].sort().join(",");
137011
137354
  }
@@ -137030,14 +137373,14 @@ var ConversationCache = class _ConversationCache {
137030
137373
  isAgentFileCached(filePath) {
137031
137374
  let s3;
137032
137375
  try {
137033
- s3 = (0, import_fs16.statSync)(filePath);
137376
+ s3 = (0, import_fs17.statSync)(filePath);
137034
137377
  } catch {
137035
137378
  return false;
137036
137379
  }
137037
137380
  return this.classifyAgentFile(filePath, s3.mtimeMs, s3.size);
137038
137381
  }
137039
137382
  static open(dbPath, tailSize = 10, migrationsDir, options) {
137040
- (0, import_fs16.mkdirSync)((0, import_path13.dirname)(dbPath), { recursive: true });
137383
+ (0, import_fs17.mkdirSync)((0, import_path13.dirname)(dbPath), { recursive: true });
137041
137384
  const db = new import_better_sqlite32.default(dbPath);
137042
137385
  db.pragma("journal_mode = WAL");
137043
137386
  db.pragma("foreign_keys = ON");
@@ -137218,7 +137561,7 @@ var ConversationCache = class _ConversationCache {
137218
137561
  let mtimeMs = null;
137219
137562
  let fileSize = null;
137220
137563
  try {
137221
- const s3 = (0, import_fs16.statSync)(m2.filePath);
137564
+ const s3 = (0, import_fs17.statSync)(m2.filePath);
137222
137565
  mtimeMs = s3.mtimeMs;
137223
137566
  fileSize = s3.size;
137224
137567
  } catch {
@@ -137277,8 +137620,8 @@ var ConversationCache = class _ConversationCache {
137277
137620
  let fileSize;
137278
137621
  let fd;
137279
137622
  try {
137280
- fileSize = (0, import_fs16.statSync)(filePath).size;
137281
- fd = (0, import_fs16.openSync)(filePath, "r");
137623
+ fileSize = (0, import_fs17.statSync)(filePath).size;
137624
+ fd = (0, import_fs17.openSync)(filePath, "r");
137282
137625
  } catch {
137283
137626
  return false;
137284
137627
  }
@@ -137291,7 +137634,7 @@ var ConversationCache = class _ConversationCache {
137291
137634
  while (pos > 0 && lines.length < this.tailSize * 4) {
137292
137635
  const toRead = Math.min(CHUNK, pos);
137293
137636
  pos -= toRead;
137294
- (0, import_fs16.readSync)(fd, buf, 0, toRead, pos);
137637
+ (0, import_fs17.readSync)(fd, buf, 0, toRead, pos);
137295
137638
  const chunk = buf.subarray(0, toRead).toString("utf8");
137296
137639
  const combined = chunk + partial2;
137297
137640
  const parts = combined.split("\n");
@@ -137302,7 +137645,7 @@ var ConversationCache = class _ConversationCache {
137302
137645
  }
137303
137646
  if (partial2) lines.push(partial2);
137304
137647
  } finally {
137305
- (0, import_fs16.closeSync)(fd);
137648
+ (0, import_fs17.closeSync)(fd);
137306
137649
  }
137307
137650
  const msgs = [];
137308
137651
  for (let i = 0; i < lines.length && msgs.length < this.tailSize; i++) {
@@ -137504,7 +137847,7 @@ var ConversationCache = class _ConversationCache {
137504
137847
  * `handleGetConversation` can still serve the cached tail even when the
137505
137848
  * JSONL has been deleted.
137506
137849
  */
137507
- pruneGhostFiles(exists = import_fs16.existsSync) {
137850
+ pruneGhostFiles(exists = import_fs17.existsSync) {
137508
137851
  const rows = this.stmts.allFilePaths.all();
137509
137852
  const ghosts = [];
137510
137853
  const prune = this.db.transaction((ids) => {
@@ -137559,7 +137902,7 @@ var ConversationCache = class _ConversationCache {
137559
137902
  * Returns the removed IDs.
137560
137903
  */
137561
137904
  reconcileDeletions(livePaths, opts) {
137562
- const exists = opts?.exists ?? import_fs16.existsSync;
137905
+ const exists = opts?.exists ?? import_fs17.existsSync;
137563
137906
  const rows = this.stmts.allFilePaths.all();
137564
137907
  const removed = [];
137565
137908
  const drop = this.db.transaction((ids) => {
@@ -137617,7 +137960,7 @@ function getDbConfig() {
137617
137960
  }
137618
137961
 
137619
137962
  // src/db/migrations.ts
137620
- var import_fs17 = require("fs");
137963
+ var import_fs18 = require("fs");
137621
137964
  var import_path14 = require("path");
137622
137965
  var import_url7 = require("url");
137623
137966
  var import_meta2 = {};
@@ -137640,10 +137983,10 @@ async function runMigrations2(pool2, migrationsDir) {
137640
137983
  );
137641
137984
  const appliedSet = new Set(applied.map((r) => r.name));
137642
137985
  const dir = migrationsDir ?? (0, import_path14.join)(getMigrationsDir2(), "pg-migrations");
137643
- const files = (0, import_fs17.readdirSync)(dir).filter((f2) => f2.endsWith(".sql")).sort();
137986
+ const files = (0, import_fs18.readdirSync)(dir).filter((f2) => f2.endsWith(".sql")).sort();
137644
137987
  for (const file2 of files) {
137645
137988
  if (appliedSet.has(file2)) continue;
137646
- const sql = (0, import_fs17.readFileSync)((0, import_path14.join)(dir, file2), "utf-8");
137989
+ const sql = (0, import_fs18.readFileSync)((0, import_path14.join)(dir, file2), "utf-8");
137647
137990
  await pool2.query(sql);
137648
137991
  await pool2.query("INSERT INTO _migrations (name) VALUES ($1)", [file2]);
137649
137992
  }
@@ -137729,7 +138072,7 @@ var ConversationsRepository = class {
137729
138072
  };
137730
138073
 
137731
138074
  // src/db/repositories/projects.repository.ts
137732
- var import_crypto5 = require("crypto");
138075
+ var import_crypto6 = require("crypto");
137733
138076
 
137734
138077
  // src/utils/canonicalizeProjectPath.ts
137735
138078
  function canonicalizeProjectPath(projectPath) {
@@ -137822,7 +138165,7 @@ var ProjectsRepository = class {
137822
138165
  });
137823
138166
  return rowToProject(this.getById.get(existing.id));
137824
138167
  }
137825
- const id = (0, import_crypto5.randomUUID)();
138168
+ const id = (0, import_crypto6.randomUUID)();
137826
138169
  this.insert.run({
137827
138170
  id,
137828
138171
  path: path2,
@@ -137878,7 +138221,7 @@ async function recordUpload(pool2, instanceId, row) {
137878
138221
  }
137879
138222
 
137880
138223
  // src/handlers/handleListProjects.ts
137881
- var import_fs18 = require("fs");
138224
+ var import_fs19 = require("fs");
137882
138225
  var import_os7 = require("os");
137883
138226
  var import_path15 = require("path");
137884
138227
  function decodeProjectPath(dirName) {
@@ -137890,11 +138233,11 @@ function handleListProjects(url2, res) {
137890
138233
  const projectsDir = (0, import_path15.join)((0, import_os7.homedir)(), ".claude", "projects");
137891
138234
  let entries;
137892
138235
  try {
137893
- entries = (0, import_fs18.readdirSync)(projectsDir).map((dirName) => {
138236
+ entries = (0, import_fs19.readdirSync)(projectsDir).map((dirName) => {
137894
138237
  const fullPath = (0, import_path15.join)(projectsDir, dirName);
137895
138238
  let mtime = 0;
137896
138239
  try {
137897
- mtime = (0, import_fs18.statSync)(fullPath).mtimeMs;
138240
+ mtime = (0, import_fs19.statSync)(fullPath).mtimeMs;
137898
138241
  } catch {
137899
138242
  }
137900
138243
  const path2 = decodeProjectPath(dirName);
@@ -137917,14 +138260,14 @@ var import_path19 = require("path");
137917
138260
 
137918
138261
  // src/codex-pty-runner.ts
137919
138262
  var import_headless = __toESM(require_xterm_headless(), 1);
137920
- var import_crypto6 = require("crypto");
137921
- var import_fs20 = require("fs");
138263
+ var import_crypto7 = require("crypto");
138264
+ var import_fs21 = require("fs");
137922
138265
  var import_path17 = require("path");
137923
138266
  init_logger();
137924
138267
 
137925
138268
  // src/platform.ts
137926
138269
  var import_child_process = require("child_process");
137927
- var import_fs19 = require("fs");
138270
+ var import_fs20 = require("fs");
137928
138271
  var import_os8 = require("os");
137929
138272
  var import_path16 = require("path");
137930
138273
  var isWindows2 = (0, import_os8.platform)() === "win32";
@@ -137954,7 +138297,7 @@ function resolveClaudeExe() {
137954
138297
  )
137955
138298
  ];
137956
138299
  for (const p2 of candidates) {
137957
- if ((0, import_fs19.existsSync)(p2)) {
138300
+ if ((0, import_fs20.existsSync)(p2)) {
137958
138301
  _claudeExe = p2;
137959
138302
  return _claudeExe;
137960
138303
  }
@@ -137965,7 +138308,7 @@ function resolveClaudeExe() {
137965
138308
  encoding: "utf-8",
137966
138309
  timeout: 3e3
137967
138310
  }).trim().split("\n")[0].trim();
137968
- if (found && (0, import_fs19.existsSync)(found)) {
138311
+ if (found && (0, import_fs20.existsSync)(found)) {
137969
138312
  _claudeExe = found;
137970
138313
  return _claudeExe;
137971
138314
  }
@@ -137977,7 +138320,7 @@ function resolveClaudeExe() {
137977
138320
  (0, import_path16.join)((0, import_os8.homedir)(), ".local", "bin", "claude")
137978
138321
  ];
137979
138322
  for (const p2 of candidates) {
137980
- if ((0, import_fs19.existsSync)(p2)) {
138323
+ if ((0, import_fs20.existsSync)(p2)) {
137981
138324
  _claudeExe = p2;
137982
138325
  return _claudeExe;
137983
138326
  }
@@ -138012,7 +138355,7 @@ function resolveCodexExe() {
138012
138355
  )
138013
138356
  ];
138014
138357
  for (const p2 of candidates) {
138015
- if ((0, import_fs19.existsSync)(p2)) {
138358
+ if ((0, import_fs20.existsSync)(p2)) {
138016
138359
  _codexExe = p2;
138017
138360
  return _codexExe;
138018
138361
  }
@@ -138023,7 +138366,7 @@ function resolveCodexExe() {
138023
138366
  encoding: "utf-8",
138024
138367
  timeout: 3e3
138025
138368
  }).trim().split("\n")[0].trim();
138026
- if (found && (0, import_fs19.existsSync)(found)) {
138369
+ if (found && (0, import_fs20.existsSync)(found)) {
138027
138370
  _codexExe = found;
138028
138371
  return _codexExe;
138029
138372
  }
@@ -138035,7 +138378,7 @@ function resolveCodexExe() {
138035
138378
  (0, import_path16.join)((0, import_os8.homedir)(), ".local", "bin", "codex")
138036
138379
  ];
138037
138380
  for (const p2 of candidates) {
138038
- if ((0, import_fs19.existsSync)(p2)) {
138381
+ if ((0, import_fs20.existsSync)(p2)) {
138039
138382
  _codexExe = p2;
138040
138383
  return _codexExe;
138041
138384
  }
@@ -138172,7 +138515,7 @@ var CodexPtyRunner = class {
138172
138515
  // ManagedSession handle only.
138173
138516
  async startFresh(options) {
138174
138517
  const nodePty = await loadPty();
138175
- const sessionId = (0, import_crypto6.randomUUID)();
138518
+ const sessionId = (0, import_crypto7.randomUUID)();
138176
138519
  const projectName = options.projectName ?? (0, import_path17.basename)(options.projectPath);
138177
138520
  const args = ["--cd", options.projectPath, "--no-alt-screen"];
138178
138521
  if (options.systemPrompt) {
@@ -138465,7 +138808,7 @@ var CodexPtyRunner = class {
138465
138808
  session.status = "idle";
138466
138809
  const elapsedMs = session.completedAt.getTime() - session.startedAt.getTime();
138467
138810
  if (exitCode !== 0 && elapsedMs < 2e3 && session.lastOutput === "") {
138468
- if (!(0, import_fs20.existsSync)(session.projectPath)) {
138811
+ if (!(0, import_fs21.existsSync)(session.projectPath)) {
138469
138812
  session.failureReason = `Project directory not found: ${session.projectPath}`;
138470
138813
  } else {
138471
138814
  session.failureReason = `Codex process exited immediately (code ${exitCode}).`;
@@ -138501,8 +138844,8 @@ function stripAnsi(str) {
138501
138844
 
138502
138845
  // src/pty-manager.ts
138503
138846
  var import_headless2 = __toESM(require_xterm_headless(), 1);
138504
- var import_crypto7 = require("crypto");
138505
- var import_fs21 = require("fs");
138847
+ var import_crypto8 = require("crypto");
138848
+ var import_fs22 = require("fs");
138506
138849
  var import_path18 = require("path");
138507
138850
  init_logger();
138508
138851
 
@@ -138905,7 +139248,7 @@ var PTYManager = class {
138905
139248
  // onReady fires once Claude reaches its first prompt (waiting_input).
138906
139249
  async startFresh(options) {
138907
139250
  const nodePty = await loadPty2();
138908
- const sessionId = (0, import_crypto7.randomUUID)();
139251
+ const sessionId = (0, import_crypto8.randomUUID)();
138909
139252
  const projectName = options.projectName ?? (0, import_path18.basename)(options.projectPath);
138910
139253
  const args = [
138911
139254
  "--permission-mode",
@@ -139350,7 +139693,7 @@ var PTYManager = class {
139350
139693
  session.status = "idle";
139351
139694
  const elapsedMs = session.completedAt.getTime() - session.startedAt.getTime();
139352
139695
  if (exitCode !== 0 && elapsedMs < 2e3 && session.lastOutput === "") {
139353
- if (!(0, import_fs21.existsSync)(session.projectPath)) {
139696
+ if (!(0, import_fs22.existsSync)(session.projectPath)) {
139354
139697
  session.failureReason = `Project directory not found: ${session.projectPath}`;
139355
139698
  } else {
139356
139699
  session.failureReason = `Process exited immediately (code ${exitCode}). Check that the Claude binary is installed and accessible.`;
@@ -139489,7 +139832,7 @@ var LiveSessionManager = class {
139489
139832
  init_logger();
139490
139833
 
139491
139834
  // src/pair-store.ts
139492
- var import_crypto8 = require("crypto");
139835
+ var import_crypto9 = require("crypto");
139493
139836
  var DEFAULT_TTL_SECONDS = 180;
139494
139837
  var SWEEP_INTERVAL_MS = 6e4;
139495
139838
  var PairTokenStore = class {
@@ -139504,7 +139847,7 @@ var PairTokenStore = class {
139504
139847
  }
139505
139848
  }
139506
139849
  mint() {
139507
- const token = `pt_${(0, import_crypto8.randomBytes)(16).toString("hex")}`;
139850
+ const token = `pt_${(0, import_crypto9.randomBytes)(16).toString("hex")}`;
139508
139851
  const expiresAt = Date.now() + this.ttlMs;
139509
139852
  this.current = { token, expiresAt, used: false };
139510
139853
  return {
@@ -139709,11 +140052,11 @@ function seal(plaintext, recipientPublicKeyBase64) {
139709
140052
  // node_modules/chokidar/index.js
139710
140053
  var import_node_events2 = require("events");
139711
140054
  var import_node_fs7 = require("fs");
139712
- var import_promises14 = require("fs/promises");
140055
+ var import_promises16 = require("fs/promises");
139713
140056
  var sp2 = __toESM(require("path"), 1);
139714
140057
 
139715
140058
  // node_modules/readdirp/index.js
139716
- var import_promises12 = require("fs/promises");
140059
+ var import_promises14 = require("fs/promises");
139717
140060
  var import_node_path9 = require("path");
139718
140061
  var import_node_stream2 = require("stream");
139719
140062
  var EntryTypes2 = {
@@ -139794,7 +140137,7 @@ var ReaddirpStream2 = class extends import_node_stream2.Readable {
139794
140137
  const { root, type } = opts;
139795
140138
  this._fileFilter = normalizeFilter2(opts.fileFilter);
139796
140139
  this._directoryFilter = normalizeFilter2(opts.directoryFilter);
139797
- const statMethod = opts.lstat ? import_promises12.lstat : import_promises12.stat;
140140
+ const statMethod = opts.lstat ? import_promises14.lstat : import_promises14.stat;
139798
140141
  if (wantBigintFsStats2) {
139799
140142
  this._stat = (path2) => statMethod(path2, { bigint: true });
139800
140143
  } else {
@@ -139865,7 +140208,7 @@ var ReaddirpStream2 = class extends import_node_stream2.Readable {
139865
140208
  async _exploreDir(path2, depth) {
139866
140209
  let files;
139867
140210
  try {
139868
- files = await (0, import_promises12.readdir)(path2, this._rdOptions);
140211
+ files = await (0, import_promises14.readdir)(path2, this._rdOptions);
139869
140212
  } catch (error51) {
139870
140213
  this._onError(error51);
139871
140214
  }
@@ -139903,8 +140246,8 @@ var ReaddirpStream2 = class extends import_node_stream2.Readable {
139903
140246
  if (stats && stats.isSymbolicLink()) {
139904
140247
  const full = entry.fullPath;
139905
140248
  try {
139906
- const entryRealPath = await (0, import_promises12.realpath)(full);
139907
- const entryRealPathStats = await (0, import_promises12.lstat)(entryRealPath);
140249
+ const entryRealPath = await (0, import_promises14.realpath)(full);
140250
+ const entryRealPathStats = await (0, import_promises14.lstat)(entryRealPath);
139908
140251
  if (entryRealPathStats.isFile()) {
139909
140252
  return "file";
139910
140253
  }
@@ -139947,7 +140290,7 @@ function readdirp2(root, options = {}) {
139947
140290
 
139948
140291
  // node_modules/chokidar/handler.js
139949
140292
  var import_node_fs6 = require("fs");
139950
- var import_promises13 = require("fs/promises");
140293
+ var import_promises15 = require("fs/promises");
139951
140294
  var import_node_os3 = require("os");
139952
140295
  var sp = __toESM(require("path"), 1);
139953
140296
  var STR_DATA2 = "data";
@@ -139974,7 +140317,7 @@ var EVENTS2 = {
139974
140317
  };
139975
140318
  var EV2 = EVENTS2;
139976
140319
  var THROTTLE_MODE_WATCH2 = "watch";
139977
- var statMethods2 = { lstat: import_promises13.lstat, stat: import_promises13.stat };
140320
+ var statMethods2 = { lstat: import_promises15.lstat, stat: import_promises15.stat };
139978
140321
  var KEY_LISTENERS2 = "listeners";
139979
140322
  var KEY_ERR2 = "errHandlers";
139980
140323
  var KEY_RAW2 = "rawEmitters";
@@ -140331,7 +140674,7 @@ var setFsWatchListener2 = (path2, fullPath, options, handlers) => {
140331
140674
  cont.watcherUnusable = true;
140332
140675
  if (isWindows3 && error51.code === "EPERM") {
140333
140676
  try {
140334
- const fd = await (0, import_promises13.open)(path2, "r");
140677
+ const fd = await (0, import_promises15.open)(path2, "r");
140335
140678
  await fd.close();
140336
140679
  broadcastErr(error51);
140337
140680
  } catch (err) {
@@ -140462,7 +140805,7 @@ var NodeFsHandler2 = class {
140462
140805
  return;
140463
140806
  if (!newStats || newStats.mtimeMs === 0) {
140464
140807
  try {
140465
- const newStats2 = await (0, import_promises13.stat)(file2);
140808
+ const newStats2 = await (0, import_promises15.stat)(file2);
140466
140809
  if (this.fsw.closed)
140467
140810
  return;
140468
140811
  const at2 = newStats2.atimeMs;
@@ -140517,7 +140860,7 @@ var NodeFsHandler2 = class {
140517
140860
  this.fsw._incrReadyCount();
140518
140861
  let linkPath;
140519
140862
  try {
140520
- linkPath = await (0, import_promises13.realpath)(path2);
140863
+ linkPath = await (0, import_promises15.realpath)(path2);
140521
140864
  } catch (e) {
140522
140865
  this.fsw._emitReady();
140523
140866
  return true;
@@ -140666,7 +141009,7 @@ var NodeFsHandler2 = class {
140666
141009
  let closer;
140667
141010
  if (stats.isDirectory()) {
140668
141011
  const absPath = sp.resolve(path2);
140669
- const targetPath = follow ? await (0, import_promises13.realpath)(path2) : path2;
141012
+ const targetPath = follow ? await (0, import_promises15.realpath)(path2) : path2;
140670
141013
  if (this.fsw.closed)
140671
141014
  return;
140672
141015
  closer = await this._handleDir(wh.watchPath, stats, initialAdd, depth, target, wh, targetPath);
@@ -140676,7 +141019,7 @@ var NodeFsHandler2 = class {
140676
141019
  this.fsw._symlinkPaths.set(absPath, targetPath);
140677
141020
  }
140678
141021
  } else if (stats.isSymbolicLink()) {
140679
- const targetPath = follow ? await (0, import_promises13.realpath)(path2) : path2;
141022
+ const targetPath = follow ? await (0, import_promises15.realpath)(path2) : path2;
140680
141023
  if (this.fsw.closed)
140681
141024
  return;
140682
141025
  const parent = sp.dirname(wh.watchPath);
@@ -140836,7 +141179,7 @@ var DirEntry2 = class {
140836
141179
  return;
140837
141180
  const dir = this.path;
140838
141181
  try {
140839
- await (0, import_promises14.readdir)(dir);
141182
+ await (0, import_promises16.readdir)(dir);
140840
141183
  } catch (err) {
140841
141184
  if (this._removeWatcher) {
140842
141185
  this._removeWatcher(sp2.dirname(dir), sp2.basename(dir));
@@ -141186,7 +141529,7 @@ var FSWatcher2 = class extends import_node_events2.EventEmitter {
141186
141529
  const fullPath = opts.cwd ? sp2.join(opts.cwd, path2) : path2;
141187
141530
  let stats2;
141188
141531
  try {
141189
- stats2 = await (0, import_promises14.stat)(fullPath);
141532
+ stats2 = await (0, import_promises16.stat)(fullPath);
141190
141533
  } catch (err) {
141191
141534
  }
141192
141535
  if (!stats2 || this.closed)
@@ -141439,19 +141782,21 @@ function watch2(paths, options = {}) {
141439
141782
  var chokidar_default = { watch: watch2, FSWatcher: FSWatcher2 };
141440
141783
 
141441
141784
  // src/services/conversations/conversationWatcher.ts
141442
- var import_fs22 = require("fs");
141443
- var import_promises15 = require("fs/promises");
141785
+ var import_fs23 = require("fs");
141786
+ var import_promises17 = require("fs/promises");
141444
141787
  var ConversationWatcher = class {
141445
141788
  files = /* @__PURE__ */ new Map();
141446
141789
  directories = /* @__PURE__ */ new Map();
141447
141790
  onNewLine;
141448
141791
  onNewLines;
141792
+ onNewLineSpans;
141449
141793
  onConversationChanged;
141450
141794
  onFileDeleted;
141451
141795
  onError;
141452
141796
  constructor(events = {}) {
141453
141797
  this.onNewLine = events.onNewLine;
141454
141798
  this.onNewLines = events.onNewLines;
141799
+ this.onNewLineSpans = events.onNewLineSpans;
141455
141800
  this.onConversationChanged = events.onConversationChanged;
141456
141801
  this.onFileDeleted = events.onFileDeleted;
141457
141802
  this.onError = events.onError;
@@ -141460,7 +141805,7 @@ var ConversationWatcher = class {
141460
141805
  if (this.files.has(filePath)) return;
141461
141806
  let offset;
141462
141807
  try {
141463
- offset = (0, import_fs22.statSync)(filePath).size;
141808
+ offset = (0, import_fs23.statSync)(filePath).size;
141464
141809
  } catch {
141465
141810
  offset = 0;
141466
141811
  }
@@ -141544,20 +141889,24 @@ var ConversationWatcher = class {
141544
141889
  entry.reading = true;
141545
141890
  try {
141546
141891
  for (; ; ) {
141547
- const st2 = await (0, import_promises15.stat)(filePath);
141892
+ const st2 = await (0, import_promises17.stat)(filePath);
141548
141893
  if (st2.size <= entry.offset) break;
141549
141894
  const readFrom = entry.offset;
141550
141895
  const bytesToRead = st2.size - readFrom;
141551
141896
  const buf = Buffer.alloc(bytesToRead);
141552
- const fh = await (0, import_promises15.open)(filePath, "r");
141897
+ const fh = await (0, import_promises17.open)(filePath, "r");
141553
141898
  try {
141554
141899
  await fh.read(buf, 0, bytesToRead, readFrom);
141555
141900
  } finally {
141556
141901
  await fh.close();
141557
141902
  }
141558
- entry.offset = readFrom + bytesToRead;
141903
+ const { spans, consumed } = splitCompleteLines(buf, readFrom);
141904
+ entry.offset = readFrom + consumed;
141559
141905
  if (!this.files.has(filePath)) return;
141560
- const lines = buf.toString("utf-8").split("\n").filter(Boolean);
141906
+ const lines = spans.map((s3) => s3.text);
141907
+ if (spans.length > 0) {
141908
+ this.onNewLineSpans?.(filePath, spans, readFrom, entry.offset);
141909
+ }
141561
141910
  if (this.onNewLines) {
141562
141911
  this.onNewLines(filePath, lines);
141563
141912
  } else {
@@ -141631,14 +141980,14 @@ function findSearchTarget(messages, query) {
141631
141980
  }
141632
141981
 
141633
141982
  // src/services/conversations/pruneAgentConversations.ts
141634
- var import_fs23 = require("fs");
141983
+ var import_fs24 = require("fs");
141635
141984
  function pruneAgentConversations(cache) {
141636
141985
  const db = cache.getDatabase();
141637
141986
  const rows = db.prepare("SELECT id, file_path FROM conversation_meta").all();
141638
141987
  let pruned = 0;
141639
141988
  let missing = 0;
141640
141989
  for (const row of rows) {
141641
- if (!(0, import_fs23.existsSync)(row.file_path)) {
141990
+ if (!(0, import_fs24.existsSync)(row.file_path)) {
141642
141991
  missing += 1;
141643
141992
  continue;
141644
141993
  }
@@ -141997,8 +142346,8 @@ function discoveredToResponse(d, conversationId) {
141997
142346
  }
141998
142347
 
141999
142348
  // src/uploads.ts
142000
- var import_crypto9 = require("crypto");
142001
- var import_promises16 = require("fs/promises");
142349
+ var import_crypto10 = require("crypto");
142350
+ var import_promises18 = require("fs/promises");
142002
142351
  var import_heic_convert = __toESM(require_heic_convert(), 1);
142003
142352
  var import_path21 = require("path");
142004
142353
  var UPLOAD_DIR_NAME = ".threadbase-uploads";
@@ -142031,12 +142380,12 @@ async function saveUploadFile(input) {
142031
142380
  mimeType = "image/jpeg";
142032
142381
  originalName = originalName.replace(/\.(heic|heif)$/i, ".jpg");
142033
142382
  }
142034
- const id = `up_${(0, import_crypto9.randomBytes)(8).toString("hex")}`;
142383
+ const id = `up_${(0, import_crypto10.randomBytes)(8).toString("hex")}`;
142035
142384
  const safeName = sanitizeFilename(originalName) || `file${MIME_TO_EXT[mimeType] ?? ""}`;
142036
142385
  const dir = (0, import_path21.join)(input.projectPath, UPLOAD_DIR_NAME, input.sessionId);
142037
- await (0, import_promises16.mkdir)(dir, { recursive: true });
142386
+ await (0, import_promises18.mkdir)(dir, { recursive: true });
142038
142387
  const filePath = (0, import_path21.join)(dir, `${Date.now()}-${id}-${safeName}`);
142039
- await (0, import_promises16.writeFile)(filePath, buffer);
142388
+ await (0, import_promises18.writeFile)(filePath, buffer);
142040
142389
  return {
142041
142390
  id,
142042
142391
  filePath,
@@ -142420,6 +142769,7 @@ var WSHub = class {
142420
142769
  var BROWSE_SYSTEM_PROMPT = (browseRoot) => `You are working within the project boundary: ${browseRoot}. Do not read, write, or execute commands that access files or directories outside this boundary.`;
142421
142770
  var DEFAULT_SYSTEM_PROMPT = "When presenting options or choices to the user, limit the options to at most 3.";
142422
142771
  var DEFAULT_PTY_GRACE_PERIOD_MS = 27e4;
142772
+ var REFRESH_TTL_MS = 2e3;
142423
142773
  var START_READY_TIMEOUT_MS = 15e3;
142424
142774
  function parseIncludeAgentsEnv(raw2) {
142425
142775
  if (raw2 === void 0) return false;
@@ -142434,6 +142784,10 @@ var StreamerServer = class {
142434
142784
  fileWatcher;
142435
142785
  sessionFileMap = /* @__PURE__ */ new Map();
142436
142786
  // sessionId → JSONL filePath
142787
+ // Per-file seq assignments from the most recent onNewLineSpans (offset index),
142788
+ // handed to the immediately-following onNewLines so it can stamp WS `seq` on
142789
+ // the matching conversation_events entries. Same read → same lines order.
142790
+ pendingLineSeqs = /* @__PURE__ */ new Map();
142437
142791
  pendingQuestions = /* @__PURE__ */ new Map();
142438
142792
  // Content key of the AskUserQuestion currently broadcast for a session (from
142439
142793
  // either the rendered screen or JSONL), used to de-dupe the two paths: when
@@ -142459,6 +142813,12 @@ var StreamerServer = class {
142459
142813
  // Set by onConversationChanged while a scan is in-flight; getScanner() does
142460
142814
  // a single rescan after the current one completes instead of restarting it.
142461
142815
  scannerStale = false;
142816
+ // Single-flight + TTL guard around scanner.refreshFile (see refreshFileGuarded).
142817
+ // A live file's mtime is always newer than the snapshot, so an unguarded
142818
+ // refresh fires on every request and re-parses the whole file from byte 0.
142819
+ // Keyed by filePath; entries drop on settle + TTL expiry, so the map stays
142820
+ // bounded by the active-file set.
142821
+ refreshInFlight = /* @__PURE__ */ new Map();
142462
142822
  // True only while bindWithRetry is actively retrying. The persistent
142463
142823
  // listener-level 'error' handler demotes EADDRINUSE to debug during this
142464
142824
  // window so the self-healing kickstart-relaunch race doesn't spam warn.
@@ -142551,7 +142911,7 @@ var StreamerServer = class {
142551
142911
  this.agentEntrypoints = parseAgentEntrypointsEnv(process.env.THREADBASE_AGENT_ENTRYPOINTS);
142552
142912
  const rawRoot = process.env.THREADBASE_BROWSE_ROOT ?? loadBrowseRoot() ?? config2.browseRoot;
142553
142913
  if (rawRoot) {
142554
- (0, import_promises17.realpath)(rawRoot).then((resolved) => {
142914
+ (0, import_promises19.realpath)(rawRoot).then((resolved) => {
142555
142915
  this.browseRoot = resolved;
142556
142916
  if (this.verbose) this.log.info(`Browse root: ${resolved}`, { browseRoot: resolved });
142557
142917
  }).catch(() => {
@@ -142573,6 +142933,42 @@ var StreamerServer = class {
142573
142933
  this.sessionStore = new SessionStore();
142574
142934
  this.wsHub = new WSHub();
142575
142935
  this.fileWatcher = new ConversationWatcher({
142936
+ onNewLineSpans: (filePath, spans, readFrom, endOffset) => {
142937
+ if (!this.cache) return;
142938
+ const cache = this.cache;
142939
+ this.pendingLineSeqs.delete(filePath);
142940
+ try {
142941
+ const seqs = cache.extendMessageIndex(
142942
+ filePath,
142943
+ spans,
142944
+ (0, import_fs25.statSync)(filePath),
142945
+ readFrom,
142946
+ endOffset
142947
+ );
142948
+ if (seqs === null) {
142949
+ cache.deleteFileIndex(filePath, ConversationCache.conversationIdForFile(filePath));
142950
+ cache.clearIndexParseState(filePath);
142951
+ this.trackCacheWrite(
142952
+ cache.backfillIndex(filePath).catch((err) => {
142953
+ this.log.warn("offset-index.backfill_failed", {
142954
+ event: "offset_index.backfill_failed",
142955
+ filePath,
142956
+ trigger: "noncontiguous-append",
142957
+ err
142958
+ });
142959
+ })
142960
+ );
142961
+ return;
142962
+ }
142963
+ this.pendingLineSeqs.set(filePath, seqs);
142964
+ } catch (err) {
142965
+ this.log.warn("offset-index.extend_failed", {
142966
+ event: "offset_index.extend_failed",
142967
+ filePath,
142968
+ err
142969
+ });
142970
+ }
142971
+ },
142576
142972
  onNewLines: (filePath, lines) => {
142577
142973
  this.cache?.updateFromLines(filePath, lines);
142578
142974
  for (const [sessionId, watchedPath] of this.sessionFileMap) {
@@ -142599,13 +142995,20 @@ var StreamerServer = class {
142599
142995
  this.pendingQuestionKey.set(sessionId, key);
142600
142996
  if (broadcast) this.wsHub.broadcast(m2);
142601
142997
  }
142602
- this.wsHub.broadcast({ type: "conversation_events", sessionId, lines });
142998
+ const seqs = this.pendingLineSeqs.get(filePath);
142999
+ this.wsHub.broadcast({
143000
+ type: "conversation_events",
143001
+ sessionId,
143002
+ lines,
143003
+ ...seqs && seqs.length === lines.length ? { seqs } : {}
143004
+ });
142603
143005
  for (const line of lines) {
142604
143006
  this.wsHub.broadcast({ type: "conversation_event", sessionId, line });
142605
143007
  }
142606
143008
  break;
142607
143009
  }
142608
143010
  }
143011
+ this.pendingLineSeqs.delete(filePath);
142609
143012
  },
142610
143013
  onConversationChanged: (filePath) => {
142611
143014
  this.fileWatcher.poke(filePath);
@@ -142657,7 +143060,7 @@ var StreamerServer = class {
142657
143060
  if (session.status === "waiting_input" || session.status === "idle") {
142658
143061
  const filePath = this.sessionFileMap.get(session.id);
142659
143062
  if (filePath) {
142660
- this.getScanner().then((scanner) => scanner.refreshFile(filePath)).then((meta3) => {
143063
+ this.getScanner().then((scanner) => this.refreshFileGuarded(scanner, filePath)).then((meta3) => {
142661
143064
  this.log.info("scanner.refreshFile: ok", {
142662
143065
  event: "scanner.refresh",
142663
143066
  sessionId: session.id,
@@ -143106,6 +143509,34 @@ var StreamerServer = class {
143106
143509
  this.inFlightCacheWrites.delete(guarded);
143107
143510
  });
143108
143511
  }
143512
+ // Single-flight + TTL wrapper for scanner.refreshFile. Both call sites (the
143513
+ // detail-stale branch and the per-turn refresh) route through here so that
143514
+ // N stacked retries on a live, actively-appended file cost one parse, not N:
143515
+ // - a refresh already in flight for the path → await the same promise;
143516
+ // - a refresh that settled within REFRESH_TTL_MS → skip, return null (the
143517
+ // caller keeps serving the current snapshot);
143518
+ // - otherwise start one, cache the promise, and stamp completedAt on settle.
143519
+ // The map is bounded by the active-file set (entries only live while a
143520
+ // refresh is in flight or within its TTL and are overwritten on the next
143521
+ // refresh of the same path).
143522
+ refreshFileGuarded(scanner, filePath) {
143523
+ const existing = this.refreshInFlight.get(filePath);
143524
+ if (existing) {
143525
+ const settled = existing.completedAt > 0;
143526
+ if (!settled) {
143527
+ return existing.promise;
143528
+ }
143529
+ if (Date.now() - existing.completedAt < REFRESH_TTL_MS) {
143530
+ return Promise.resolve(null);
143531
+ }
143532
+ }
143533
+ const entry = { promise: Promise.resolve(null), completedAt: 0 };
143534
+ entry.promise = scanner.refreshFile(filePath).finally(() => {
143535
+ entry.completedAt = Date.now();
143536
+ });
143537
+ this.refreshInFlight.set(filePath, entry);
143538
+ return entry.promise;
143539
+ }
143109
143540
  async close() {
143110
143541
  for (const timer of this.ptyGraceTimers.values()) clearTimeout(timer);
143111
143542
  this.ptyGraceTimers.clear();
@@ -143516,16 +143947,16 @@ var StreamerServer = class {
143516
143947
  }
143517
143948
  findJsonlPath(uuid3) {
143518
143949
  const projectsDir = (0, import_path22.join)((0, import_os10.homedir)(), ".claude", "projects");
143519
- if (!(0, import_fs24.existsSync)(projectsDir)) return null;
143950
+ if (!(0, import_fs25.existsSync)(projectsDir)) return null;
143520
143951
  const filename = `${uuid3}.jsonl`;
143521
- for (const dir of (0, import_fs24.readdirSync)(projectsDir)) {
143952
+ for (const dir of (0, import_fs25.readdirSync)(projectsDir)) {
143522
143953
  const fp = (0, import_path22.join)(projectsDir, dir, filename);
143523
- if ((0, import_fs24.existsSync)(fp)) return fp;
143954
+ if ((0, import_fs25.existsSync)(fp)) return fp;
143524
143955
  const projectDir = (0, import_path22.join)(projectsDir, dir);
143525
143956
  try {
143526
- for (const sub of (0, import_fs24.readdirSync)(projectDir)) {
143957
+ for (const sub of (0, import_fs25.readdirSync)(projectDir)) {
143527
143958
  const subagentPath = (0, import_path22.join)(projectDir, sub, "subagents", filename);
143528
- if ((0, import_fs24.existsSync)(subagentPath)) return subagentPath;
143959
+ if ((0, import_fs25.existsSync)(subagentPath)) return subagentPath;
143529
143960
  }
143530
143961
  } catch {
143531
143962
  }
@@ -143534,7 +143965,7 @@ var StreamerServer = class {
143534
143965
  }
143535
143966
  async readCwdFromJsonl(filePath) {
143536
143967
  return new Promise((resolve6) => {
143537
- const rl = (0, import_readline4.createInterface)({ input: (0, import_fs24.createReadStream)(filePath), crlfDelay: Infinity });
143968
+ const rl = (0, import_readline4.createInterface)({ input: (0, import_fs25.createReadStream)(filePath), crlfDelay: Infinity });
143538
143969
  let found = false;
143539
143970
  rl.on("line", (line) => {
143540
143971
  if (found) return;
@@ -143570,10 +144001,22 @@ var StreamerServer = class {
143570
144001
  const scanner = await this.getScanner(true);
143571
144002
  const fromIndex = await scanner.getConversation(uuid3);
143572
144003
  if (fromIndex) {
144004
+ if (this.ptyManager.hasSession(uuid3)) {
144005
+ return fromIndex;
144006
+ }
143573
144007
  if (fromIndex.filePath && this.isConversationSnapshotStale(fromIndex)) {
143574
- const refreshedMeta = await scanner.refreshFile(fromIndex.filePath);
143575
- if (!refreshedMeta) return null;
143576
- return await scanner.getConversation(uuid3) ?? fromIndex;
144008
+ const filePath2 = fromIndex.filePath;
144009
+ this.trackCacheWrite(
144010
+ this.refreshFileGuarded(scanner, filePath2).catch((err) => {
144011
+ this.log.warn("scanner.refreshFile: failed", {
144012
+ event: "scanner.refresh_failed",
144013
+ conversationId: uuid3,
144014
+ filePath: filePath2,
144015
+ trigger: "detail-swr",
144016
+ err
144017
+ });
144018
+ })
144019
+ );
143577
144020
  }
143578
144021
  return fromIndex;
143579
144022
  }
@@ -143591,7 +144034,7 @@ var StreamerServer = class {
143591
144034
  if (!conv.filePath) return false;
143592
144035
  let mtimeMs = null;
143593
144036
  try {
143594
- mtimeMs = (0, import_fs24.statSync)(conv.filePath).mtimeMs;
144037
+ mtimeMs = (0, import_fs25.statSync)(conv.filePath).mtimeMs;
143595
144038
  } catch {
143596
144039
  return false;
143597
144040
  }
@@ -143649,9 +144092,13 @@ var StreamerServer = class {
143649
144092
  return;
143650
144093
  }
143651
144094
  const etagSource = conversation;
144095
+ const indexedCount = etagSource.filePath && this.cache ? this.cache.getIndexedMessageCount(
144096
+ ConversationCache.conversationIdForFile(etagSource.filePath)
144097
+ ) : 0;
144098
+ const etagMessageCount = Math.max(etagSource.messageCount, indexedCount);
143652
144099
  const etag = computeConversationEtag({
143653
144100
  filePath: etagSource.filePath,
143654
- messageCount: etagSource.messageCount,
144101
+ messageCount: etagMessageCount,
143655
144102
  timestamp: etagSource.timestamp
143656
144103
  });
143657
144104
  const isFirstPage = !url2.searchParams.has("before_index") && !url2.searchParams.has("anchor_index") && !url2.searchParams.has("after_index");
@@ -143668,12 +144115,14 @@ var StreamerServer = class {
143668
144115
  let slice = filtered;
143669
144116
  let fromIdx = 0;
143670
144117
  let messagePagination;
144118
+ let indexTotal = null;
143671
144119
  if (usePaging) {
143672
144120
  const limit = Math.min(Math.max(intParam(url2, "msg_limit", 80), 1), 500);
143673
144121
  let beforeIndex = total;
143674
144122
  let scanLimit = limit;
143675
144123
  let anchorIndex = null;
143676
144124
  let newerPaging = false;
144125
+ let usedAfterIndex = false;
143677
144126
  if (url2.searchParams.has("before_index")) {
143678
144127
  beforeIndex = intParam(url2, "before_index", total);
143679
144128
  beforeIndex = Math.min(Math.max(beforeIndex, 0), total);
@@ -143682,6 +144131,7 @@ var StreamerServer = class {
143682
144131
  beforeIndex = Math.min(total, from + limit);
143683
144132
  scanLimit = beforeIndex - from;
143684
144133
  newerPaging = true;
144134
+ usedAfterIndex = true;
143685
144135
  } else if (hasAnchor) {
143686
144136
  anchorIndex = Math.min(
143687
144137
  Math.max(intParam(url2, "anchor_index", 0), 0),
@@ -143691,9 +144141,34 @@ var StreamerServer = class {
143691
144141
  beforeIndex = Math.min(total, from + limit);
143692
144142
  newerPaging = true;
143693
144143
  }
143694
- const pagedScanner = this.scannerReady ? await this.getScanner(true) : null;
143695
- const page = scanLimit > 0 && pagedScanner && typeof pagedScanner.getConversationPage === "function" ? await pagedScanner.getConversationPage(id, { beforeIndex, limit: scanLimit }) : null;
143696
- const start = page?.fromIndex ?? Math.max(0, beforeIndex - scanLimit);
144144
+ const isTailRequest = !url2.searchParams.has("before_index") && !hasAfter && !hasAnchor;
144145
+ const indexFilePath = conversation.filePath;
144146
+ if (isTailRequest && indexFilePath && this.cache) {
144147
+ const indexed = this.cache.getIndexedMessageCount(
144148
+ ConversationCache.conversationIdForFile(indexFilePath)
144149
+ );
144150
+ if (indexed > beforeIndex) {
144151
+ beforeIndex = indexed;
144152
+ }
144153
+ }
144154
+ const windowStart = Math.max(0, beforeIndex - scanLimit);
144155
+ const indexWindow = scanLimit > 0 && !hasAnchor && indexFilePath && this.cache ? this.cache.readMessageWindow(indexFilePath, windowStart, beforeIndex) : null;
144156
+ if (!indexWindow && indexFilePath && this.cache && !hasAnchor) {
144157
+ this.trackCacheWrite(
144158
+ this.cache.backfillIndex(indexFilePath).catch((err) => {
144159
+ this.log.warn("offset-index.backfill_failed", {
144160
+ event: "offset_index.backfill_failed",
144161
+ conversationId: id,
144162
+ filePath: indexFilePath,
144163
+ err
144164
+ });
144165
+ })
144166
+ );
144167
+ }
144168
+ const pagedScanner = !indexWindow && this.scannerReady ? await this.getScanner(true) : null;
144169
+ const page = indexWindow ?? (scanLimit > 0 && pagedScanner && typeof pagedScanner.getConversationPage === "function" ? await pagedScanner.getConversationPage(id, { beforeIndex, limit: scanLimit }) : null);
144170
+ if (indexWindow) indexTotal = indexWindow.total;
144171
+ const start = page?.fromIndex ?? windowStart;
143697
144172
  slice = page?.messages ?? filtered.slice(start, beforeIndex);
143698
144173
  fromIdx = start;
143699
144174
  const effectiveTotal = page?.total ?? total;
@@ -143709,6 +144184,9 @@ var StreamerServer = class {
143709
144184
  messagePagination.has_more_newer = beforeIndex < effectiveTotal;
143710
144185
  messagePagination.next_after_index = beforeIndex < effectiveTotal ? beforeIndex : null;
143711
144186
  }
144187
+ if (usedAfterIndex) {
144188
+ messagePagination.etag = etag;
144189
+ }
143712
144190
  }
143713
144191
  const messagesPayload = slice.map((m2, localIdx) => {
143714
144192
  const content = [];
@@ -143750,6 +144228,8 @@ var StreamerServer = class {
143750
144228
  const cachedConvMeta = this.cache?.getMetaById(id);
143751
144229
  const convProvider = coerceProviderForRunner(conv.provider ?? cachedConvMeta?.provider);
143752
144230
  const availability = classifyResumability(conv.projectPath);
144231
+ const metaMessageCount = indexTotal != null && indexTotal > conv.messageCount ? indexTotal : conv.messageCount;
144232
+ const metaLastUpdatedAt = indexTotal != null && indexTotal > conv.messageCount ? slice.at(-1)?.timestamp ?? conv.timestamp : conv.timestamp;
143753
144233
  const body = {
143754
144234
  meta: {
143755
144235
  id,
@@ -143757,8 +144237,8 @@ var StreamerServer = class {
143757
144237
  project_name: conv.projectName,
143758
144238
  project_path: conv.projectPath,
143759
144239
  file_path: conv.filePath,
143760
- last_updated_at: conv.timestamp,
143761
- message_count: conv.messageCount,
144240
+ last_updated_at: metaLastUpdatedAt,
144241
+ message_count: metaMessageCount,
143762
144242
  last_prompt: conv.lastPrompt ?? void 0,
143763
144243
  provider: convProvider,
143764
144244
  resumable: isProviderResumable(convProvider, availability.resumable),
@@ -143921,7 +144401,7 @@ var StreamerServer = class {
143921
144401
  handleGetSession(sessionId, res) {
143922
144402
  const session = this.sessionStore.get(sessionId, this.ptyAttachedIds());
143923
144403
  if (session) {
143924
- if (!(0, import_fs24.existsSync)(session.projectPath)) {
144404
+ if (!(0, import_fs25.existsSync)(session.projectPath)) {
143925
144405
  session.failureReason = `Project directory not found: ${session.projectPath}`;
143926
144406
  }
143927
144407
  json2(res, 200, session);
@@ -144478,11 +144958,11 @@ var StreamerServer = class {
144478
144958
  cleanup();
144479
144959
  return;
144480
144960
  }
144481
- let resolvedFilePath = (0, import_fs24.existsSync)(filePath) ? filePath : null;
144482
- if (!resolvedFilePath && (0, import_fs24.existsSync)(projectsDir)) {
144961
+ let resolvedFilePath = (0, import_fs25.existsSync)(filePath) ? filePath : null;
144962
+ if (!resolvedFilePath && (0, import_fs25.existsSync)(projectsDir)) {
144483
144963
  try {
144484
144964
  const now = Date.now();
144485
- const recent = (0, import_fs24.readdirSync)(projectsDir).filter((f2) => f2.endsWith(".jsonl")).map((f2) => ({ f: f2, mtime: (0, import_fs24.statSync)((0, import_path22.join)(projectsDir, f2)).mtimeMs })).filter(({ mtime }) => now - mtime < 5e3).sort((a, b2) => b2.mtime - a.mtime)[0];
144965
+ const recent = (0, import_fs25.readdirSync)(projectsDir).filter((f2) => f2.endsWith(".jsonl")).map((f2) => ({ f: f2, mtime: (0, import_fs25.statSync)((0, import_path22.join)(projectsDir, f2)).mtimeMs })).filter(({ mtime }) => now - mtime < 5e3).sort((a, b2) => b2.mtime - a.mtime)[0];
144486
144966
  if (recent) resolvedFilePath = (0, import_path22.join)(projectsDir, recent.f);
144487
144967
  } catch {
144488
144968
  }
@@ -144492,7 +144972,7 @@ var StreamerServer = class {
144492
144972
  this.sessionFileMap.set(sessionId, resolvedFilePath);
144493
144973
  this.fileWatcher.watch(resolvedFilePath);
144494
144974
  try {
144495
- const existing = (0, import_fs24.readFileSync)(resolvedFilePath, "utf8").split("\n").filter(Boolean);
144975
+ const existing = (0, import_fs25.readFileSync)(resolvedFilePath, "utf8").split("\n").filter(Boolean);
144496
144976
  if (existing.length > 0) {
144497
144977
  this.wsHub.broadcast({ type: "conversation_events", sessionId, lines: existing });
144498
144978
  for (const line of existing) {
@@ -144518,7 +144998,7 @@ var StreamerServer = class {
144518
144998
  if (this.sessionFileMap.has(sessionId)) return;
144519
144999
  try {
144520
145000
  require("fs").mkdirSync(projectsDir, { recursive: true });
144521
- watcher = (0, import_fs24.watch)(projectsDir, tryWire);
145001
+ watcher = (0, import_fs25.watch)(projectsDir, tryWire);
144522
145002
  watcher.on("error", cleanup);
144523
145003
  } catch {
144524
145004
  }
@@ -144547,7 +145027,7 @@ var StreamerServer = class {
144547
145027
  };
144548
145028
  const matchesProjectPath = (candidatePath) => {
144549
145029
  try {
144550
- const firstLine = (0, import_fs24.readFileSync)(candidatePath, "utf8").split("\n", 1)[0];
145030
+ const firstLine = (0, import_fs25.readFileSync)(candidatePath, "utf8").split("\n", 1)[0];
144551
145031
  if (!firstLine) return null;
144552
145032
  const parsed = JSON.parse(firstLine);
144553
145033
  if (parsed?.type !== "session_meta") return null;
@@ -144576,15 +145056,15 @@ var StreamerServer = class {
144576
145056
  );
144577
145057
  for (const root of this.codexRoots) {
144578
145058
  const sessionsDir = (0, import_path22.join)(root, dateDir);
144579
- if (!(0, import_fs24.existsSync)(sessionsDir)) continue;
145059
+ if (!(0, import_fs25.existsSync)(sessionsDir)) continue;
144580
145060
  let candidateFiles;
144581
145061
  try {
144582
- candidateFiles = (0, import_fs24.readdirSync)(sessionsDir).filter((f2) => f2.endsWith(".jsonl"));
145062
+ candidateFiles = (0, import_fs25.readdirSync)(sessionsDir).filter((f2) => f2.endsWith(".jsonl"));
144583
145063
  } catch {
144584
145064
  continue;
144585
145065
  }
144586
145066
  const nowMs = Date.now();
144587
- const recentCandidates = candidateFiles.map((f2) => ({ f: f2, mtime: (0, import_fs24.statSync)((0, import_path22.join)(sessionsDir, f2)).mtimeMs })).filter(({ mtime }) => nowMs - mtime < 1e4).sort((a, b2) => b2.mtime - a.mtime);
145067
+ const recentCandidates = candidateFiles.map((f2) => ({ f: f2, mtime: (0, import_fs25.statSync)((0, import_path22.join)(sessionsDir, f2)).mtimeMs })).filter(({ mtime }) => nowMs - mtime < 1e4).sort((a, b2) => b2.mtime - a.mtime);
144588
145068
  for (const { f: f2 } of recentCandidates) {
144589
145069
  const candidatePath = (0, import_path22.join)(sessionsDir, f2);
144590
145070
  const match2 = matchesProjectPath(candidatePath);
@@ -144596,7 +145076,7 @@ var StreamerServer = class {
144596
145076
  this.sessionFileMap.set(sessionId, candidatePath);
144597
145077
  this.fileWatcher.watch(candidatePath);
144598
145078
  try {
144599
- const existing = (0, import_fs24.readFileSync)(candidatePath, "utf8").split("\n").filter(Boolean);
145079
+ const existing = (0, import_fs25.readFileSync)(candidatePath, "utf8").split("\n").filter(Boolean);
144600
145080
  if (existing.length > 0) {
144601
145081
  this.wsHub.broadcast({ type: "conversation_events", sessionId, lines: existing });
144602
145082
  for (const line of existing) {
@@ -144721,7 +145201,7 @@ var StreamerServer = class {
144721
145201
  };
144722
145202
  function classifyResumability(cwd) {
144723
145203
  if (!cwd) return { resumable: true };
144724
- if ((0, import_fs24.existsSync)(cwd)) return { resumable: true };
145204
+ if ((0, import_fs25.existsSync)(cwd)) return { resumable: true };
144725
145205
  const ranInWorktree = /\/\.worktrees\//.test(cwd) || /\/\.claude\/worktrees\//.test(cwd);
144726
145206
  return {
144727
145207
  resumable: false,
@@ -145040,7 +145520,7 @@ function isBrewInstall(scriptPath = process.argv[1] ?? "") {
145040
145520
  var import_node_crypto4 = require("crypto");
145041
145521
  var import_node_fs8 = require("fs");
145042
145522
  var import_node_path10 = require("path");
145043
- var import_promises18 = require("stream/promises");
145523
+ var import_promises20 = require("stream/promises");
145044
145524
 
145045
145525
  // src/updater/manifest.ts
145046
145526
  init_zod();
@@ -145115,7 +145595,7 @@ async function downloadAndVerify(opts) {
145115
145595
  }
145116
145596
  });
145117
145597
  try {
145118
- await (0, import_promises18.pipeline)(res.body.pipeThrough(measured), out);
145598
+ await (0, import_promises20.pipeline)(res.body.pipeThrough(measured), out);
145119
145599
  } catch (err) {
145120
145600
  (0, import_node_fs8.rmSync)(targetPath, { force: true });
145121
145601
  throw err;
@@ -145301,7 +145781,7 @@ var import_node_fs17 = require("fs");
145301
145781
 
145302
145782
  // node_modules/tar/dist/esm/index.min.js
145303
145783
  var import_events4 = __toESM(require("events"), 1);
145304
- var import_fs25 = __toESM(require("fs"), 1);
145784
+ var import_fs26 = __toESM(require("fs"), 1);
145305
145785
  var import_node_events3 = require("events");
145306
145786
  var import_node_stream3 = __toESM(require("stream"), 1);
145307
145787
  var import_node_string_decoder = require("string_decoder");
@@ -145315,8 +145795,8 @@ var Ps = __toESM(require("zlib"), 1);
145315
145795
  var import_zlib = __toESM(require("zlib"), 1);
145316
145796
  var import_node_path15 = require("path");
145317
145797
  var import_node_path16 = require("path");
145318
- var import_fs26 = __toESM(require("fs"), 1);
145319
145798
  var import_fs27 = __toESM(require("fs"), 1);
145799
+ var import_fs28 = __toESM(require("fs"), 1);
145320
145800
  var import_path24 = __toESM(require("path"), 1);
145321
145801
  var import_node_path17 = require("path");
145322
145802
  var import_path25 = __toESM(require("path"), 1);
@@ -145325,11 +145805,11 @@ var import_node_assert = __toESM(require("assert"), 1);
145325
145805
  var import_node_crypto5 = require("crypto");
145326
145806
  var import_node_fs13 = __toESM(require("fs"), 1);
145327
145807
  var import_node_path18 = __toESM(require("path"), 1);
145328
- var import_fs28 = __toESM(require("fs"), 1);
145808
+ var import_fs29 = __toESM(require("fs"), 1);
145329
145809
  var import_node_fs14 = __toESM(require("fs"), 1);
145330
145810
  var import_node_path19 = __toESM(require("path"), 1);
145331
145811
  var import_node_fs15 = __toESM(require("fs"), 1);
145332
- var import_promises19 = __toESM(require("fs/promises"), 1);
145812
+ var import_promises21 = __toESM(require("fs/promises"), 1);
145333
145813
  var import_node_path20 = __toESM(require("path"), 1);
145334
145814
  var import_node_path21 = require("path");
145335
145815
  var import_node_fs16 = __toESM(require("fs"), 1);
@@ -145677,7 +146157,7 @@ var A = class extends import_node_events3.EventEmitter {
145677
146157
  return Wr;
145678
146158
  }
145679
146159
  };
145680
- var Jr = import_fs25.default.writev;
146160
+ var Jr = import_fs26.default.writev;
145681
146161
  var ht = /* @__PURE__ */ Symbol("_autoClose");
145682
146162
  var H = /* @__PURE__ */ Symbol("_close");
145683
146163
  var te = /* @__PURE__ */ Symbol("_ended");
@@ -145732,7 +146212,7 @@ var _t = class extends A {
145732
146212
  throw new TypeError("this is a readable stream");
145733
146213
  }
145734
146214
  [at]() {
145735
- import_fs25.default.open(this[U2], "r", (t2, e) => this[Ht](t2, e));
146215
+ import_fs26.default.open(this[U2], "r", (t2, e) => this[Ht](t2, e));
145736
146216
  }
145737
146217
  [Ht](t2, e) {
145738
146218
  t2 ? this[Ut](t2) : (this[u2] = e, this.emit("open", e), this[zt]());
@@ -145745,7 +146225,7 @@ var _t = class extends A {
145745
146225
  this[j] = true;
145746
146226
  let t2 = this[vi]();
145747
146227
  if (t2.length === 0) return process.nextTick(() => this[Ii](null, 0, t2));
145748
- import_fs25.default.read(this[u2], t2, 0, t2.length, null, (e, i, r) => this[Ii](e, i, r));
146228
+ import_fs26.default.read(this[u2], t2, 0, t2.length, null, (e, i, r) => this[Ii](e, i, r));
145749
146229
  }
145750
146230
  }
145751
146231
  [Ii](t2, e, i) {
@@ -145754,7 +146234,7 @@ var _t = class extends A {
145754
146234
  [H]() {
145755
146235
  if (this[ht] && typeof this[u2] == "number") {
145756
146236
  let t2 = this[u2];
145757
- this[u2] = void 0, import_fs25.default.close(t2, (e) => e ? this.emit("error", e) : this.emit("close"));
146237
+ this[u2] = void 0, import_fs26.default.close(t2, (e) => e ? this.emit("error", e) : this.emit("close"));
145758
146238
  }
145759
146239
  }
145760
146240
  [Ut](t2) {
@@ -145782,7 +146262,7 @@ var Be = class extends _t {
145782
146262
  [at]() {
145783
146263
  let t2 = true;
145784
146264
  try {
145785
- this[Ht](null, import_fs25.default.openSync(this[U2], "r")), t2 = false;
146265
+ this[Ht](null, import_fs26.default.openSync(this[U2], "r")), t2 = false;
145786
146266
  } finally {
145787
146267
  t2 && this[H]();
145788
146268
  }
@@ -145793,7 +146273,7 @@ var Be = class extends _t {
145793
146273
  if (!this[j]) {
145794
146274
  this[j] = true;
145795
146275
  do {
145796
- let e = this[vi](), i = e.length === 0 ? 0 : import_fs25.default.readSync(this[u2], e, 0, e.length, null);
146276
+ let e = this[vi](), i = e.length === 0 ? 0 : import_fs26.default.readSync(this[u2], e, 0, e.length, null);
145797
146277
  if (!this[ki](i, e)) break;
145798
146278
  } while (true);
145799
146279
  this[j] = false;
@@ -145806,7 +146286,7 @@ var Be = class extends _t {
145806
146286
  [H]() {
145807
146287
  if (this[ht] && typeof this[u2] == "number") {
145808
146288
  let t2 = this[u2];
145809
- this[u2] = void 0, import_fs25.default.closeSync(t2), this.emit("close");
146289
+ this[u2] = void 0, import_fs26.default.closeSync(t2), this.emit("close");
145810
146290
  }
145811
146291
  }
145812
146292
  };
@@ -145848,7 +146328,7 @@ var et = class extends import_events4.default {
145848
146328
  this[H](), this[gt] = true, this.emit("error", t2);
145849
146329
  }
145850
146330
  [at]() {
145851
- import_fs25.default.open(this[U2], this[tt], this[ie], (t2, e) => this[Ht](t2, e));
146331
+ import_fs26.default.open(this[U2], this[tt], this[ie], (t2, e) => this[Ht](t2, e));
145852
146332
  }
145853
146333
  [Ht](t2, e) {
145854
146334
  this[Me] && this[tt] === "r+" && t2 && t2.code === "ENOENT" ? (this[tt] = "w", this[at]()) : t2 ? this[Ut](t2) : (this[u2] = e, this.emit("open", e), this[gt] || this[Ai]());
@@ -145860,7 +146340,7 @@ var et = class extends import_events4.default {
145860
146340
  return typeof t2 == "string" && (t2 = Buffer.from(t2, e)), this[te] ? (this.emit("error", new Error("write() after end()")), false) : this[u2] === void 0 || this[gt] || this[Y2].length ? (this[Y2].push(t2), this[ke] = true, false) : (this[gt] = true, this[ve](t2), true);
145861
146341
  }
145862
146342
  [ve](t2) {
145863
- import_fs25.default.write(this[u2], t2, 0, t2.length, this[ot], (e, i) => this[Pt](e, i));
146343
+ import_fs26.default.write(this[u2], t2, 0, t2.length, this[ot], (e, i) => this[Pt](e, i));
145864
146344
  }
145865
146345
  [Pt](t2, e) {
145866
146346
  t2 ? this[Ut](t2) : (this[ot] !== void 0 && typeof e == "number" && (this[ot] += e), this[Y2].length ? this[Ai]() : (this[gt] = false, this[te] && !this[Ni] ? (this[Ni] = true, this[H](), this.emit("finish")) : this[ke] && (this[ke] = false, this.emit("drain"))));
@@ -145876,7 +146356,7 @@ var et = class extends import_events4.default {
145876
146356
  [H]() {
145877
146357
  if (this[ht] && typeof this[u2] == "number") {
145878
146358
  let t2 = this[u2];
145879
- this[u2] = void 0, import_fs25.default.close(t2, (e) => e ? this.emit("error", e) : this.emit("close"));
146359
+ this[u2] = void 0, import_fs26.default.close(t2, (e) => e ? this.emit("error", e) : this.emit("close"));
145880
146360
  }
145881
146361
  }
145882
146362
  };
@@ -145884,24 +146364,24 @@ var Wt = class extends et {
145884
146364
  [at]() {
145885
146365
  let t2;
145886
146366
  if (this[Me] && this[tt] === "r+") try {
145887
- t2 = import_fs25.default.openSync(this[U2], this[tt], this[ie]);
146367
+ t2 = import_fs26.default.openSync(this[U2], this[tt], this[ie]);
145888
146368
  } catch (e) {
145889
146369
  if (e?.code === "ENOENT") return this[tt] = "w", this[at]();
145890
146370
  throw e;
145891
146371
  }
145892
- else t2 = import_fs25.default.openSync(this[U2], this[tt], this[ie]);
146372
+ else t2 = import_fs26.default.openSync(this[U2], this[tt], this[ie]);
145893
146373
  this[Ht](null, t2);
145894
146374
  }
145895
146375
  [H]() {
145896
146376
  if (this[ht] && typeof this[u2] == "number") {
145897
146377
  let t2 = this[u2];
145898
- this[u2] = void 0, import_fs25.default.closeSync(t2), this.emit("close");
146378
+ this[u2] = void 0, import_fs26.default.closeSync(t2), this.emit("close");
145899
146379
  }
145900
146380
  }
145901
146381
  [ve](t2) {
145902
146382
  let e = true;
145903
146383
  try {
145904
- this[Pt](null, import_fs25.default.writeSync(this[u2], t2, 0, t2.length, this[ot])), e = false;
146384
+ this[Pt](null, import_fs26.default.writeSync(this[u2], t2, 0, t2.length, this[ot])), e = false;
145905
146385
  } finally {
145906
146386
  if (e) try {
145907
146387
  this[H]();
@@ -146819,7 +147299,7 @@ var de = class extends A {
146819
147299
  return t2 === "error" && (this.#t = true), super.emit(t2, ...e);
146820
147300
  }
146821
147301
  [ss]() {
146822
- import_fs27.default.lstat(this.absolute, (t2, e) => {
147302
+ import_fs28.default.lstat(this.absolute, (t2, e) => {
146823
147303
  if (t2) return this.emit("error", t2);
146824
147304
  this[si](e);
146825
147305
  });
@@ -146857,7 +147337,7 @@ var de = class extends A {
146857
147337
  this.path.slice(-1) !== "/" && (this.path += "/"), this.stat.size = 0, this[fe](), this.end();
146858
147338
  }
146859
147339
  [is]() {
146860
- import_fs27.default.readlink(this.absolute, (t2, e) => {
147340
+ import_fs28.default.readlink(this.absolute, (t2, e) => {
146861
147341
  if (t2) return this.emit("error", t2);
146862
147342
  this[ns](e);
146863
147343
  });
@@ -146880,7 +147360,7 @@ var de = class extends A {
146880
147360
  this[os]();
146881
147361
  }
146882
147362
  [os]() {
146883
- import_fs27.default.open(this.absolute, "r", (t2, e) => {
147363
+ import_fs28.default.open(this.absolute, "r", (t2, e) => {
146884
147364
  if (t2) return this.emit("error", t2);
146885
147365
  this[hs](e);
146886
147366
  });
@@ -146895,14 +147375,14 @@ var de = class extends A {
146895
147375
  [ii]() {
146896
147376
  let { fd: t2, buf: e, offset: i, length: r, pos: n } = this;
146897
147377
  if (t2 === void 0 || e === void 0) throw new Error("cannot read file without first opening");
146898
- import_fs27.default.read(t2, e, i, r, n, (o, h) => {
147378
+ import_fs28.default.read(t2, e, i, r, n, (o, h) => {
146899
147379
  if (o) return this[pt](() => this.emit("error", o));
146900
147380
  this[rs](h);
146901
147381
  });
146902
147382
  }
146903
147383
  [pt](t2 = () => {
146904
147384
  }) {
146905
- this.fd !== void 0 && import_fs27.default.close(this.fd, t2);
147385
+ this.fd !== void 0 && import_fs28.default.close(this.fd, t2);
146906
147386
  }
146907
147387
  [rs](t2) {
146908
147388
  if (t2 <= 0 && this.remain > 0) {
@@ -146937,20 +147417,20 @@ var de = class extends A {
146937
147417
  var ni = class extends de {
146938
147418
  sync = true;
146939
147419
  [ss]() {
146940
- this[si](import_fs27.default.lstatSync(this.absolute));
147420
+ this[si](import_fs28.default.lstatSync(this.absolute));
146941
147421
  }
146942
147422
  [is]() {
146943
- this[ns](import_fs27.default.readlinkSync(this.absolute));
147423
+ this[ns](import_fs28.default.readlinkSync(this.absolute));
146944
147424
  }
146945
147425
  [os]() {
146946
- this[hs](import_fs27.default.openSync(this.absolute, "r"));
147426
+ this[hs](import_fs28.default.openSync(this.absolute, "r"));
146947
147427
  }
146948
147428
  [ii]() {
146949
147429
  let t2 = true;
146950
147430
  try {
146951
147431
  let { fd: e, buf: i, offset: r, length: n, pos: o } = this;
146952
147432
  if (e === void 0 || i === void 0) throw new Error("fd and buf must be set in READ method");
146953
- let h = import_fs27.default.readSync(e, i, r, n, o);
147433
+ let h = import_fs28.default.readSync(e, i, r, n, o);
146954
147434
  this[rs](h), t2 = false;
146955
147435
  } finally {
146956
147436
  if (t2) try {
@@ -146965,7 +147445,7 @@ var ni = class extends de {
146965
147445
  }
146966
147446
  [pt](t2 = () => {
146967
147447
  }) {
146968
- this.fd !== void 0 && import_fs27.default.closeSync(this.fd), t2();
147448
+ this.fd !== void 0 && import_fs28.default.closeSync(this.fd), t2();
146969
147449
  }
146970
147450
  };
146971
147451
  var oi = class extends A {
@@ -147296,7 +147776,7 @@ var wt = class extends A {
147296
147776
  [ds](t2) {
147297
147777
  t2.pending = true, this[G2] += 1;
147298
147778
  let e = this.follow ? "stat" : "lstat";
147299
- import_fs26.default[e](t2.absolute, (i, r) => {
147779
+ import_fs27.default[e](t2.absolute, (i, r) => {
147300
147780
  t2.pending = false, this[G2] -= 1, i ? this.emit("error", i) : this[li](t2, r);
147301
147781
  });
147302
147782
  }
@@ -147310,7 +147790,7 @@ var wt = class extends A {
147310
147790
  this[Ft]();
147311
147791
  }
147312
147792
  [ms](t2) {
147313
- t2.pending = true, this[G2] += 1, import_fs26.default.readdir(t2.absolute, (e, i) => {
147793
+ t2.pending = true, this[G2] += 1, import_fs27.default.readdir(t2.absolute, (e, i) => {
147314
147794
  if (t2.pending = false, this[G2] -= 1, e) return this.emit("error", e);
147315
147795
  this[fi](t2, i);
147316
147796
  });
@@ -147411,10 +147891,10 @@ var kt = class extends wt {
147411
147891
  }
147412
147892
  [ds](t2) {
147413
147893
  let e = this.follow ? "statSync" : "lstatSync";
147414
- this[li](t2, import_fs26.default[e](t2.absolute));
147894
+ this[li](t2, import_fs27.default[e](t2.absolute));
147415
147895
  }
147416
147896
  [ms](t2) {
147417
- this[fi](t2, import_fs26.default.readdirSync(t2.absolute));
147897
+ this[fi](t2, import_fs27.default.readdirSync(t2.absolute));
147418
147898
  }
147419
147899
  [di](t2) {
147420
147900
  let e = t2.entry, i = this.zip;
@@ -147465,8 +147945,8 @@ var Qn = K2(Vn, $n, Xn, qn, (s3, t2) => {
147465
147945
  });
147466
147946
  var Jn = process.env.__FAKE_PLATFORM__ || process.platform;
147467
147947
  var Er = Jn === "win32";
147468
- var { O_CREAT: wr, O_NOFOLLOW: mr, O_TRUNC: Sr, O_WRONLY: yr } = import_fs28.default.constants;
147469
- var Rr = Number(process.env.__FAKE_FS_O_FILENAME__) || import_fs28.default.constants.UV_FS_O_FILEMAP || 0;
147948
+ var { O_CREAT: wr, O_NOFOLLOW: mr, O_TRUNC: Sr, O_WRONLY: yr } = import_fs29.default.constants;
147949
+ var Rr = Number(process.env.__FAKE_FS_O_FILENAME__) || import_fs29.default.constants.UV_FS_O_FILEMAP || 0;
147470
147950
  var jn = Er && !!Rr;
147471
147951
  var to = 512 * 1024;
147472
147952
  var eo = Rr | Sr | wr | yr;
@@ -147561,7 +148041,7 @@ var gr = (s3, t2, e) => {
147561
148041
  E2 ? e(E2) : x2 && a ? Es(x2, o, h, (Le) => S2(Le)) : n ? import_node_fs15.default.chmod(s3, r, e) : e();
147562
148042
  };
147563
148043
  if (s3 === d) return no(s3, S2);
147564
- if (l) return import_promises19.default.mkdir(s3, { mode: r, recursive: true }).then((E2) => S2(null, E2 ?? void 0), S2);
148044
+ if (l) return import_promises21.default.mkdir(s3, { mode: r, recursive: true }).then((E2) => S2(null, E2 ?? void 0), S2);
147565
148045
  let D2 = f(import_node_path20.default.relative(d, s3)).split("/");
147566
148046
  Ss(d, D2, r, c, d, void 0, S2);
147567
148047
  };