@threadbase-sh/streamer 1.27.1 → 1.27.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.cjs CHANGED
@@ -99922,8 +99922,8 @@ var require_pattern = __commonJS({
99922
99922
  }
99923
99923
  exports2.endsWithSlashGlobStar = endsWithSlashGlobStar;
99924
99924
  function isAffectDepthOfReadingPattern(pattern) {
99925
- const basename11 = path2.basename(pattern);
99926
- return endsWithSlashGlobStar(pattern) || isStaticPattern(basename11);
99925
+ const basename12 = path2.basename(pattern);
99926
+ return endsWithSlashGlobStar(pattern) || isStaticPattern(basename12);
99927
99927
  }
99928
99928
  exports2.isAffectDepthOfReadingPattern = isAffectDepthOfReadingPattern;
99929
99929
  function expandPatternsWithBraceExpansion(patterns2) {
@@ -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_promises18, interactivePrompt, interactivePermissionModePrompt;
123753
+ var import_node_process2, import_promises20, 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_promises18 = require("readline/promises");
123758
+ import_promises20 = require("readline/promises");
123759
123759
  interactivePrompt = async ({ prodPort, suggestedAltPort, prodActive }) => {
123760
- const rl = (0, import_promises18.createInterface)({ input: import_node_process2.stdin, output: import_node_process2.stdout });
123760
+ const rl = (0, import_promises20.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_promises18.createInterface)({ input: import_node_process2.stdin, output: import_node_process2.stdout });
123795
+ const rl = (0, import_promises20.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"
@@ -128528,35 +128528,39 @@ var flexsearch_bundle_module_min_default = { Index: N, Document: U, Worker: S, r
128528
128528
 
128529
128529
  // node_modules/@threadbase-sh/scanner/dist/index.js
128530
128530
  var import_fs5 = require("fs");
128531
- var import_promises4 = require("fs/promises");
128532
- var import_os4 = require("os");
128533
128531
  var import_path3 = require("path");
128534
- var import_fast_glob = __toESM(require_out4(), 1);
128535
- var import_fs6 = require("fs");
128536
- var import_promises5 = require("fs/promises");
128537
- var import_path4 = require("path");
128538
128532
  var import_readline = require("readline");
128539
- var import_fast_glob2 = __toESM(require_out4(), 1);
128540
- var import_promises6 = require("fs/promises");
128533
+ var import_path4 = require("path");
128534
+ var import_fs6 = require("fs");
128535
+ var import_promises4 = require("fs/promises");
128536
+ var import_os4 = require("os");
128541
128537
  var import_path5 = require("path");
128538
+ var import_fast_glob = __toESM(require_out4(), 1);
128542
128539
  var import_fs7 = require("fs");
128540
+ var import_promises5 = require("fs/promises");
128543
128541
  var import_path6 = require("path");
128544
128542
  var import_readline2 = require("readline");
128543
+ var import_fast_glob2 = __toESM(require_out4(), 1);
128544
+ var import_promises6 = require("fs/promises");
128545
128545
  var import_events2 = require("events");
128546
128546
  var import_fs8 = require("fs");
128547
128547
  var import_os5 = require("os");
128548
128548
  var import_path7 = require("path");
128549
- var import_crypto2 = require("crypto");
128549
+ var import_path8 = require("path");
128550
128550
  var import_fs9 = require("fs");
128551
+ var import_promises7 = require("timers/promises");
128551
128552
  var import_fs10 = require("fs");
128552
- var import_readline3 = require("readline");
128553
- var import_better_sqlite3 = __toESM(require("better-sqlite3"), 1);
128553
+ var import_promises8 = require("timers/promises");
128554
+ var import_crypto2 = require("crypto");
128554
128555
  var import_fs11 = require("fs");
128555
- var import_path8 = require("path");
128556
- var import_promises7 = require("fs/promises");
128557
128556
  var import_fs12 = require("fs");
128558
128557
  var import_fs13 = require("fs");
128558
+ var import_readline3 = require("readline");
128559
+ var import_better_sqlite3 = __toESM(require("better-sqlite3"), 1);
128560
+ var import_fs14 = require("fs");
128559
128561
  var import_path9 = require("path");
128562
+ var import_promises9 = require("fs/promises");
128563
+ var import_path10 = require("path");
128560
128564
 
128561
128565
  // node_modules/@threadbase-sh/scanner/node_modules/chokidar/esm/index.js
128562
128566
  var import_fs3 = require("fs");
@@ -128711,10 +128715,10 @@ var ReaddirpStream = class extends import_node_stream.Readable {
128711
128715
  }
128712
128716
  async _formatEntry(dirent, path2) {
128713
128717
  let entry;
128714
- const basename11 = this._isDirent ? dirent.name : dirent;
128718
+ const basename12 = this._isDirent ? dirent.name : dirent;
128715
128719
  try {
128716
- const fullPath = (0, import_node_path5.resolve)((0, import_node_path5.join)(path2, basename11));
128717
- entry = { path: (0, import_node_path5.relative)(this._root, fullPath), fullPath, basename: basename11 };
128720
+ const fullPath = (0, import_node_path5.resolve)((0, import_node_path5.join)(path2, basename12));
128721
+ entry = { path: (0, import_node_path5.relative)(this._root, fullPath), fullPath, basename: basename12 };
128718
128722
  entry[this._statsProp] = this._isDirent ? dirent : await this._stat(fullPath);
128719
128723
  } catch (err) {
128720
128724
  this._onError(err);
@@ -129253,9 +129257,9 @@ var NodeFsHandler = class {
129253
129257
  _watchWithNodeFs(path2, listener) {
129254
129258
  const opts = this.fsw.options;
129255
129259
  const directory = sysPath.dirname(path2);
129256
- const basename11 = sysPath.basename(path2);
129260
+ const basename12 = sysPath.basename(path2);
129257
129261
  const parent = this.fsw._getWatchedDir(directory);
129258
- parent.add(basename11);
129262
+ parent.add(basename12);
129259
129263
  const absolutePath = sysPath.resolve(path2);
129260
129264
  const options = {
129261
129265
  persistent: opts.persistent
@@ -129265,7 +129269,7 @@ var NodeFsHandler = class {
129265
129269
  let closer;
129266
129270
  if (opts.usePolling) {
129267
129271
  const enableBin = opts.interval !== opts.binaryInterval;
129268
- options.interval = enableBin && isBinaryPath(basename11) ? opts.binaryInterval : opts.interval;
129272
+ options.interval = enableBin && isBinaryPath(basename12) ? opts.binaryInterval : opts.interval;
129269
129273
  closer = setFsWatchFileListener(path2, absolutePath, options, {
129270
129274
  listener,
129271
129275
  rawEmitter: this.fsw._emitRaw
@@ -129288,10 +129292,10 @@ var NodeFsHandler = class {
129288
129292
  return;
129289
129293
  }
129290
129294
  const dirname17 = sysPath.dirname(file2);
129291
- const basename11 = sysPath.basename(file2);
129295
+ const basename12 = sysPath.basename(file2);
129292
129296
  const parent = this.fsw._getWatchedDir(dirname17);
129293
129297
  let prevStats = stats;
129294
- if (parent.has(basename11))
129298
+ if (parent.has(basename12))
129295
129299
  return;
129296
129300
  const listener = async (path2, newStats) => {
129297
129301
  if (!this.fsw._throttle(THROTTLE_MODE_WATCH, file2, 5))
@@ -129316,9 +129320,9 @@ var NodeFsHandler = class {
129316
129320
  prevStats = newStats2;
129317
129321
  }
129318
129322
  } catch (error51) {
129319
- this.fsw._remove(dirname17, basename11);
129323
+ this.fsw._remove(dirname17, basename12);
129320
129324
  }
129321
- } else if (parent.has(basename11)) {
129325
+ } else if (parent.has(basename12)) {
129322
129326
  const at2 = newStats.atimeMs;
129323
129327
  const mt2 = newStats.mtimeMs;
129324
129328
  if (!at2 || at2 <= mt2 || mt2 !== prevStats.mtimeMs) {
@@ -130514,6 +130518,435 @@ var SearchIndexer = class {
130514
130518
  getLogger2().trace("indexer: cleared");
130515
130519
  }
130516
130520
  };
130521
+ var CLAUDE_CODE_PROVIDER = "claude-code";
130522
+ var CODEX_CLI_PROVIDER = "codex-cli";
130523
+ function initialReducerState() {
130524
+ return {
130525
+ sessionId: "",
130526
+ sessionName: "",
130527
+ latestTimestamp: "",
130528
+ cwd: "",
130529
+ teamName: "",
130530
+ model: null,
130531
+ messageCount: 0,
130532
+ lastMessageSender: "user",
130533
+ isTeammate: false,
130534
+ firstUserSeen: false,
130535
+ firstMessage: null,
130536
+ lastMessage: null,
130537
+ lastPrompt: "",
130538
+ pageMessageCount: 0,
130539
+ toolNames: [],
130540
+ previewParts: [],
130541
+ snippetParts: [],
130542
+ previewLength: 0,
130543
+ snippetLength: 0,
130544
+ badJsonLines: 0
130545
+ };
130546
+ }
130547
+ function reduceLine(state, entry, tier) {
130548
+ if (entry.cwd && !state.cwd) state.cwd = entry.cwd;
130549
+ if (entry.sessionId && !state.sessionId) state.sessionId = entry.sessionId;
130550
+ if (entry.slug && !state.sessionName) state.sessionName = entry.slug;
130551
+ if (entry.teamName && !state.teamName) state.teamName = entry.teamName;
130552
+ if (entry.timestamp) {
130553
+ const ts2 = entry.timestamp;
130554
+ if (!state.latestTimestamp || ts2 > state.latestTimestamp) state.latestTimestamp = ts2;
130555
+ }
130556
+ const type = entry.type;
130557
+ if (type === "last-prompt") {
130558
+ if (entry.lastPrompt && !state.lastPrompt) state.lastPrompt = entry.lastPrompt;
130559
+ return;
130560
+ }
130561
+ if (type !== "user" && type !== "assistant") return;
130562
+ if (entry.isMeta) return;
130563
+ const msg = entry.message;
130564
+ if (state.model === null && msg?.model) state.model = msg.model;
130565
+ if (type === "user" && !state.firstUserSeen) {
130566
+ state.firstUserSeen = true;
130567
+ if (isTeammateContent(msg?.content)) state.isTeammate = true;
130568
+ }
130569
+ const content = extractTextContent(msg?.content);
130570
+ const hasToolUseResult = type === "user" && entry.toolUseResult != null;
130571
+ const isOnlyToolResult = hasToolUseResult && isOnlyToolResultContent(msg?.content);
130572
+ const toolSet = new Set(state.toolNames);
130573
+ collectToolNames(msg?.content, toolSet);
130574
+ state.toolNames = Array.from(toolSet);
130575
+ const toolUseBlocks = extractToolUseBlocks(msg?.content);
130576
+ const thinking = type === "assistant" ? extractThinking(msg?.content) : null;
130577
+ const hasThinking = !!(thinking?.content || thinking?.signature);
130578
+ if (content || isOnlyToolResult || toolUseBlocks.length > 0 || hasThinking) {
130579
+ state.pageMessageCount++;
130580
+ }
130581
+ if (content || isOnlyToolResult) {
130582
+ state.messageCount++;
130583
+ state.lastMessageSender = type;
130584
+ if (content) {
130585
+ const ts2 = entry.timestamp || "";
130586
+ if (!state.firstMessage) state.firstMessage = { text: content.slice(0, 200), timestamp: ts2 };
130587
+ state.lastMessage = { text: content.slice(0, 200), timestamp: ts2 };
130588
+ if (state.previewLength < tier.previewMax) {
130589
+ state.previewParts.push(content);
130590
+ state.previewLength += content.length;
130591
+ }
130592
+ if (state.snippetLength < tier.snippetMax) {
130593
+ const remaining = tier.snippetMax - state.snippetLength;
130594
+ const chunk = content.length > remaining ? content.slice(0, remaining) : content;
130595
+ state.snippetParts.push(chunk);
130596
+ state.snippetLength += chunk.length;
130597
+ }
130598
+ }
130599
+ }
130600
+ }
130601
+ function finalizeMeta(state, filePath, account, tier) {
130602
+ if (state.messageCount === 0) return null;
130603
+ const isSubagent = filePath.includes("/subagents/");
130604
+ let parentSessionId = null;
130605
+ if (isSubagent) {
130606
+ const uuidDir = (0, import_path4.dirname)((0, import_path4.dirname)(filePath));
130607
+ parentSessionId = (0, import_path4.join)((0, import_path4.dirname)(uuidDir), `${(0, import_path4.basename)(uuidDir)}.jsonl`);
130608
+ }
130609
+ const projectPath = state.cwd;
130610
+ return {
130611
+ id: filePath,
130612
+ filePath,
130613
+ provider: CLAUDE_CODE_PROVIDER,
130614
+ sessionId: state.sessionId || (0, import_path4.basename)(filePath, ".jsonl"),
130615
+ sessionName: state.sessionName,
130616
+ projectPath,
130617
+ projectName: getShortProjectName(projectPath),
130618
+ account,
130619
+ timestamp: state.latestTimestamp || (/* @__PURE__ */ new Date()).toISOString(),
130620
+ messageCount: state.messageCount,
130621
+ lastMessageSender: state.lastMessageSender,
130622
+ preview: state.previewParts.join(" ").slice(0, tier.previewMax),
130623
+ contentSnippet: state.snippetParts.join(" "),
130624
+ gitBranch: null,
130625
+ model: state.model,
130626
+ isSubagent,
130627
+ parentSessionId,
130628
+ isTeammate: state.isTeammate,
130629
+ teamName: state.teamName || null,
130630
+ toolNames: state.toolNames,
130631
+ firstMessage: state.firstMessage,
130632
+ lastMessage: state.lastMessage,
130633
+ lastPrompt: state.lastPrompt || void 0
130634
+ };
130635
+ }
130636
+ function getShortProjectName(fullPath) {
130637
+ const parts = fullPath.split("/").filter(Boolean);
130638
+ return parts.slice(-3).join("/");
130639
+ }
130640
+ var SYSTEM_TAGS = [
130641
+ "system-reminder",
130642
+ "command-name",
130643
+ "command-message",
130644
+ "command-args",
130645
+ "ide_selection",
130646
+ "ide_opened_file",
130647
+ "local-command-stdout",
130648
+ "local-command-caveat",
130649
+ "retrieval_status",
130650
+ "task_id",
130651
+ "task_type",
130652
+ "task-id",
130653
+ "task-notification",
130654
+ "fast_mode_info",
130655
+ "persisted-output",
130656
+ "tool_use_error",
130657
+ "user-prompt-submit-hook",
130658
+ "thinking",
130659
+ "ask_user",
130660
+ "teammate-message"
130661
+ ];
130662
+ var SYSTEM_TAG_RE = new RegExp(`<(${SYSTEM_TAGS.join("|")})[^>]*>[\\s\\S]*?<\\/\\1>`, "g");
130663
+ function cleanSystemTags(text) {
130664
+ return text.replace(SYSTEM_TAG_RE, "").replace(/[^\S\n]+/g, " ").replace(/\n{3,}/g, "\n\n").trim();
130665
+ }
130666
+ async function parseMeta(filePath, account, tier) {
130667
+ const log8 = getLogger2();
130668
+ log8.trace({ filePath, account, tier: tier.name }, "parseMeta: start");
130669
+ const state = initialReducerState();
130670
+ const fileStream = (0, import_fs5.createReadStream)(filePath);
130671
+ const rl = (0, import_readline.createInterface)({ input: fileStream, crlfDelay: Infinity });
130672
+ try {
130673
+ for await (const line of rl) {
130674
+ if (!line.trim()) continue;
130675
+ let entry;
130676
+ try {
130677
+ entry = JSON.parse(line);
130678
+ } catch {
130679
+ state.badJsonLines++;
130680
+ continue;
130681
+ }
130682
+ reduceLine(state, entry, tier);
130683
+ }
130684
+ } catch (err) {
130685
+ log8.warn({ filePath, err }, "parseMeta: read failed");
130686
+ return null;
130687
+ }
130688
+ if (state.badJsonLines > 0) {
130689
+ log8.warn(
130690
+ { filePath, badJsonLines: state.badJsonLines },
130691
+ "parseMeta: skipped malformed JSON lines"
130692
+ );
130693
+ }
130694
+ const meta3 = finalizeMeta(state, filePath, account, tier);
130695
+ if (!meta3) log8.trace({ filePath }, "parseMeta: no messages");
130696
+ return meta3;
130697
+ }
130698
+ async function parseConversation(filePath, account) {
130699
+ const log8 = getLogger2();
130700
+ log8.trace({ filePath, account }, "parseConversation: start");
130701
+ const messages = [];
130702
+ let badJsonLines = 0;
130703
+ const textParts = [];
130704
+ const turnDurations = [];
130705
+ const state = initialConvState();
130706
+ const fileStream = (0, import_fs5.createReadStream)(filePath);
130707
+ const rl = (0, import_readline.createInterface)({ input: fileStream, crlfDelay: Infinity });
130708
+ try {
130709
+ for await (const line of rl) {
130710
+ if (!line.trim()) continue;
130711
+ let entry;
130712
+ try {
130713
+ entry = JSON.parse(line);
130714
+ } catch {
130715
+ badJsonLines++;
130716
+ continue;
130717
+ }
130718
+ if (entry.type === "system" && entry.subtype === "turn_duration" && typeof entry.durationMs === "number") {
130719
+ turnDurations.push({
130720
+ durationMs: entry.durationMs,
130721
+ messageCount: entry.messageCount || 0,
130722
+ uuid: entry.uuid
130723
+ });
130724
+ continue;
130725
+ }
130726
+ const message = reduceConvLine(state, entry);
130727
+ if (message) {
130728
+ messages.push(message);
130729
+ if (message.text) textParts.push(message.text);
130730
+ }
130731
+ }
130732
+ } catch (err) {
130733
+ log8.warn({ filePath, err }, "parseConversation: read failed");
130734
+ return null;
130735
+ }
130736
+ if (badJsonLines > 0) {
130737
+ log8.warn({ filePath, badJsonLines }, "parseConversation: skipped malformed JSON lines");
130738
+ }
130739
+ if (messages.length === 0) {
130740
+ log8.trace({ filePath }, "parseConversation: no messages");
130741
+ return null;
130742
+ }
130743
+ log8.debug({ filePath, messageCount: messages.length }, "parseConversation: complete");
130744
+ applyTeamInfo(messages, state);
130745
+ return {
130746
+ id: filePath,
130747
+ filePath,
130748
+ projectPath: state.cwd,
130749
+ projectName: getShortProjectName2(state.cwd),
130750
+ sessionId: state.sessionId || (0, import_path3.basename)(filePath, ".jsonl"),
130751
+ sessionName: state.sessionName,
130752
+ messages,
130753
+ fullText: textParts.join(" "),
130754
+ timestamp: state.latestTimestamp || (/* @__PURE__ */ new Date()).toISOString(),
130755
+ messageCount: messages.length,
130756
+ account,
130757
+ turnDurations: turnDurations.length > 0 ? turnDurations : void 0,
130758
+ lastPrompt: state.lastPrompt || void 0
130759
+ };
130760
+ }
130761
+ function extractTextContent(content) {
130762
+ if (!content) return "";
130763
+ if (typeof content === "string") return cleanSystemTags(content);
130764
+ if (Array.isArray(content)) {
130765
+ return content.map((item) => {
130766
+ if (typeof item === "string") return item;
130767
+ if (item?.type === "text" && item?.text) return item.text;
130768
+ if (item?.type === "tool_result" && typeof item?.content === "string") return item.content;
130769
+ return "";
130770
+ }).filter(Boolean).map(cleanSystemTags).join(" ");
130771
+ }
130772
+ return "";
130773
+ }
130774
+ function extractToolUseNames(content) {
130775
+ if (!Array.isArray(content)) return [];
130776
+ return content.filter((item) => item?.type === "tool_use" && item?.name).map((item) => item.name);
130777
+ }
130778
+ function extractToolUseBlocks(content) {
130779
+ if (!Array.isArray(content)) return [];
130780
+ return content.filter((item) => item?.type === "tool_use" && item?.name && item?.id).map((item) => ({
130781
+ id: item.id,
130782
+ name: item.name,
130783
+ input: item.input || {}
130784
+ }));
130785
+ }
130786
+ var TOOL_NAME_TO_TYPE = {
130787
+ Edit: "edit",
130788
+ Write: "write",
130789
+ Read: "read",
130790
+ Bash: "bash",
130791
+ Grep: "grep",
130792
+ Glob: "glob",
130793
+ Agent: "taskAgent",
130794
+ TaskCreate: "taskCreate",
130795
+ TaskUpdate: "taskUpdate"
130796
+ };
130797
+ function extractToolResultBlocks(content, pendingToolUses) {
130798
+ if (!Array.isArray(content)) return [];
130799
+ return content.filter((item) => item?.type === "tool_result" && item?.tool_use_id).map((item) => {
130800
+ const toolName = pendingToolUses.get(item.tool_use_id)?.name ?? "";
130801
+ return {
130802
+ toolUseId: item.tool_use_id,
130803
+ type: TOOL_NAME_TO_TYPE[toolName] ?? "generic",
130804
+ content: typeof item.content === "string" ? { text: item.content } : item.content ?? {},
130805
+ isError: typeof item.is_error === "boolean" ? item.is_error : void 0
130806
+ };
130807
+ });
130808
+ }
130809
+ function collectToolNames(content, toolSet) {
130810
+ if (!Array.isArray(content)) return;
130811
+ for (const item of content) {
130812
+ if (item?.type === "tool_use" && item?.name) {
130813
+ toolSet.add(item.name);
130814
+ }
130815
+ }
130816
+ }
130817
+ function isOnlyToolResultContent(content) {
130818
+ if (!Array.isArray(content)) return false;
130819
+ return content.length > 0 && content.every((item) => item?.type === "tool_result");
130820
+ }
130821
+ function isTeammateContent(content) {
130822
+ const raw2 = typeof content === "string" ? content : Array.isArray(content) ? content.map(
130823
+ (item) => typeof item === "string" ? item : item?.type === "text" ? item.text ?? "" : ""
130824
+ ).join("") : "";
130825
+ return raw2.includes("<teammate-message");
130826
+ }
130827
+ function extractThinking(content) {
130828
+ if (!Array.isArray(content)) return { content: "", signature: "" };
130829
+ const blocks = content.filter((item) => item?.type === "thinking");
130830
+ return {
130831
+ content: blocks.map((b2) => b2.thinking).filter(Boolean).join("\n\n"),
130832
+ signature: blocks.map((b2) => b2.signature).filter(Boolean).join("")
130833
+ };
130834
+ }
130835
+ function hasImageBlocks(content) {
130836
+ if (!Array.isArray(content)) return false;
130837
+ return content.some(
130838
+ (item) => item?.type === "image" && (item?.source?.type === "base64" || item?.file?.base64 !== void 0)
130839
+ );
130840
+ }
130841
+ function parseTeammateMessageTag(content) {
130842
+ const match2 = content.match(/<teammate-message\s+([^>]*)>/);
130843
+ if (!match2) return null;
130844
+ const attrs = match2[1];
130845
+ const id = attrs.match(/teammate_id="([^"]*)"/)?.[1];
130846
+ if (!id) return null;
130847
+ const summary = attrs.match(/summary="([^"]*)"/)?.[1];
130848
+ const color = attrs.match(/color="([^"]*)"/)?.[1];
130849
+ return { teammateId: id, summary, color };
130850
+ }
130851
+ function getShortProjectName2(fullPath) {
130852
+ const parts = fullPath.split("/").filter(Boolean);
130853
+ return parts.slice(-3).join("/");
130854
+ }
130855
+ function initialConvState() {
130856
+ return {
130857
+ cwd: "",
130858
+ sessionId: "",
130859
+ sessionName: "",
130860
+ latestTimestamp: "",
130861
+ lastPrompt: "",
130862
+ pendingToolUses: {},
130863
+ teamInfo: {}
130864
+ };
130865
+ }
130866
+ function reduceConvLine(state, entry) {
130867
+ if (entry.cwd && !state.cwd) state.cwd = entry.cwd;
130868
+ if (entry.sessionId && !state.sessionId) state.sessionId = entry.sessionId;
130869
+ if (entry.slug && !state.sessionName) state.sessionName = entry.slug;
130870
+ if (entry.timestamp) {
130871
+ const ts2 = entry.timestamp;
130872
+ if (!state.latestTimestamp || ts2 > state.latestTimestamp) state.latestTimestamp = ts2;
130873
+ }
130874
+ const type = entry.type;
130875
+ if (type === "last-prompt") {
130876
+ if (entry.lastPrompt && !state.lastPrompt) state.lastPrompt = entry.lastPrompt;
130877
+ return null;
130878
+ }
130879
+ if (type !== "user" && type !== "assistant") return null;
130880
+ if (entry.isMeta) return null;
130881
+ const msg = entry.message;
130882
+ const toolUseBlocks = extractToolUseBlocks(msg?.content);
130883
+ for (const block of toolUseBlocks) state.pendingToolUses[block.id] = block;
130884
+ const hasToolUseResult = type === "user" && entry.toolUseResult != null;
130885
+ const isToolResultOnly = hasToolUseResult && isOnlyToolResultContent(msg?.content);
130886
+ const content = extractTextContent(msg?.content);
130887
+ const thinking = type === "assistant" ? extractThinking(msg?.content) : null;
130888
+ const hasThinking = !!(thinking?.content || thinking?.signature);
130889
+ if (!(content || isToolResultOnly || toolUseBlocks.length > 0 || hasThinking)) return null;
130890
+ const metadata = {};
130891
+ if (msg?.model) metadata.model = msg.model;
130892
+ if (msg?.stop_reason !== void 0) metadata.stopReason = msg.stop_reason;
130893
+ if (entry.gitBranch) metadata.gitBranch = entry.gitBranch;
130894
+ if (entry.version) metadata.version = entry.version;
130895
+ const usage = msg?.usage;
130896
+ if (usage) {
130897
+ if (usage.input_tokens) metadata.inputTokens = usage.input_tokens;
130898
+ if (usage.output_tokens) metadata.outputTokens = usage.output_tokens;
130899
+ if (usage.cache_read_input_tokens) metadata.cacheReadTokens = usage.cache_read_input_tokens;
130900
+ if (usage.cache_creation_input_tokens)
130901
+ metadata.cacheCreationTokens = usage.cache_creation_input_tokens;
130902
+ }
130903
+ const toolUseNames = extractToolUseNames(msg?.content);
130904
+ if (toolUseNames.length > 0) metadata.toolUses = toolUseNames;
130905
+ if (toolUseBlocks.length > 0) metadata.toolUseBlocks = toolUseBlocks;
130906
+ if (isToolResultOnly) {
130907
+ const pending = new Map(Object.entries(state.pendingToolUses));
130908
+ const toolResultBlocks = extractToolResultBlocks(msg?.content, pending);
130909
+ if (toolResultBlocks.length > 0) {
130910
+ metadata.toolResults = toolResultBlocks;
130911
+ for (const block of toolResultBlocks) delete state.pendingToolUses[block.toolUseId];
130912
+ }
130913
+ }
130914
+ if (entry.teamName) {
130915
+ metadata.teamName = entry.teamName;
130916
+ if (!state.teamInfo[metadata.teamName] && content) {
130917
+ const info = parseTeammateMessageTag(content);
130918
+ if (info) state.teamInfo[metadata.teamName] = info;
130919
+ }
130920
+ }
130921
+ const thinkingContent = thinking?.content || void 0;
130922
+ const thinkingSignature = thinking?.signature || void 0;
130923
+ const hasMetadata = Object.keys(metadata).length > 0;
130924
+ return {
130925
+ role: type,
130926
+ text: content || "",
130927
+ timestamp: entry.timestamp || "",
130928
+ uuid: entry.uuid || void 0,
130929
+ metadata: hasMetadata ? metadata : void 0,
130930
+ isToolResult: isToolResultOnly || void 0,
130931
+ isThinking: thinkingContent || thinkingSignature ? true : void 0,
130932
+ thinkingContent,
130933
+ thinkingSignature,
130934
+ parentUuid: entry.parentUuid !== void 0 ? entry.parentUuid : void 0,
130935
+ requestId: type === "assistant" ? entry.requestId : void 0,
130936
+ promptId: type === "user" ? entry.promptId : void 0,
130937
+ isSidechain: typeof entry.isSidechain === "boolean" ? entry.isSidechain : void 0,
130938
+ permissionMode: type === "user" ? entry.permissionMode : void 0,
130939
+ hasImages: hasImageBlocks(msg?.content) || void 0,
130940
+ attachment: entry.attachment !== void 0 ? entry.attachment : void 0
130941
+ };
130942
+ }
130943
+ function applyTeamInfo(messages, state) {
130944
+ if (Object.keys(state.teamInfo).length === 0) return;
130945
+ for (const m2 of messages) {
130946
+ const name = m2.metadata?.teamName;
130947
+ if (name && state.teamInfo[name] && m2.metadata) m2.metadata.teamInfo = state.teamInfo[name];
130948
+ }
130949
+ }
130517
130950
  var SIDECAR_VERSION = 1;
130518
130951
  function sidecarPath(jsonlPath) {
130519
130952
  return `${jsonlPath}.idx.json`;
@@ -130539,7 +130972,7 @@ function buildSidecar(meta3, cursor, updatedAt) {
130539
130972
  }
130540
130973
  function writeSidecar(jsonlPath, sidecar) {
130541
130974
  try {
130542
- (0, import_fs5.writeFileSync)(sidecarPath(jsonlPath), JSON.stringify(sidecar, null, 2));
130975
+ (0, import_fs6.writeFileSync)(sidecarPath(jsonlPath), JSON.stringify(sidecar, null, 2));
130543
130976
  } catch (err) {
130544
130977
  getLogger2().warn({ jsonlPath, err }, "sidecar: write failed");
130545
130978
  }
@@ -130549,13 +130982,13 @@ function resolveConfigDir(configDir2) {
130549
130982
  return configDir2.replace(/^~/, (0, import_os4.homedir)());
130550
130983
  }
130551
130984
  function getProjectsDir(profile) {
130552
- return (0, import_path3.join)(resolveConfigDir(profile.configDir), "projects");
130985
+ return (0, import_path5.join)(resolveConfigDir(profile.configDir), "projects");
130553
130986
  }
130554
130987
  async function detectDefaultProfile() {
130555
130988
  return {
130556
130989
  id: "default",
130557
130990
  label: "Default",
130558
- configDir: (0, import_path3.join)((0, import_os4.homedir)(), ".claude"),
130991
+ configDir: (0, import_path5.join)((0, import_os4.homedir)(), ".claude"),
130559
130992
  enabled: true,
130560
130993
  emoji: "\u{1F916}"
130561
130994
  };
@@ -130564,7 +130997,7 @@ async function loadProfiles(configPath) {
130564
130997
  const log8 = getLogger2();
130565
130998
  try {
130566
130999
  const resolved = resolveConfigDir(configPath);
130567
- const data = await (0, import_promises4.readFile)((0, import_path3.join)(resolved, PROFILES_FILE), "utf-8");
131000
+ const data = await (0, import_promises4.readFile)((0, import_path5.join)(resolved, PROFILES_FILE), "utf-8");
130568
131001
  const profiles = JSON.parse(data);
130569
131002
  log8.debug({ configPath, count: profiles.length }, "profiles: loaded");
130570
131003
  return profiles;
@@ -130574,34 +131007,6 @@ async function loadProfiles(configPath) {
130574
131007
  return [defaultProfile];
130575
131008
  }
130576
131009
  }
130577
- var SYSTEM_TAGS = [
130578
- "system-reminder",
130579
- "command-name",
130580
- "command-message",
130581
- "command-args",
130582
- "ide_selection",
130583
- "ide_opened_file",
130584
- "local-command-stdout",
130585
- "local-command-caveat",
130586
- "retrieval_status",
130587
- "task_id",
130588
- "task_type",
130589
- "task-id",
130590
- "task-notification",
130591
- "fast_mode_info",
130592
- "persisted-output",
130593
- "tool_use_error",
130594
- "user-prompt-submit-hook",
130595
- "thinking",
130596
- "ask_user",
130597
- "teammate-message"
130598
- ];
130599
- var SYSTEM_TAG_RE = new RegExp(`<(${SYSTEM_TAGS.join("|")})[^>]*>[\\s\\S]*?<\\/\\1>`, "g");
130600
- function cleanSystemTags(text) {
130601
- return text.replace(SYSTEM_TAG_RE, "").replace(/[^\S\n]+/g, " ").replace(/\n{3,}/g, "\n\n").trim();
130602
- }
130603
- var CLAUDE_CODE_PROVIDER = "claude-code";
130604
- var CODEX_CLI_PROVIDER = "codex-cli";
130605
131010
  var CodexCliProvider = class {
130606
131011
  name = CODEX_CLI_PROVIDER;
130607
131012
  async discover(roots) {
@@ -130734,7 +131139,7 @@ function reduceCodexEntry(acc, entry, tier) {
130734
131139
  }
130735
131140
  function finalizeCodexMeta(acc, filePath, account, tier) {
130736
131141
  if (acc.messageCount === 0) return null;
130737
- const sessionId = acc.sessionId || (0, import_path4.basename)(filePath, ".jsonl");
131142
+ const sessionId = acc.sessionId || (0, import_path6.basename)(filePath, ".jsonl");
130738
131143
  const projectPath = acc.cwd;
130739
131144
  const kind = acc.lastAssistant === null && acc.toolNames.length > 0 ? "task" : "conversation";
130740
131145
  return {
@@ -130746,7 +131151,7 @@ function finalizeCodexMeta(acc, filePath, account, tier) {
130746
131151
  sessionId,
130747
131152
  sessionName: "",
130748
131153
  projectPath,
130749
- projectName: getShortProjectName(projectPath),
131154
+ projectName: getShortProjectName3(projectPath),
130750
131155
  account,
130751
131156
  timestamp: acc.latestTimestamp || (/* @__PURE__ */ new Date()).toISOString(),
130752
131157
  messageCount: acc.messageCount,
@@ -130765,7 +131170,7 @@ function finalizeCodexMeta(acc, filePath, account, tier) {
130765
131170
  lastPrompt: acc.lastUser?.text || void 0
130766
131171
  };
130767
131172
  }
130768
- function getShortProjectName(fullPath) {
131173
+ function getShortProjectName3(fullPath) {
130769
131174
  return fullPath.split("/").filter(Boolean).slice(-3).join("/");
130770
131175
  }
130771
131176
  async function parseCodexConversation(filePath, account) {
@@ -130776,7 +131181,7 @@ async function parseCodexConversation(filePath, account) {
130776
131181
  let cwd = "";
130777
131182
  let latestTimestamp = "";
130778
131183
  let lastUserText = "";
130779
- const rl = (0, import_readline.createInterface)({ input: (0, import_fs6.createReadStream)(filePath), crlfDelay: Infinity });
131184
+ const rl = (0, import_readline2.createInterface)({ input: (0, import_fs7.createReadStream)(filePath), crlfDelay: Infinity });
130780
131185
  try {
130781
131186
  for await (const line of rl) {
130782
131187
  if (!line.trim()) continue;
@@ -130813,8 +131218,8 @@ async function parseCodexConversation(filePath, account) {
130813
131218
  id: filePath,
130814
131219
  filePath,
130815
131220
  projectPath: cwd,
130816
- projectName: getShortProjectName(cwd),
130817
- sessionId: sessionId || (0, import_path4.basename)(filePath, ".jsonl"),
131221
+ projectName: getShortProjectName3(cwd),
131222
+ sessionId: sessionId || (0, import_path6.basename)(filePath, ".jsonl"),
130818
131223
  sessionName: "",
130819
131224
  messages,
130820
131225
  fullText: textParts.join(" "),
@@ -130886,404 +131291,6 @@ async function discoverJsonlFiles(dirs, onProgress) {
130886
131291
  log8.debug({ totalFiles: results.length, dirs: dirs.length }, "discovery: complete");
130887
131292
  return results;
130888
131293
  }
130889
- function initialConvState() {
130890
- return {
130891
- cwd: "",
130892
- sessionId: "",
130893
- sessionName: "",
130894
- latestTimestamp: "",
130895
- lastPrompt: "",
130896
- pendingToolUses: {},
130897
- teamInfo: {}
130898
- };
130899
- }
130900
- function reduceConvLine(state, entry) {
130901
- if (entry.cwd && !state.cwd) state.cwd = entry.cwd;
130902
- if (entry.sessionId && !state.sessionId) state.sessionId = entry.sessionId;
130903
- if (entry.slug && !state.sessionName) state.sessionName = entry.slug;
130904
- if (entry.timestamp) {
130905
- const ts2 = entry.timestamp;
130906
- if (!state.latestTimestamp || ts2 > state.latestTimestamp) state.latestTimestamp = ts2;
130907
- }
130908
- const type = entry.type;
130909
- if (type === "last-prompt") {
130910
- if (entry.lastPrompt && !state.lastPrompt) state.lastPrompt = entry.lastPrompt;
130911
- return null;
130912
- }
130913
- if (type !== "user" && type !== "assistant") return null;
130914
- if (entry.isMeta) return null;
130915
- const msg = entry.message;
130916
- const toolUseBlocks = extractToolUseBlocks(msg?.content);
130917
- for (const block of toolUseBlocks) state.pendingToolUses[block.id] = block;
130918
- const hasToolUseResult = type === "user" && entry.toolUseResult != null;
130919
- const isToolResultOnly = hasToolUseResult && isOnlyToolResultContent(msg?.content);
130920
- const content = extractTextContent(msg?.content);
130921
- const thinking = type === "assistant" ? extractThinking(msg?.content) : null;
130922
- const hasThinking = !!(thinking?.content || thinking?.signature);
130923
- if (!(content || isToolResultOnly || toolUseBlocks.length > 0 || hasThinking)) return null;
130924
- const metadata = {};
130925
- if (msg?.model) metadata.model = msg.model;
130926
- if (msg?.stop_reason !== void 0) metadata.stopReason = msg.stop_reason;
130927
- if (entry.gitBranch) metadata.gitBranch = entry.gitBranch;
130928
- if (entry.version) metadata.version = entry.version;
130929
- const usage = msg?.usage;
130930
- if (usage) {
130931
- if (usage.input_tokens) metadata.inputTokens = usage.input_tokens;
130932
- if (usage.output_tokens) metadata.outputTokens = usage.output_tokens;
130933
- if (usage.cache_read_input_tokens) metadata.cacheReadTokens = usage.cache_read_input_tokens;
130934
- if (usage.cache_creation_input_tokens)
130935
- metadata.cacheCreationTokens = usage.cache_creation_input_tokens;
130936
- }
130937
- const toolUseNames = extractToolUseNames(msg?.content);
130938
- if (toolUseNames.length > 0) metadata.toolUses = toolUseNames;
130939
- if (toolUseBlocks.length > 0) metadata.toolUseBlocks = toolUseBlocks;
130940
- if (isToolResultOnly) {
130941
- const pending = new Map(Object.entries(state.pendingToolUses));
130942
- const toolResultBlocks = extractToolResultBlocks(msg?.content, pending);
130943
- if (toolResultBlocks.length > 0) metadata.toolResults = toolResultBlocks;
130944
- }
130945
- if (entry.teamName) {
130946
- metadata.teamName = entry.teamName;
130947
- if (!state.teamInfo[metadata.teamName] && content) {
130948
- const info = parseTeammateMessageTag(content);
130949
- if (info) state.teamInfo[metadata.teamName] = info;
130950
- }
130951
- }
130952
- const thinkingContent = thinking?.content || void 0;
130953
- const thinkingSignature = thinking?.signature || void 0;
130954
- const hasMetadata = Object.keys(metadata).length > 0;
130955
- return {
130956
- role: type,
130957
- text: content || "",
130958
- timestamp: entry.timestamp || "",
130959
- uuid: entry.uuid || void 0,
130960
- metadata: hasMetadata ? metadata : void 0,
130961
- isToolResult: isToolResultOnly || void 0,
130962
- isThinking: thinkingContent || thinkingSignature ? true : void 0,
130963
- thinkingContent,
130964
- thinkingSignature,
130965
- parentUuid: entry.parentUuid !== void 0 ? entry.parentUuid : void 0,
130966
- requestId: type === "assistant" ? entry.requestId : void 0,
130967
- promptId: type === "user" ? entry.promptId : void 0,
130968
- isSidechain: typeof entry.isSidechain === "boolean" ? entry.isSidechain : void 0,
130969
- permissionMode: type === "user" ? entry.permissionMode : void 0,
130970
- hasImages: hasImageBlocks(msg?.content) || void 0,
130971
- attachment: entry.attachment !== void 0 ? entry.attachment : void 0
130972
- };
130973
- }
130974
- function applyTeamInfo(messages, state) {
130975
- if (Object.keys(state.teamInfo).length === 0) return;
130976
- for (const m2 of messages) {
130977
- const name = m2.metadata?.teamName;
130978
- if (name && state.teamInfo[name] && m2.metadata) m2.metadata.teamInfo = state.teamInfo[name];
130979
- }
130980
- }
130981
- async function parseMeta(filePath, account, tier) {
130982
- const log8 = getLogger2();
130983
- log8.trace({ filePath, account, tier: tier.name }, "parseMeta: start");
130984
- const state = initialReducerState();
130985
- const fileStream = (0, import_fs7.createReadStream)(filePath);
130986
- const rl = (0, import_readline2.createInterface)({ input: fileStream, crlfDelay: Infinity });
130987
- try {
130988
- for await (const line of rl) {
130989
- if (!line.trim()) continue;
130990
- let entry;
130991
- try {
130992
- entry = JSON.parse(line);
130993
- } catch {
130994
- state.badJsonLines++;
130995
- continue;
130996
- }
130997
- reduceLine(state, entry, tier);
130998
- }
130999
- } catch (err) {
131000
- log8.warn({ filePath, err }, "parseMeta: read failed");
131001
- return null;
131002
- }
131003
- if (state.badJsonLines > 0) {
131004
- log8.warn(
131005
- { filePath, badJsonLines: state.badJsonLines },
131006
- "parseMeta: skipped malformed JSON lines"
131007
- );
131008
- }
131009
- const meta3 = finalizeMeta(state, filePath, account, tier);
131010
- if (!meta3) log8.trace({ filePath }, "parseMeta: no messages");
131011
- return meta3;
131012
- }
131013
- async function parseConversation(filePath, account) {
131014
- const log8 = getLogger2();
131015
- log8.trace({ filePath, account }, "parseConversation: start");
131016
- const messages = [];
131017
- let badJsonLines = 0;
131018
- const textParts = [];
131019
- const turnDurations = [];
131020
- const state = initialConvState();
131021
- const fileStream = (0, import_fs7.createReadStream)(filePath);
131022
- const rl = (0, import_readline2.createInterface)({ input: fileStream, crlfDelay: Infinity });
131023
- try {
131024
- for await (const line of rl) {
131025
- if (!line.trim()) continue;
131026
- let entry;
131027
- try {
131028
- entry = JSON.parse(line);
131029
- } catch {
131030
- badJsonLines++;
131031
- continue;
131032
- }
131033
- if (entry.type === "system" && entry.subtype === "turn_duration" && typeof entry.durationMs === "number") {
131034
- turnDurations.push({
131035
- durationMs: entry.durationMs,
131036
- messageCount: entry.messageCount || 0,
131037
- uuid: entry.uuid
131038
- });
131039
- continue;
131040
- }
131041
- const message = reduceConvLine(state, entry);
131042
- if (message) {
131043
- messages.push(message);
131044
- if (message.text) textParts.push(message.text);
131045
- }
131046
- }
131047
- } catch (err) {
131048
- log8.warn({ filePath, err }, "parseConversation: read failed");
131049
- return null;
131050
- }
131051
- if (badJsonLines > 0) {
131052
- log8.warn({ filePath, badJsonLines }, "parseConversation: skipped malformed JSON lines");
131053
- }
131054
- if (messages.length === 0) {
131055
- log8.trace({ filePath }, "parseConversation: no messages");
131056
- return null;
131057
- }
131058
- log8.debug({ filePath, messageCount: messages.length }, "parseConversation: complete");
131059
- applyTeamInfo(messages, state);
131060
- return {
131061
- id: filePath,
131062
- filePath,
131063
- projectPath: state.cwd,
131064
- projectName: getShortProjectName2(state.cwd),
131065
- sessionId: state.sessionId || (0, import_path6.basename)(filePath, ".jsonl"),
131066
- sessionName: state.sessionName,
131067
- messages,
131068
- fullText: textParts.join(" "),
131069
- timestamp: state.latestTimestamp || (/* @__PURE__ */ new Date()).toISOString(),
131070
- messageCount: messages.length,
131071
- account,
131072
- turnDurations: turnDurations.length > 0 ? turnDurations : void 0,
131073
- lastPrompt: state.lastPrompt || void 0
131074
- };
131075
- }
131076
- function extractTextContent(content) {
131077
- if (!content) return "";
131078
- if (typeof content === "string") return cleanSystemTags(content);
131079
- if (Array.isArray(content)) {
131080
- return content.map((item) => {
131081
- if (typeof item === "string") return item;
131082
- if (item?.type === "text" && item?.text) return item.text;
131083
- if (item?.type === "tool_result" && typeof item?.content === "string") return item.content;
131084
- return "";
131085
- }).filter(Boolean).map(cleanSystemTags).join(" ");
131086
- }
131087
- return "";
131088
- }
131089
- function extractToolUseNames(content) {
131090
- if (!Array.isArray(content)) return [];
131091
- return content.filter((item) => item?.type === "tool_use" && item?.name).map((item) => item.name);
131092
- }
131093
- function extractToolUseBlocks(content) {
131094
- if (!Array.isArray(content)) return [];
131095
- return content.filter((item) => item?.type === "tool_use" && item?.name && item?.id).map((item) => ({
131096
- id: item.id,
131097
- name: item.name,
131098
- input: item.input || {}
131099
- }));
131100
- }
131101
- var TOOL_NAME_TO_TYPE = {
131102
- Edit: "edit",
131103
- Write: "write",
131104
- Read: "read",
131105
- Bash: "bash",
131106
- Grep: "grep",
131107
- Glob: "glob",
131108
- Agent: "taskAgent",
131109
- TaskCreate: "taskCreate",
131110
- TaskUpdate: "taskUpdate"
131111
- };
131112
- function extractToolResultBlocks(content, pendingToolUses) {
131113
- if (!Array.isArray(content)) return [];
131114
- return content.filter((item) => item?.type === "tool_result" && item?.tool_use_id).map((item) => {
131115
- const toolName = pendingToolUses.get(item.tool_use_id)?.name ?? "";
131116
- return {
131117
- toolUseId: item.tool_use_id,
131118
- type: TOOL_NAME_TO_TYPE[toolName] ?? "generic",
131119
- content: typeof item.content === "string" ? { text: item.content } : item.content ?? {},
131120
- isError: typeof item.is_error === "boolean" ? item.is_error : void 0
131121
- };
131122
- });
131123
- }
131124
- function collectToolNames(content, toolSet) {
131125
- if (!Array.isArray(content)) return;
131126
- for (const item of content) {
131127
- if (item?.type === "tool_use" && item?.name) {
131128
- toolSet.add(item.name);
131129
- }
131130
- }
131131
- }
131132
- function isOnlyToolResultContent(content) {
131133
- if (!Array.isArray(content)) return false;
131134
- return content.length > 0 && content.every((item) => item?.type === "tool_result");
131135
- }
131136
- function isTeammateContent(content) {
131137
- const raw2 = typeof content === "string" ? content : Array.isArray(content) ? content.map(
131138
- (item) => typeof item === "string" ? item : item?.type === "text" ? item.text ?? "" : ""
131139
- ).join("") : "";
131140
- return raw2.includes("<teammate-message");
131141
- }
131142
- function extractThinking(content) {
131143
- if (!Array.isArray(content)) return { content: "", signature: "" };
131144
- const blocks = content.filter((item) => item?.type === "thinking");
131145
- return {
131146
- content: blocks.map((b2) => b2.thinking).filter(Boolean).join("\n\n"),
131147
- signature: blocks.map((b2) => b2.signature).filter(Boolean).join("")
131148
- };
131149
- }
131150
- function hasImageBlocks(content) {
131151
- if (!Array.isArray(content)) return false;
131152
- return content.some(
131153
- (item) => item?.type === "image" && (item?.source?.type === "base64" || item?.file?.base64 !== void 0)
131154
- );
131155
- }
131156
- function parseTeammateMessageTag(content) {
131157
- const match2 = content.match(/<teammate-message\s+([^>]*)>/);
131158
- if (!match2) return null;
131159
- const attrs = match2[1];
131160
- const id = attrs.match(/teammate_id="([^"]*)"/)?.[1];
131161
- if (!id) return null;
131162
- const summary = attrs.match(/summary="([^"]*)"/)?.[1];
131163
- const color = attrs.match(/color="([^"]*)"/)?.[1];
131164
- return { teammateId: id, summary, color };
131165
- }
131166
- function getShortProjectName2(fullPath) {
131167
- const parts = fullPath.split("/").filter(Boolean);
131168
- return parts.slice(-3).join("/");
131169
- }
131170
- function initialReducerState() {
131171
- return {
131172
- sessionId: "",
131173
- sessionName: "",
131174
- latestTimestamp: "",
131175
- cwd: "",
131176
- teamName: "",
131177
- model: null,
131178
- messageCount: 0,
131179
- lastMessageSender: "user",
131180
- isTeammate: false,
131181
- firstUserSeen: false,
131182
- firstMessage: null,
131183
- lastMessage: null,
131184
- lastPrompt: "",
131185
- pageMessageCount: 0,
131186
- toolNames: [],
131187
- previewParts: [],
131188
- snippetParts: [],
131189
- previewLength: 0,
131190
- snippetLength: 0,
131191
- badJsonLines: 0
131192
- };
131193
- }
131194
- function reduceLine(state, entry, tier) {
131195
- if (entry.cwd && !state.cwd) state.cwd = entry.cwd;
131196
- if (entry.sessionId && !state.sessionId) state.sessionId = entry.sessionId;
131197
- if (entry.slug && !state.sessionName) state.sessionName = entry.slug;
131198
- if (entry.teamName && !state.teamName) state.teamName = entry.teamName;
131199
- if (entry.timestamp) {
131200
- const ts2 = entry.timestamp;
131201
- if (!state.latestTimestamp || ts2 > state.latestTimestamp) state.latestTimestamp = ts2;
131202
- }
131203
- const type = entry.type;
131204
- if (type === "last-prompt") {
131205
- if (entry.lastPrompt && !state.lastPrompt) state.lastPrompt = entry.lastPrompt;
131206
- return;
131207
- }
131208
- if (type !== "user" && type !== "assistant") return;
131209
- if (entry.isMeta) return;
131210
- const msg = entry.message;
131211
- if (state.model === null && msg?.model) state.model = msg.model;
131212
- if (type === "user" && !state.firstUserSeen) {
131213
- state.firstUserSeen = true;
131214
- if (isTeammateContent(msg?.content)) state.isTeammate = true;
131215
- }
131216
- const content = extractTextContent(msg?.content);
131217
- const hasToolUseResult = type === "user" && entry.toolUseResult != null;
131218
- const isOnlyToolResult = hasToolUseResult && isOnlyToolResultContent(msg?.content);
131219
- const toolSet = new Set(state.toolNames);
131220
- collectToolNames(msg?.content, toolSet);
131221
- state.toolNames = Array.from(toolSet);
131222
- const toolUseBlocks = extractToolUseBlocks(msg?.content);
131223
- const thinking = type === "assistant" ? extractThinking(msg?.content) : null;
131224
- const hasThinking = !!(thinking?.content || thinking?.signature);
131225
- if (content || isOnlyToolResult || toolUseBlocks.length > 0 || hasThinking) {
131226
- state.pageMessageCount++;
131227
- }
131228
- if (content || isOnlyToolResult) {
131229
- state.messageCount++;
131230
- state.lastMessageSender = type;
131231
- if (content) {
131232
- const ts2 = entry.timestamp || "";
131233
- if (!state.firstMessage) state.firstMessage = { text: content.slice(0, 200), timestamp: ts2 };
131234
- state.lastMessage = { text: content.slice(0, 200), timestamp: ts2 };
131235
- if (state.previewLength < tier.previewMax) {
131236
- state.previewParts.push(content);
131237
- state.previewLength += content.length;
131238
- }
131239
- if (state.snippetLength < tier.snippetMax) {
131240
- const remaining = tier.snippetMax - state.snippetLength;
131241
- const chunk = content.length > remaining ? content.slice(0, remaining) : content;
131242
- state.snippetParts.push(chunk);
131243
- state.snippetLength += chunk.length;
131244
- }
131245
- }
131246
- }
131247
- }
131248
- function finalizeMeta(state, filePath, account, tier) {
131249
- if (state.messageCount === 0) return null;
131250
- const isSubagent = filePath.includes("/subagents/");
131251
- let parentSessionId = null;
131252
- if (isSubagent) {
131253
- const uuidDir = (0, import_path5.dirname)((0, import_path5.dirname)(filePath));
131254
- parentSessionId = (0, import_path5.join)((0, import_path5.dirname)(uuidDir), `${(0, import_path5.basename)(uuidDir)}.jsonl`);
131255
- }
131256
- const projectPath = state.cwd;
131257
- return {
131258
- id: filePath,
131259
- filePath,
131260
- provider: CLAUDE_CODE_PROVIDER,
131261
- sessionId: state.sessionId || (0, import_path5.basename)(filePath, ".jsonl"),
131262
- sessionName: state.sessionName,
131263
- projectPath,
131264
- projectName: getShortProjectName3(projectPath),
131265
- account,
131266
- timestamp: state.latestTimestamp || (/* @__PURE__ */ new Date()).toISOString(),
131267
- messageCount: state.messageCount,
131268
- lastMessageSender: state.lastMessageSender,
131269
- preview: state.previewParts.join(" ").slice(0, tier.previewMax),
131270
- contentSnippet: state.snippetParts.join(" "),
131271
- gitBranch: null,
131272
- model: state.model,
131273
- isSubagent,
131274
- parentSessionId,
131275
- isTeammate: state.isTeammate,
131276
- teamName: state.teamName || null,
131277
- toolNames: state.toolNames,
131278
- firstMessage: state.firstMessage,
131279
- lastMessage: state.lastMessage,
131280
- lastPrompt: state.lastPrompt || void 0
131281
- };
131282
- }
131283
- function getShortProjectName3(fullPath) {
131284
- const parts = fullPath.split("/").filter(Boolean);
131285
- return parts.slice(-3).join("/");
131286
- }
131287
131294
  var ThreadbaseProvider = class {
131288
131295
  name = CLAUDE_CODE_PROVIDER;
131289
131296
  // Roots are passed as "<projectsDir>\0<account>" so the scanner can carry the
@@ -131352,32 +131359,219 @@ var LRUCache = class {
131352
131359
  return this.map.size;
131353
131360
  }
131354
131361
  };
131362
+ var YIELD_EVERY_LINES = 500;
131363
+ async function tailReduce(filePath, startOffset, startLine, state, tier) {
131364
+ const stream = (0, import_fs10.createReadStream)(filePath, { start: startOffset, encoding: "utf8" });
131365
+ let buffer = "";
131366
+ let offset = startOffset;
131367
+ let line = startLine;
131368
+ let parsedLines = 0;
131369
+ let sinceYield = 0;
131370
+ for await (const chunk of stream) {
131371
+ buffer += chunk;
131372
+ let nl;
131373
+ while ((nl = buffer.indexOf("\n")) >= 0) {
131374
+ const lineWithNewline = buffer.slice(0, nl + 1);
131375
+ const text = lineWithNewline.trimEnd();
131376
+ buffer = buffer.slice(nl + 1);
131377
+ if (text.length > 0) {
131378
+ try {
131379
+ reduceLine(state, JSON.parse(text), tier);
131380
+ } catch {
131381
+ state.badJsonLines++;
131382
+ }
131383
+ parsedLines++;
131384
+ }
131385
+ offset += Buffer.byteLength(lineWithNewline, "utf8");
131386
+ line++;
131387
+ if (++sinceYield >= YIELD_EVERY_LINES) {
131388
+ sinceYield = 0;
131389
+ await (0, import_promises8.setImmediate)();
131390
+ }
131391
+ }
131392
+ }
131393
+ return { newOffset: offset, newLine: line, parsedLines, badJsonLines: state.badJsonLines };
131394
+ }
131395
+ var CHECKPOINT_INTERVAL = 500;
131396
+ async function streamMessages(filePath, startOffset, startLine, state, onMessage, onEntry) {
131397
+ const stream = (0, import_fs9.createReadStream)(filePath, { start: startOffset, encoding: "utf8" });
131398
+ let buffer = "";
131399
+ let offset = startOffset;
131400
+ let line = startLine;
131401
+ let sinceYield = 0;
131402
+ for await (const chunk of stream) {
131403
+ buffer += chunk;
131404
+ let nl;
131405
+ while ((nl = buffer.indexOf("\n")) >= 0) {
131406
+ const lineWithNewline = buffer.slice(0, nl + 1);
131407
+ const text = lineWithNewline.trimEnd();
131408
+ buffer = buffer.slice(nl + 1);
131409
+ offset += Buffer.byteLength(lineWithNewline, "utf8");
131410
+ line += 1;
131411
+ if (++sinceYield >= YIELD_EVERY_LINES) {
131412
+ sinceYield = 0;
131413
+ await (0, import_promises7.setImmediate)();
131414
+ }
131415
+ if (text.length === 0) continue;
131416
+ let entry;
131417
+ try {
131418
+ entry = JSON.parse(text);
131419
+ } catch {
131420
+ continue;
131421
+ }
131422
+ if (onEntry?.(entry)) continue;
131423
+ const message = reduceConvLine(state, entry);
131424
+ if (message && onMessage(message, offset, line)) {
131425
+ stream.destroy();
131426
+ return { offset, line };
131427
+ }
131428
+ }
131429
+ }
131430
+ return { offset, line };
131431
+ }
131432
+ async function buildCheckpoints(filePath, interval = CHECKPOINT_INTERVAL, from = null) {
131433
+ const checkpoints = [];
131434
+ const state = from ? from.state : initialConvState();
131435
+ let index = from ? from.messageIndex : 0;
131436
+ await streamMessages(
131437
+ filePath,
131438
+ from?.byteOffset ?? 0,
131439
+ from?.lineNumber ?? 0,
131440
+ state,
131441
+ (_msg, nextOffset, nextLine) => {
131442
+ index += 1;
131443
+ if (index % interval === 0) {
131444
+ checkpoints.push({
131445
+ messageIndex: index,
131446
+ byteOffset: nextOffset,
131447
+ lineNumber: nextLine,
131448
+ state: structuredClone(state)
131449
+ });
131450
+ }
131451
+ return false;
131452
+ }
131453
+ );
131454
+ return checkpoints;
131455
+ }
131456
+ async function readPage(filePath, total, options, floor) {
131457
+ const beforeIndex = options.beforeIndex ?? total;
131458
+ const fromIndex = Math.max(0, beforeIndex - options.limit);
131459
+ const state = floor ? structuredClone(floor.state) : initialConvState();
131460
+ const startOffset = floor ? floor.byteOffset : 0;
131461
+ const startLine = floor ? floor.lineNumber : 0;
131462
+ let index = floor ? floor.messageIndex : 0;
131463
+ const window2 = [];
131464
+ await streamMessages(filePath, startOffset, startLine, state, (message) => {
131465
+ const current = index;
131466
+ index += 1;
131467
+ if (current >= fromIndex && current < beforeIndex) window2.push(message);
131468
+ return index >= beforeIndex;
131469
+ });
131470
+ applyTeamInfo(window2, state);
131471
+ return { messages: window2, total, fromIndex };
131472
+ }
131473
+ async function foldTail(filePath, resume) {
131474
+ const messages = [];
131475
+ const textParts = [];
131476
+ const turnDurations = [];
131477
+ const end = await streamMessages(
131478
+ filePath,
131479
+ resume.offset,
131480
+ resume.line,
131481
+ resume.state,
131482
+ (message) => {
131483
+ messages.push(message);
131484
+ if (message.text) textParts.push(message.text);
131485
+ return false;
131486
+ },
131487
+ (entry) => {
131488
+ if (entry.type === "system" && entry.subtype === "turn_duration" && typeof entry.durationMs === "number") {
131489
+ turnDurations.push({
131490
+ durationMs: entry.durationMs,
131491
+ messageCount: entry.messageCount || 0,
131492
+ uuid: entry.uuid
131493
+ });
131494
+ return true;
131495
+ }
131496
+ return false;
131497
+ }
131498
+ );
131499
+ return { messages, textParts, turnDurations, end };
131500
+ }
131501
+ function assemble(filePath, account, messages, fullText, turnDurations, state) {
131502
+ return {
131503
+ id: filePath,
131504
+ filePath,
131505
+ projectPath: state.cwd,
131506
+ projectName: getShortProjectName2(state.cwd),
131507
+ sessionId: state.sessionId || (0, import_path8.basename)(filePath, ".jsonl"),
131508
+ sessionName: state.sessionName,
131509
+ messages,
131510
+ fullText,
131511
+ timestamp: state.latestTimestamp || (/* @__PURE__ */ new Date()).toISOString(),
131512
+ messageCount: messages.length,
131513
+ account,
131514
+ turnDurations: turnDurations.length > 0 ? turnDurations : void 0,
131515
+ lastPrompt: state.lastPrompt || void 0
131516
+ };
131517
+ }
131518
+ async function parseConversationResumable(filePath, account) {
131519
+ const resume = { state: initialConvState(), offset: 0, line: 0 };
131520
+ const { messages, textParts, turnDurations, end } = await foldTail(filePath, resume);
131521
+ if (messages.length === 0) return null;
131522
+ applyTeamInfo(messages, resume.state);
131523
+ const conversation = assemble(
131524
+ filePath,
131525
+ account,
131526
+ messages,
131527
+ textParts.join(" "),
131528
+ turnDurations,
131529
+ resume.state
131530
+ );
131531
+ return { conversation, resume: { state: resume.state, offset: end.offset, line: end.line } };
131532
+ }
131533
+ async function extendConversation(previous, resume, filePath, account) {
131534
+ const { messages: fresh, textParts, turnDurations, end } = await foldTail(filePath, resume);
131535
+ const messages = fresh.length > 0 ? previous.messages.concat(fresh) : previous.messages;
131536
+ applyTeamInfo(messages, resume.state);
131537
+ const fullText = textParts.length === 0 ? previous.fullText : previous.fullText ? `${previous.fullText} ${textParts.join(" ")}` : textParts.join(" ");
131538
+ const allTurnDurations = (previous.turnDurations ?? []).concat(turnDurations);
131539
+ const conversation = assemble(
131540
+ filePath,
131541
+ account,
131542
+ messages,
131543
+ fullText,
131544
+ allTurnDurations,
131545
+ resume.state
131546
+ );
131547
+ return { conversation, resume: { state: resume.state, offset: end.offset, line: end.line } };
131548
+ }
131355
131549
  var FP_BYTES = 4096;
131356
131550
  function fingerprint(filePath, size) {
131357
131551
  const hash2 = (0, import_crypto2.createHash)("sha1");
131358
131552
  hash2.update(String(size));
131359
- const fd = (0, import_fs9.openSync)(filePath, "r");
131553
+ const fd = (0, import_fs11.openSync)(filePath, "r");
131360
131554
  try {
131361
131555
  const head = Buffer.alloc(Math.min(FP_BYTES, size));
131362
131556
  if (head.length > 0) {
131363
- (0, import_fs9.readSync)(fd, head, 0, head.length, 0);
131557
+ (0, import_fs11.readSync)(fd, head, 0, head.length, 0);
131364
131558
  hash2.update(head);
131365
131559
  }
131366
131560
  if (size > FP_BYTES) {
131367
131561
  const tailLen = Math.min(FP_BYTES, size);
131368
131562
  const tail = Buffer.alloc(tailLen);
131369
- (0, import_fs9.readSync)(fd, tail, 0, tailLen, size - tailLen);
131563
+ (0, import_fs11.readSync)(fd, tail, 0, tailLen, size - tailLen);
131370
131564
  hash2.update(tail);
131371
131565
  }
131372
131566
  } finally {
131373
- (0, import_fs9.closeSync)(fd);
131567
+ (0, import_fs11.closeSync)(fd);
131374
131568
  }
131375
131569
  return hash2.digest("hex");
131376
131570
  }
131377
131571
  function classify(filePath, existing) {
131378
131572
  let stat42;
131379
131573
  try {
131380
- const s3 = (0, import_fs9.statSync)(filePath);
131574
+ const s3 = (0, import_fs11.statSync)(filePath);
131381
131575
  stat42 = { size: s3.size, mtimeMs: s3.mtimeMs };
131382
131576
  } catch {
131383
131577
  return { change: "vanished" };
@@ -131407,7 +131601,7 @@ async function parseMetaWithProvider(provider, filePath, account, tier) {
131407
131601
  const log8 = getLogger2();
131408
131602
  const acc = provider.createEmptyAccumulator();
131409
131603
  const rl = (0, import_readline3.createInterface)({
131410
- input: (0, import_fs10.createReadStream)(filePath),
131604
+ input: (0, import_fs13.createReadStream)(filePath),
131411
131605
  crlfDelay: Infinity
131412
131606
  });
131413
131607
  try {
@@ -131630,7 +131824,7 @@ function hasColumn(db, table, column) {
131630
131824
  }
131631
131825
  function openDatabase(dbPath) {
131632
131826
  if (dbPath !== ":memory:") {
131633
- (0, import_fs11.mkdirSync)((0, import_path8.dirname)(dbPath), { recursive: true });
131827
+ (0, import_fs14.mkdirSync)((0, import_path9.dirname)(dbPath), { recursive: true });
131634
131828
  }
131635
131829
  const db = new import_better_sqlite3.default(dbPath);
131636
131830
  db.pragma("journal_mode = WAL");
@@ -131656,7 +131850,7 @@ async function discoverJsonlFilesGated(dirs, files, scannedDirs, options = {}) {
131656
131850
  for (const projectDir of resolved.entries) {
131657
131851
  let dirStat;
131658
131852
  try {
131659
- dirStat = await (0, import_promises7.stat)(projectDir);
131853
+ dirStat = await (0, import_promises9.stat)(projectDir);
131660
131854
  } catch {
131661
131855
  scannedDirs.remove(projectDir);
131662
131856
  continue;
@@ -131694,7 +131888,7 @@ async function discoverJsonlFilesGated(dirs, files, scannedDirs, options = {}) {
131694
131888
  async function resolveProjectDirs(projectsDir, scannedDirs) {
131695
131889
  let rootStat;
131696
131890
  try {
131697
- rootStat = await (0, import_promises7.stat)(projectsDir);
131891
+ rootStat = await (0, import_promises9.stat)(projectsDir);
131698
131892
  } catch {
131699
131893
  return null;
131700
131894
  }
@@ -131704,7 +131898,7 @@ async function resolveProjectDirs(projectsDir, scannedDirs) {
131704
131898
  }
131705
131899
  let entries;
131706
131900
  try {
131707
- entries = (await (0, import_promises7.readdir)(projectsDir, { withFileTypes: true })).filter((e) => e.isDirectory()).map((e) => joinPath(projectsDir, e.name));
131901
+ entries = (await (0, import_promises9.readdir)(projectsDir, { withFileTypes: true })).filter((e) => e.isDirectory()).map((e) => joinPath(projectsDir, e.name));
131708
131902
  } catch {
131709
131903
  return null;
131710
131904
  }
@@ -131717,98 +131911,6 @@ function dirnameOf(filePath) {
131717
131911
  function joinPath(dir, name) {
131718
131912
  return dir.endsWith("/") ? `${dir}${name}` : `${dir}/${name}`;
131719
131913
  }
131720
- async function tailReduce(filePath, startOffset, startLine, state, tier) {
131721
- const stream = (0, import_fs12.createReadStream)(filePath, { start: startOffset, encoding: "utf8" });
131722
- let buffer = "";
131723
- let offset = startOffset;
131724
- let line = startLine;
131725
- let parsedLines = 0;
131726
- for await (const chunk of stream) {
131727
- buffer += chunk;
131728
- let nl;
131729
- while ((nl = buffer.indexOf("\n")) >= 0) {
131730
- const lineWithNewline = buffer.slice(0, nl + 1);
131731
- const text = lineWithNewline.trimEnd();
131732
- buffer = buffer.slice(nl + 1);
131733
- if (text.length > 0) {
131734
- try {
131735
- reduceLine(state, JSON.parse(text), tier);
131736
- } catch {
131737
- state.badJsonLines++;
131738
- }
131739
- parsedLines++;
131740
- }
131741
- offset += Buffer.byteLength(lineWithNewline, "utf8");
131742
- line++;
131743
- }
131744
- }
131745
- return { newOffset: offset, newLine: line, parsedLines, badJsonLines: state.badJsonLines };
131746
- }
131747
- var CHECKPOINT_INTERVAL = 500;
131748
- async function streamMessages(filePath, startOffset, startLine, state, onMessage) {
131749
- const stream = (0, import_fs13.createReadStream)(filePath, { start: startOffset, encoding: "utf8" });
131750
- let buffer = "";
131751
- let offset = startOffset;
131752
- let line = startLine;
131753
- for await (const chunk of stream) {
131754
- buffer += chunk;
131755
- let nl;
131756
- while ((nl = buffer.indexOf("\n")) >= 0) {
131757
- const lineWithNewline = buffer.slice(0, nl + 1);
131758
- const text = lineWithNewline.trimEnd();
131759
- buffer = buffer.slice(nl + 1);
131760
- offset += Buffer.byteLength(lineWithNewline, "utf8");
131761
- line += 1;
131762
- if (text.length === 0) continue;
131763
- let entry;
131764
- try {
131765
- entry = JSON.parse(text);
131766
- } catch {
131767
- continue;
131768
- }
131769
- const message = reduceConvLine(state, entry);
131770
- if (message && onMessage(message, offset, line)) {
131771
- stream.destroy();
131772
- return;
131773
- }
131774
- }
131775
- }
131776
- }
131777
- async function buildCheckpoints(filePath, interval = CHECKPOINT_INTERVAL) {
131778
- const checkpoints = [];
131779
- const state = initialConvState();
131780
- let index = 0;
131781
- await streamMessages(filePath, 0, 0, state, (_msg, nextOffset, nextLine) => {
131782
- index += 1;
131783
- if (index % interval === 0) {
131784
- checkpoints.push({
131785
- messageIndex: index,
131786
- byteOffset: nextOffset,
131787
- lineNumber: nextLine,
131788
- state: structuredClone(state)
131789
- });
131790
- }
131791
- return false;
131792
- });
131793
- return checkpoints;
131794
- }
131795
- async function readPage(filePath, total, options, floor) {
131796
- const beforeIndex = options.beforeIndex ?? total;
131797
- const fromIndex = Math.max(0, beforeIndex - options.limit);
131798
- const state = floor ? structuredClone(floor.state) : initialConvState();
131799
- const startOffset = floor ? floor.byteOffset : 0;
131800
- const startLine = floor ? floor.lineNumber : 0;
131801
- let index = floor ? floor.messageIndex : 0;
131802
- const window2 = [];
131803
- await streamMessages(filePath, startOffset, startLine, state, (message) => {
131804
- const current = index;
131805
- index += 1;
131806
- if (current >= fromIndex && current < beforeIndex) window2.push(message);
131807
- return index >= beforeIndex;
131808
- });
131809
- applyTeamInfo(window2, state);
131810
- return { messages: window2, total, fromIndex };
131811
- }
131812
131914
  var CheckpointsRepo = class {
131813
131915
  constructor(db) {
131814
131916
  this.db = db;
@@ -131828,6 +131930,22 @@ var CheckpointsRepo = class {
131828
131930
  });
131829
131931
  tx();
131830
131932
  }
131933
+ // Insert checkpoints without touching existing rows. Appends never invalidate
131934
+ // the chain covering the immutable prefix (Kafka sparse-index style); rows are
131935
+ // only ever removed on truncation/replace or deletion.
131936
+ append(sourcePath, checkpoints) {
131937
+ const tx = this.db.transaction(() => {
131938
+ const insert = this.db.prepare(
131939
+ `INSERT INTO message_checkpoints
131940
+ (source_path, message_index, byte_offset, line_number, parser_state)
131941
+ VALUES (?, ?, ?, ?, ?)`
131942
+ );
131943
+ for (const c of checkpoints) {
131944
+ insert.run(sourcePath, c.messageIndex, c.byteOffset, c.lineNumber, JSON.stringify(c.state));
131945
+ }
131946
+ });
131947
+ tx();
131948
+ }
131831
131949
  // The latest checkpoint at or before `messageIndex`, or null if none (read
131832
131950
  // from the file start). Lets a page seek to the nearest prior anchor.
131833
131951
  floor(sourcePath, messageIndex) {
@@ -131839,6 +131957,17 @@ var CheckpointsRepo = class {
131839
131957
  ).get(sourcePath, messageIndex);
131840
131958
  return row ? toCheckpoint(row) : null;
131841
131959
  }
131960
+ // The highest-index checkpoint for a file, or null if none. The resume point
131961
+ // for extending the chain after an append.
131962
+ last(sourcePath) {
131963
+ const row = this.db.prepare(
131964
+ `SELECT message_index, byte_offset, line_number, parser_state
131965
+ FROM message_checkpoints
131966
+ WHERE source_path = ?
131967
+ ORDER BY message_index DESC LIMIT 1`
131968
+ ).get(sourcePath);
131969
+ return row ? toCheckpoint(row) : null;
131970
+ }
131842
131971
  count(sourcePath) {
131843
131972
  return this.db.prepare("SELECT COUNT(*) AS n FROM message_checkpoints WHERE source_path = ?").get(sourcePath).n;
131844
131973
  }
@@ -131870,7 +131999,7 @@ var ConversationFilesRepo = class {
131870
131999
  const info = this.db.prepare(
131871
132000
  `INSERT INTO conversation_files (absolute_path, parent_dir, file_name, account)
131872
132001
  VALUES (?, ?, ?, ?)`
131873
- ).run(absolutePath, (0, import_path9.dirname)(absolutePath), (0, import_path9.basename)(absolutePath), account);
132002
+ ).run(absolutePath, (0, import_path10.dirname)(absolutePath), (0, import_path10.basename)(absolutePath), account);
131874
132003
  return Number(info.lastInsertRowid);
131875
132004
  }
131876
132005
  // Advance the cursor + persisted reducer state after a successful index pass.
@@ -132221,6 +132350,9 @@ var PersistentEngine = class {
132221
132350
  // restart just means the first few post-restart scans don't force an early
132222
132351
  // backstop pass, which is harmless (watermarks themselves persist in the DB).
132223
132352
  scanCount = 0;
132353
+ // In-flight checkpoint build/extension per file, so concurrent getPage
132354
+ // callers share one stream instead of each walking the file.
132355
+ checkpointBuilds = /* @__PURE__ */ new Map();
132224
132356
  constructor(dbPath, options = {}) {
132225
132357
  this.db = openDatabase(dbPath);
132226
132358
  this.files = new ConversationFilesRepo(this.db);
@@ -132273,7 +132405,7 @@ var PersistentEngine = class {
132273
132405
  const batch = discovered.slice(i, i + BATCH_SIZE);
132274
132406
  const results = await Promise.all(
132275
132407
  batch.map(async ({ filePath, account, provider }) => {
132276
- const meta3 = await this.indexFile(
132408
+ const { meta: meta3 } = await this.indexFile(
132277
132409
  filePath,
132278
132410
  account,
132279
132411
  tier.name,
@@ -132308,7 +132440,9 @@ var PersistentEngine = class {
132308
132440
  // unchanged → return the stored summary; appended → resume the fold and read
132309
132441
  // only new bytes; reindex/force → fold from offset 0. Writes the summary +
132310
132442
  // cursor + reducer state in one transaction so a crash never leaves a
132311
- // half-written row or an over-advanced cursor.
132443
+ // half-written row or an over-advanced cursor. Returns the classification
132444
+ // alongside the meta so callers (refreshFile) can keep, extend, or evict
132445
+ // their own per-file caches without re-stat'ing the file (racy) themselves.
132312
132446
  async indexFile(filePath, account, tierName, customTiers, resolveGitBranch, force = false, provider) {
132313
132447
  const log8 = getLogger2();
132314
132448
  const tier = resolveTier(tierName, customTiers);
@@ -132316,13 +132450,21 @@ var PersistentEngine = class {
132316
132450
  const { change, stat: stat42 } = classify(filePath, existing);
132317
132451
  if (change === "vanished" || !stat42) {
132318
132452
  this.markDeleted(filePath);
132319
- return null;
132453
+ return { meta: null, change: "vanished" };
132320
132454
  }
132321
132455
  if (change === "unchanged" && !force) {
132322
- return this.conversations.getBySourcePath(filePath);
132456
+ return { meta: this.conversations.getBySourcePath(filePath), change };
132323
132457
  }
132324
132458
  if (provider && provider.name !== CLAUDE_CODE_PROVIDER) {
132325
- return this.indexFileWithProvider(provider, filePath, account, tier, stat42, resolveGitBranch);
132459
+ const meta22 = await this.indexFileWithProvider(
132460
+ provider,
132461
+ filePath,
132462
+ account,
132463
+ tier,
132464
+ stat42,
132465
+ resolveGitBranch
132466
+ );
132467
+ return { meta: meta22, change };
132326
132468
  }
132327
132469
  const resume = change === "appended" && !force && existing?.reducer_state;
132328
132470
  const state = resume ? JSON.parse(existing.reducer_state) : initialReducerState();
@@ -132333,12 +132475,12 @@ var PersistentEngine = class {
132333
132475
  result = await tailReduce(filePath, startOffset, startLine, state, tier);
132334
132476
  } catch (err) {
132335
132477
  log8.warn({ filePath, err }, "persistent: tail read failed");
132336
- return null;
132478
+ return { meta: null, change };
132337
132479
  }
132338
132480
  const meta3 = finalizeMeta(state, filePath, account, tier);
132339
132481
  if (!meta3) {
132340
132482
  this.markDeleted(filePath);
132341
- return null;
132483
+ return { meta: null, change };
132342
132484
  }
132343
132485
  meta3.gitBranch = resolveGitBranch(meta3.projectPath);
132344
132486
  const fp = stat42.size > 0 ? fingerprint(filePath, stat42.size) : null;
@@ -132346,7 +132488,7 @@ var PersistentEngine = class {
132346
132488
  const upsert = this.db.transaction(() => {
132347
132489
  this.conversations.upsert(fileId, meta3, state.pageMessageCount);
132348
132490
  this.fts.upsert(meta3);
132349
- this.checkpoints.remove(filePath);
132491
+ if (!resume) this.checkpoints.remove(filePath);
132350
132492
  this.files.updateCursor(fileId, {
132351
132493
  sizeBytes: stat42.size,
132352
132494
  mtimeMs: stat42.mtimeMs,
@@ -132379,7 +132521,7 @@ var PersistentEngine = class {
132379
132521
  { filePath, change, bytesRead: result.newOffset - startOffset, msgs: meta3.messageCount },
132380
132522
  "persistent: indexed file"
132381
132523
  );
132382
- return meta3;
132524
+ return { meta: meta3, change };
132383
132525
  }
132384
132526
  // Index a non-Threadbase provider file: full reparse from offset 0 through the
132385
132527
  // provider's reducer/finalize, then the same upsert + FTS write + cursor bump
@@ -132479,15 +132621,40 @@ var PersistentEngine = class {
132479
132621
  return { messages: messages.slice(fromIndex2, beforeIndex2), total: total2, fromIndex: fromIndex2 };
132480
132622
  }
132481
132623
  const total = this.conversations.pageMessageCount(filePath);
132482
- if (total > CHECKPOINT_INTERVAL && this.checkpoints.count(filePath) === 0) {
132483
- const built = await buildCheckpoints(filePath);
132484
- if (built.length > 0) this.checkpoints.replaceAll(filePath, built);
132485
- }
132624
+ await this.ensureCheckpoints(filePath, total);
132486
132625
  const beforeIndex = options.beforeIndex ?? total;
132487
132626
  const fromIndex = Math.max(0, beforeIndex - options.limit);
132488
- const floor = this.checkpoints.floor(filePath, fromIndex);
132627
+ let floor = this.checkpoints.floor(filePath, fromIndex);
132628
+ if (floor) {
132629
+ try {
132630
+ if (floor.byteOffset > (0, import_fs12.statSync)(filePath).size) floor = null;
132631
+ } catch {
132632
+ }
132633
+ }
132489
132634
  return readPage(filePath, total, options, floor);
132490
132635
  }
132636
+ // Build or extend the checkpoint chain so it covers `total` messages. Cold
132637
+ // file → full build; a file that grew → extend from the last persisted
132638
+ // checkpoint (reads only past its offset, never the prefix). Single-flighted
132639
+ // per path: concurrent getPage callers await the same build instead of
132640
+ // streaming the file in parallel.
132641
+ ensureCheckpoints(filePath, total) {
132642
+ if (total <= CHECKPOINT_INTERVAL) return Promise.resolve();
132643
+ const inFlight = this.checkpointBuilds.get(filePath);
132644
+ if (inFlight) return inFlight;
132645
+ const build2 = (async () => {
132646
+ const last = this.checkpoints.last(filePath);
132647
+ if (last && total < last.messageIndex + CHECKPOINT_INTERVAL) return;
132648
+ const fresh = await buildCheckpoints(filePath, CHECKPOINT_INTERVAL, last);
132649
+ if (fresh.length === 0) return;
132650
+ if (last) this.checkpoints.append(filePath, fresh);
132651
+ else this.checkpoints.replaceAll(filePath, fresh);
132652
+ })().finally(() => {
132653
+ if (this.checkpointBuilds.get(filePath) === build2) this.checkpointBuilds.delete(filePath);
132654
+ });
132655
+ this.checkpointBuilds.set(filePath, build2);
132656
+ return build2;
132657
+ }
132491
132658
  };
132492
132659
  var EXCLUDED_SEGMENTS2 = ["/memory/", "/tool-results/"];
132493
132660
  var FileWatcher = class {
@@ -132586,6 +132753,8 @@ function defaultDbPath() {
132586
132753
  }
132587
132754
  var ConversationScanner = class {
132588
132755
  metadataCache = /* @__PURE__ */ new Map();
132756
+ // Parsed conversations plus (persistent claude-code entries only) the resume
132757
+ // point that lets refreshFile extend them in place when the file grows.
132589
132758
  conversationLRU;
132590
132759
  // session_id is NOT unique, so this maps a sessionId to every active meta that
132591
132760
  // carries it. Resolution picks deterministically (newest timestamp, then path
@@ -132617,7 +132786,9 @@ var ConversationScanner = class {
132617
132786
  // can't hit a closed DB (the watch-mode half of Bug #4).
132618
132787
  inFlightReconcile = null;
132619
132788
  constructor(options) {
132620
- this.conversationLRU = new LRUCache(options?.conversationCacheSize ?? 5);
132789
+ this.conversationLRU = new LRUCache(
132790
+ options?.conversationCacheSize ?? 5
132791
+ );
132621
132792
  if (options?.persistent === false) {
132622
132793
  this.dbPath = null;
132623
132794
  this.sidecarEnabled = false;
@@ -132874,7 +133045,7 @@ var ConversationScanner = class {
132874
133045
  const cached3 = this.conversationLRU.get(id);
132875
133046
  if (cached3) {
132876
133047
  log8.debug({ id }, "getConversation: cache hit");
132877
- return cached3;
133048
+ return cached3.conversation;
132878
133049
  }
132879
133050
  const meta3 = this.persistent ? this.engine().getByIdOrSession(id) : this.metadataCache.get(id) ?? this.resolveSessionId(id);
132880
133051
  if (!meta3) {
@@ -132883,9 +133054,14 @@ var ConversationScanner = class {
132883
133054
  }
132884
133055
  log8.debug({ id, filePath: meta3.filePath }, "getConversation: cache miss, parsing");
132885
133056
  try {
133057
+ if (this.persistent && meta3.provider !== CODEX_CLI_PROVIDER) {
133058
+ const parsed = await parseConversationResumable(meta3.filePath, meta3.account);
133059
+ if (parsed) this.conversationLRU.set(id, parsed);
133060
+ return parsed?.conversation ?? null;
133061
+ }
132886
133062
  const conversation = meta3.provider === CODEX_CLI_PROVIDER ? await parseCodexConversation(meta3.filePath, meta3.account) : await parseConversation(meta3.filePath, meta3.account);
132887
133063
  if (conversation) {
132888
- this.conversationLRU.set(id, conversation);
133064
+ this.conversationLRU.set(id, { conversation });
132889
133065
  }
132890
133066
  return conversation;
132891
133067
  } catch (err) {
@@ -132957,20 +133133,30 @@ var ConversationScanner = class {
132957
133133
  // not seen before. Returns the fresh ConversationMeta, or null when the file
132958
133134
  // no longer parses (missing/empty) — in which case any prior entry for it is
132959
133135
  // dropped from all indexes.
132960
- async refreshFile(filePath, account) {
133136
+ //
133137
+ // Single-flighted per path: concurrent callers (stacked client retries, a
133138
+ // watcher tick racing a caller) await the one in-flight refresh instead of
133139
+ // each re-reading the file.
133140
+ refreshesInFlight = /* @__PURE__ */ new Map();
133141
+ refreshFile(filePath, account) {
133142
+ const inFlight = this.refreshesInFlight.get(filePath);
133143
+ if (inFlight) return inFlight;
133144
+ const refresh = this.doRefreshFile(filePath, account).finally(() => {
133145
+ if (this.refreshesInFlight.get(filePath) === refresh) {
133146
+ this.refreshesInFlight.delete(filePath);
133147
+ }
133148
+ });
133149
+ this.refreshesInFlight.set(filePath, refresh);
133150
+ return refresh;
133151
+ }
133152
+ async doRefreshFile(filePath, account) {
132961
133153
  const log8 = getLogger2();
132962
133154
  if (this.persistent) {
132963
133155
  const engine = this.engine();
132964
133156
  const previous2 = engine.getByIdOrSession(filePath);
132965
133157
  const resolvedAccount2 = account ?? previous2?.account ?? "default";
132966
- const evict2 = (m2) => {
132967
- if (!m2) return;
132968
- this.conversationLRU.delete(m2.id);
132969
- this.conversationLRU.delete(m2.sessionId);
132970
- };
132971
- evict2(previous2);
132972
133158
  const provider = await this.resolveProviderForFile(filePath, previous2);
132973
- const meta22 = await engine.indexFile(
133159
+ const { meta: meta22, change } = await engine.indexFile(
132974
133160
  filePath,
132975
133161
  resolvedAccount2,
132976
133162
  this.lastTier.name,
@@ -132979,8 +133165,19 @@ var ConversationScanner = class {
132979
133165
  false,
132980
133166
  provider
132981
133167
  );
132982
- evict2(meta22);
132983
- log8.debug({ filePath, kept: !!meta22 }, "refreshFile: updated persistent index");
133168
+ const cacheKeys = /* @__PURE__ */ new Set();
133169
+ for (const m2 of [previous2, meta22]) {
133170
+ if (m2) {
133171
+ cacheKeys.add(m2.id);
133172
+ cacheKeys.add(m2.sessionId);
133173
+ }
133174
+ }
133175
+ if (!meta22 || change === "reindex" || change === "vanished") {
133176
+ for (const key of cacheKeys) this.conversationLRU.delete(key);
133177
+ } else if (change === "appended") {
133178
+ await this.extendCachedConversations(cacheKeys, filePath, meta22.account);
133179
+ }
133180
+ log8.debug({ filePath, change, kept: !!meta22 }, "refreshFile: updated persistent index");
132984
133181
  return meta22;
132985
133182
  }
132986
133183
  const previous = this.metadataCache.get(filePath);
@@ -133024,6 +133221,39 @@ var ConversationScanner = class {
133024
133221
  );
133025
133222
  return meta3;
133026
133223
  }
133224
+ // Advance every cached parse of an appended file by folding only the new
133225
+ // bytes through the conversation reducer — the in-memory analogue of the
133226
+ // persisted metadata fold. Entries without resume state (Codex) and entries
133227
+ // whose extension fails are evicted so the next read re-parses from scratch.
133228
+ async extendCachedConversations(cacheKeys, filePath, account) {
133229
+ const wrappers = /* @__PURE__ */ new Map();
133230
+ for (const key of cacheKeys) {
133231
+ const wrapper = this.conversationLRU.get(key);
133232
+ if (!wrapper) continue;
133233
+ const keys = wrappers.get(wrapper) ?? [];
133234
+ keys.push(key);
133235
+ wrappers.set(wrapper, keys);
133236
+ }
133237
+ for (const [wrapper, keys] of wrappers) {
133238
+ if (!wrapper.resume) {
133239
+ for (const key of keys) this.conversationLRU.delete(key);
133240
+ continue;
133241
+ }
133242
+ try {
133243
+ const extended = await extendConversation(
133244
+ wrapper.conversation,
133245
+ wrapper.resume,
133246
+ filePath,
133247
+ account
133248
+ );
133249
+ wrapper.conversation = extended.conversation;
133250
+ wrapper.resume = extended.resume;
133251
+ } catch (err) {
133252
+ getLogger2().warn({ filePath, err }, "refreshFile: cache extension failed, evicting");
133253
+ for (const key of keys) this.conversationLRU.delete(key);
133254
+ }
133255
+ }
133256
+ }
133027
133257
  getMetadataCache() {
133028
133258
  if (this.persistent) {
133029
133259
  const map2 = /* @__PURE__ */ new Map();
@@ -133289,11 +133519,11 @@ async function search(query, options, scanner) {
133289
133519
 
133290
133520
  // src/server.ts
133291
133521
  var import_events3 = require("events");
133292
- var import_fs24 = require("fs");
133293
- var import_promises15 = require("fs/promises");
133522
+ var import_fs25 = require("fs");
133523
+ var import_promises17 = require("fs/promises");
133294
133524
  var import_http = require("http");
133295
133525
  var import_os10 = require("os");
133296
- var import_path21 = require("path");
133526
+ var import_path22 = require("path");
133297
133527
  var import_readline4 = require("readline");
133298
133528
 
133299
133529
  // src/agent/agent-client.ts
@@ -133382,7 +133612,7 @@ function readAgentConfig(env = process.env) {
133382
133612
  }
133383
133613
 
133384
133614
  // src/agent/conversation-writer.ts
133385
- var import_promises8 = require("fs/promises");
133615
+ var import_promises10 = require("fs/promises");
133386
133616
  var import_node_path6 = require("path");
133387
133617
  function createConversationWriter(opts) {
133388
133618
  const { baseDir } = opts;
@@ -133392,7 +133622,7 @@ function createConversationWriter(opts) {
133392
133622
  throw new Error("ConversationWriter: refusing to write empty assistant turn");
133393
133623
  }
133394
133624
  const file2 = (0, import_node_path6.join)(baseDir, `${args.sessionId}.jsonl`);
133395
- await (0, import_promises8.mkdir)((0, import_node_path6.dirname)(file2), { recursive: true });
133625
+ await (0, import_promises10.mkdir)((0, import_node_path6.dirname)(file2), { recursive: true });
133396
133626
  const record2 = {
133397
133627
  role: "assistant",
133398
133628
  turnId: args.turnId,
@@ -133402,7 +133632,7 @@ function createConversationWriter(opts) {
133402
133632
  };
133403
133633
  const line = `${JSON.stringify(record2)}
133404
133634
  `;
133405
- await (0, import_promises8.appendFile)(file2, line, { encoding: "utf8" });
133635
+ await (0, import_promises10.appendFile)(file2, line, { encoding: "utf8" });
133406
133636
  }
133407
133637
  };
133408
133638
  }
@@ -136383,8 +136613,8 @@ var createHonoApp = (deps, upgradeWebSocket) => {
136383
136613
  init_auth();
136384
136614
 
136385
136615
  // src/browse.ts
136386
- var import_promises9 = require("fs/promises");
136387
- var import_path10 = require("path");
136616
+ var import_promises11 = require("fs/promises");
136617
+ var import_path11 = require("path");
136388
136618
  var BrowsePathNotFoundError = class extends Error {
136389
136619
  constructor(message) {
136390
136620
  super(message);
@@ -136392,20 +136622,20 @@ var BrowsePathNotFoundError = class extends Error {
136392
136622
  }
136393
136623
  };
136394
136624
  async function resolveBrowsePath(browseRoot, relativePath) {
136395
- const normalizedRoot = (0, import_path10.resolve)(browseRoot);
136625
+ const normalizedRoot = (0, import_path11.resolve)(browseRoot);
136396
136626
  let sanitized;
136397
136627
  if (process.platform !== "win32" && relativePath.startsWith("/") && relativePath.length > 1 && relativePath.includes("/", 1)) {
136398
136628
  sanitized = relativePath;
136399
136629
  } else {
136400
136630
  sanitized = relativePath.replace(/^[/\\]+/, "");
136401
136631
  }
136402
- const target = sanitized ? (0, import_path10.resolve)(normalizedRoot, sanitized) : normalizedRoot;
136403
- const rootPrefix = normalizedRoot.endsWith(import_path10.sep) ? normalizedRoot : `${normalizedRoot}${import_path10.sep}`;
136632
+ const target = sanitized ? (0, import_path11.resolve)(normalizedRoot, sanitized) : normalizedRoot;
136633
+ const rootPrefix = normalizedRoot.endsWith(import_path11.sep) ? normalizedRoot : `${normalizedRoot}${import_path11.sep}`;
136404
136634
  if (!target.startsWith(rootPrefix) && target !== normalizedRoot) {
136405
136635
  throw new Error("Path outside browse root");
136406
136636
  }
136407
136637
  try {
136408
- await (0, import_promises9.realpath)(target);
136638
+ await (0, import_promises11.realpath)(target);
136409
136639
  } catch (err) {
136410
136640
  if (err?.code === "ENOENT") {
136411
136641
  throw new BrowsePathNotFoundError(`Path not found: ${target}`);
@@ -136415,37 +136645,37 @@ async function resolveBrowsePath(browseRoot, relativePath) {
136415
136645
  return target;
136416
136646
  }
136417
136647
  async function listDirectories(absolutePath) {
136418
- const entries = await (0, import_promises9.readdir)(absolutePath, { withFileTypes: true });
136648
+ const entries = await (0, import_promises11.readdir)(absolutePath, { withFileTypes: true });
136419
136649
  return entries.filter((e) => e.isDirectory()).map((e) => ({ name: e.name })).sort((a, b2) => a.name.localeCompare(b2.name));
136420
136650
  }
136421
136651
  async function createDirectory(parentAbsolutePath, name) {
136422
136652
  if (name.includes("/") || name.includes("\\") || name === ".." || name === ".") {
136423
136653
  throw new Error("Invalid directory name");
136424
136654
  }
136425
- const target = (0, import_path10.join)(parentAbsolutePath, name);
136655
+ const target = (0, import_path11.join)(parentAbsolutePath, name);
136426
136656
  try {
136427
- const s3 = await (0, import_promises9.stat)(target);
136657
+ const s3 = await (0, import_promises11.stat)(target);
136428
136658
  if (s3.isDirectory()) throw new Error("Directory already exists");
136429
136659
  } catch (err) {
136430
136660
  if (err.code !== "ENOENT") throw err;
136431
136661
  }
136432
- await (0, import_promises9.mkdir)(target);
136662
+ await (0, import_promises11.mkdir)(target);
136433
136663
  return target;
136434
136664
  }
136435
136665
 
136436
136666
  // src/conversation-cache.ts
136437
136667
  var import_better_sqlite32 = __toESM(require("better-sqlite3"), 1);
136438
- var import_fs16 = require("fs");
136439
- var import_path12 = require("path");
136668
+ var import_fs17 = require("fs");
136669
+ var import_path13 = require("path");
136440
136670
 
136441
136671
  // src/db/sqlite-migrate.ts
136442
- var import_fs14 = require("fs");
136443
- var import_path11 = require("path");
136672
+ var import_fs15 = require("fs");
136673
+ var import_path12 = require("path");
136444
136674
  var import_url6 = require("url");
136445
136675
  var import_meta = {};
136446
136676
  function getMigrationsDir() {
136447
136677
  if (typeof import_meta !== "undefined" && import_meta.url) {
136448
- return (0, import_path11.dirname)((0, import_url6.fileURLToPath)(import_meta.url));
136678
+ return (0, import_path12.dirname)((0, import_url6.fileURLToPath)(import_meta.url));
136449
136679
  }
136450
136680
  return __dirname;
136451
136681
  }
@@ -136457,8 +136687,8 @@ CREATE TABLE IF NOT EXISTS schema_migrations (
136457
136687
  `;
136458
136688
  function runSqliteMigrations(db, migrationsDir) {
136459
136689
  db.exec(SCHEMA_MIGRATIONS_SQL);
136460
- const dir = migrationsDir ?? (0, import_path11.join)(getMigrationsDir(), "migrations");
136461
- const files = (0, import_fs14.readdirSync)(dir).filter((f2) => f2.endsWith(".sql")).sort();
136690
+ const dir = migrationsDir ?? (0, import_path12.join)(getMigrationsDir(), "migrations");
136691
+ const files = (0, import_fs15.readdirSync)(dir).filter((f2) => f2.endsWith(".sql")).sort();
136462
136692
  const appliedRows = db.prepare("SELECT id FROM schema_migrations").all();
136463
136693
  const appliedSet = new Set(appliedRows.map((r) => r.id));
136464
136694
  const recordApplied = db.prepare("INSERT INTO schema_migrations (id, applied_at) VALUES (?, ?)");
@@ -136469,7 +136699,7 @@ function runSqliteMigrations(db, migrationsDir) {
136469
136699
  skipped.push(file2);
136470
136700
  continue;
136471
136701
  }
136472
- const sql = (0, import_fs14.readFileSync)((0, import_path11.join)(dir, file2), "utf-8");
136702
+ const sql = (0, import_fs15.readFileSync)((0, import_path12.join)(dir, file2), "utf-8");
136473
136703
  const tx = db.transaction(() => {
136474
136704
  db.exec(sql);
136475
136705
  recordApplied.run(file2, (/* @__PURE__ */ new Date()).toISOString());
@@ -136494,7 +136724,7 @@ function isProviderResumable(_provider, availabilityResumable) {
136494
136724
  }
136495
136725
 
136496
136726
  // src/services/conversations/isAgentConversation.ts
136497
- var import_fs15 = require("fs");
136727
+ var import_fs16 = require("fs");
136498
136728
  var DEFAULT_AGENT_ENTRYPOINTS = /* @__PURE__ */ new Set(["sdk-cli", "claude-vscode"]);
136499
136729
  var CHUNK_BYTES = 64 * 1024;
136500
136730
  var ENTRYPOINT_PROBE = `"entrypoint":`;
@@ -136516,12 +136746,12 @@ function isAgentFile(filePath, entrypoints = DEFAULT_AGENT_ENTRYPOINTS) {
136516
136746
  if (cached3 !== void 0) return cached3;
136517
136747
  let fd;
136518
136748
  try {
136519
- fd = (0, import_fs15.openSync)(filePath, "r");
136749
+ fd = (0, import_fs16.openSync)(filePath, "r");
136520
136750
  } catch {
136521
136751
  return false;
136522
136752
  }
136523
136753
  try {
136524
- const fileSize = (0, import_fs15.statSync)(filePath).size;
136754
+ const fileSize = (0, import_fs16.statSync)(filePath).size;
136525
136755
  if (fileSize === 0) {
136526
136756
  fileDecisionCache.set(key, false);
136527
136757
  return false;
@@ -136532,7 +136762,7 @@ function isAgentFile(filePath, entrypoints = DEFAULT_AGENT_ENTRYPOINTS) {
136532
136762
  let carry = "";
136533
136763
  while (offset < fileSize) {
136534
136764
  const toRead = Math.min(CHUNK_BYTES, fileSize - offset);
136535
- const got = (0, import_fs15.readSync)(fd, buf, 0, toRead, offset);
136765
+ const got = (0, import_fs16.readSync)(fd, buf, 0, toRead, offset);
136536
136766
  if (got <= 0) break;
136537
136767
  const chunk = carry + buf.toString("utf8", 0, got);
136538
136768
  for (const marker of markers) {
@@ -136553,7 +136783,7 @@ function isAgentFile(filePath, entrypoints = DEFAULT_AGENT_ENTRYPOINTS) {
136553
136783
  } catch {
136554
136784
  return false;
136555
136785
  } finally {
136556
- (0, import_fs15.closeSync)(fd);
136786
+ (0, import_fs16.closeSync)(fd);
136557
136787
  }
136558
136788
  }
136559
136789
  function parseAgentEntrypointsEnv(raw2) {
@@ -136807,14 +137037,14 @@ var ConversationCache = class _ConversationCache {
136807
137037
  isAgentFileCached(filePath) {
136808
137038
  let s3;
136809
137039
  try {
136810
- s3 = (0, import_fs16.statSync)(filePath);
137040
+ s3 = (0, import_fs17.statSync)(filePath);
136811
137041
  } catch {
136812
137042
  return false;
136813
137043
  }
136814
137044
  return this.classifyAgentFile(filePath, s3.mtimeMs, s3.size);
136815
137045
  }
136816
137046
  static open(dbPath, tailSize = 10, migrationsDir, options) {
136817
- (0, import_fs16.mkdirSync)((0, import_path12.dirname)(dbPath), { recursive: true });
137047
+ (0, import_fs17.mkdirSync)((0, import_path13.dirname)(dbPath), { recursive: true });
136818
137048
  const db = new import_better_sqlite32.default(dbPath);
136819
137049
  db.pragma("journal_mode = WAL");
136820
137050
  db.pragma("foreign_keys = ON");
@@ -136995,7 +137225,7 @@ var ConversationCache = class _ConversationCache {
136995
137225
  let mtimeMs = null;
136996
137226
  let fileSize = null;
136997
137227
  try {
136998
- const s3 = (0, import_fs16.statSync)(m2.filePath);
137228
+ const s3 = (0, import_fs17.statSync)(m2.filePath);
136999
137229
  mtimeMs = s3.mtimeMs;
137000
137230
  fileSize = s3.size;
137001
137231
  } catch {
@@ -137054,8 +137284,8 @@ var ConversationCache = class _ConversationCache {
137054
137284
  let fileSize;
137055
137285
  let fd;
137056
137286
  try {
137057
- fileSize = (0, import_fs16.statSync)(filePath).size;
137058
- fd = (0, import_fs16.openSync)(filePath, "r");
137287
+ fileSize = (0, import_fs17.statSync)(filePath).size;
137288
+ fd = (0, import_fs17.openSync)(filePath, "r");
137059
137289
  } catch {
137060
137290
  return false;
137061
137291
  }
@@ -137068,7 +137298,7 @@ var ConversationCache = class _ConversationCache {
137068
137298
  while (pos > 0 && lines.length < this.tailSize * 4) {
137069
137299
  const toRead = Math.min(CHUNK, pos);
137070
137300
  pos -= toRead;
137071
- (0, import_fs16.readSync)(fd, buf, 0, toRead, pos);
137301
+ (0, import_fs17.readSync)(fd, buf, 0, toRead, pos);
137072
137302
  const chunk = buf.subarray(0, toRead).toString("utf8");
137073
137303
  const combined = chunk + partial2;
137074
137304
  const parts = combined.split("\n");
@@ -137079,7 +137309,7 @@ var ConversationCache = class _ConversationCache {
137079
137309
  }
137080
137310
  if (partial2) lines.push(partial2);
137081
137311
  } finally {
137082
- (0, import_fs16.closeSync)(fd);
137312
+ (0, import_fs17.closeSync)(fd);
137083
137313
  }
137084
137314
  const msgs = [];
137085
137315
  for (let i = 0; i < lines.length && msgs.length < this.tailSize; i++) {
@@ -137281,7 +137511,7 @@ var ConversationCache = class _ConversationCache {
137281
137511
  * `handleGetConversation` can still serve the cached tail even when the
137282
137512
  * JSONL has been deleted.
137283
137513
  */
137284
- pruneGhostFiles(exists = import_fs16.existsSync) {
137514
+ pruneGhostFiles(exists = import_fs17.existsSync) {
137285
137515
  const rows = this.stmts.allFilePaths.all();
137286
137516
  const ghosts = [];
137287
137517
  const prune = this.db.transaction((ids) => {
@@ -137336,7 +137566,7 @@ var ConversationCache = class _ConversationCache {
137336
137566
  * Returns the removed IDs.
137337
137567
  */
137338
137568
  reconcileDeletions(livePaths, opts) {
137339
- const exists = opts?.exists ?? import_fs16.existsSync;
137569
+ const exists = opts?.exists ?? import_fs17.existsSync;
137340
137570
  const rows = this.stmts.allFilePaths.all();
137341
137571
  const removed = [];
137342
137572
  const drop = this.db.transaction((ids) => {
@@ -137394,13 +137624,13 @@ function getDbConfig() {
137394
137624
  }
137395
137625
 
137396
137626
  // src/db/migrations.ts
137397
- var import_fs17 = require("fs");
137398
- var import_path13 = require("path");
137627
+ var import_fs18 = require("fs");
137628
+ var import_path14 = require("path");
137399
137629
  var import_url7 = require("url");
137400
137630
  var import_meta2 = {};
137401
137631
  function getMigrationsDir2() {
137402
137632
  if (import_meta2.url) {
137403
- return (0, import_path13.dirname)((0, import_url7.fileURLToPath)(import_meta2.url));
137633
+ return (0, import_path14.dirname)((0, import_url7.fileURLToPath)(import_meta2.url));
137404
137634
  }
137405
137635
  return __dirname;
137406
137636
  }
@@ -137416,11 +137646,11 @@ async function runMigrations2(pool2, migrationsDir) {
137416
137646
  "SELECT name FROM _migrations ORDER BY name"
137417
137647
  );
137418
137648
  const appliedSet = new Set(applied.map((r) => r.name));
137419
- const dir = migrationsDir ?? (0, import_path13.join)(getMigrationsDir2(), "pg-migrations");
137420
- const files = (0, import_fs17.readdirSync)(dir).filter((f2) => f2.endsWith(".sql")).sort();
137649
+ const dir = migrationsDir ?? (0, import_path14.join)(getMigrationsDir2(), "pg-migrations");
137650
+ const files = (0, import_fs18.readdirSync)(dir).filter((f2) => f2.endsWith(".sql")).sort();
137421
137651
  for (const file2 of files) {
137422
137652
  if (appliedSet.has(file2)) continue;
137423
- const sql = (0, import_fs17.readFileSync)((0, import_path13.join)(dir, file2), "utf-8");
137653
+ const sql = (0, import_fs18.readFileSync)((0, import_path14.join)(dir, file2), "utf-8");
137424
137654
  await pool2.query(sql);
137425
137655
  await pool2.query("INSERT INTO _migrations (name) VALUES ($1)", [file2]);
137426
137656
  }
@@ -137655,23 +137885,23 @@ async function recordUpload(pool2, instanceId, row) {
137655
137885
  }
137656
137886
 
137657
137887
  // src/handlers/handleListProjects.ts
137658
- var import_fs18 = require("fs");
137888
+ var import_fs19 = require("fs");
137659
137889
  var import_os7 = require("os");
137660
- var import_path14 = require("path");
137890
+ var import_path15 = require("path");
137661
137891
  function decodeProjectPath(dirName) {
137662
137892
  return dirName.replace(/-/g, "/");
137663
137893
  }
137664
137894
  function handleListProjects(url2, res) {
137665
137895
  const limit = Math.max(1, parseInt(url2.searchParams.get("limit") ?? "50", 10) || 50);
137666
137896
  const offset = Math.max(0, parseInt(url2.searchParams.get("offset") ?? "0", 10) || 0);
137667
- const projectsDir = (0, import_path14.join)((0, import_os7.homedir)(), ".claude", "projects");
137897
+ const projectsDir = (0, import_path15.join)((0, import_os7.homedir)(), ".claude", "projects");
137668
137898
  let entries;
137669
137899
  try {
137670
- entries = (0, import_fs18.readdirSync)(projectsDir).map((dirName) => {
137671
- const fullPath = (0, import_path14.join)(projectsDir, dirName);
137900
+ entries = (0, import_fs19.readdirSync)(projectsDir).map((dirName) => {
137901
+ const fullPath = (0, import_path15.join)(projectsDir, dirName);
137672
137902
  let mtime = 0;
137673
137903
  try {
137674
- mtime = (0, import_fs18.statSync)(fullPath).mtimeMs;
137904
+ mtime = (0, import_fs19.statSync)(fullPath).mtimeMs;
137675
137905
  } catch {
137676
137906
  }
137677
137907
  const path2 = decodeProjectPath(dirName);
@@ -137690,20 +137920,20 @@ function handleListProjects(url2, res) {
137690
137920
  }
137691
137921
 
137692
137922
  // src/live-session-manager.ts
137693
- var import_path18 = require("path");
137923
+ var import_path19 = require("path");
137694
137924
 
137695
137925
  // src/codex-pty-runner.ts
137696
137926
  var import_headless = __toESM(require_xterm_headless(), 1);
137697
137927
  var import_crypto6 = require("crypto");
137698
- var import_fs20 = require("fs");
137699
- var import_path16 = require("path");
137928
+ var import_fs21 = require("fs");
137929
+ var import_path17 = require("path");
137700
137930
  init_logger();
137701
137931
 
137702
137932
  // src/platform.ts
137703
137933
  var import_child_process = require("child_process");
137704
- var import_fs19 = require("fs");
137934
+ var import_fs20 = require("fs");
137705
137935
  var import_os8 = require("os");
137706
- var import_path15 = require("path");
137936
+ var import_path16 = require("path");
137707
137937
  var isWindows2 = (0, import_os8.platform)() === "win32";
137708
137938
  var _claudeExe;
137709
137939
  function resolveClaudeExe() {
@@ -137722,16 +137952,16 @@ function resolveClaudeExe() {
137722
137952
  } catch {
137723
137953
  }
137724
137954
  const candidates = [
137725
- (0, import_path15.join)((0, import_os8.homedir)(), ".local", "bin", "claude.exe"),
137726
- (0, import_path15.join)(
137727
- process.env.LOCALAPPDATA ?? (0, import_path15.join)((0, import_os8.homedir)(), "AppData", "Local"),
137955
+ (0, import_path16.join)((0, import_os8.homedir)(), ".local", "bin", "claude.exe"),
137956
+ (0, import_path16.join)(
137957
+ process.env.LOCALAPPDATA ?? (0, import_path16.join)((0, import_os8.homedir)(), "AppData", "Local"),
137728
137958
  "Microsoft",
137729
137959
  "WindowsApps",
137730
137960
  "claude.exe"
137731
137961
  )
137732
137962
  ];
137733
137963
  for (const p2 of candidates) {
137734
- if ((0, import_fs19.existsSync)(p2)) {
137964
+ if ((0, import_fs20.existsSync)(p2)) {
137735
137965
  _claudeExe = p2;
137736
137966
  return _claudeExe;
137737
137967
  }
@@ -137742,7 +137972,7 @@ function resolveClaudeExe() {
137742
137972
  encoding: "utf-8",
137743
137973
  timeout: 3e3
137744
137974
  }).trim().split("\n")[0].trim();
137745
- if (found && (0, import_fs19.existsSync)(found)) {
137975
+ if (found && (0, import_fs20.existsSync)(found)) {
137746
137976
  _claudeExe = found;
137747
137977
  return _claudeExe;
137748
137978
  }
@@ -137751,10 +137981,10 @@ function resolveClaudeExe() {
137751
137981
  const candidates = [
137752
137982
  "/opt/homebrew/bin/claude",
137753
137983
  "/usr/local/bin/claude",
137754
- (0, import_path15.join)((0, import_os8.homedir)(), ".local", "bin", "claude")
137984
+ (0, import_path16.join)((0, import_os8.homedir)(), ".local", "bin", "claude")
137755
137985
  ];
137756
137986
  for (const p2 of candidates) {
137757
- if ((0, import_fs19.existsSync)(p2)) {
137987
+ if ((0, import_fs20.existsSync)(p2)) {
137758
137988
  _claudeExe = p2;
137759
137989
  return _claudeExe;
137760
137990
  }
@@ -137780,16 +138010,16 @@ function resolveCodexExe() {
137780
138010
  } catch {
137781
138011
  }
137782
138012
  const candidates = [
137783
- (0, import_path15.join)((0, import_os8.homedir)(), ".local", "bin", "codex.exe"),
137784
- (0, import_path15.join)(
137785
- process.env.LOCALAPPDATA ?? (0, import_path15.join)((0, import_os8.homedir)(), "AppData", "Local"),
138013
+ (0, import_path16.join)((0, import_os8.homedir)(), ".local", "bin", "codex.exe"),
138014
+ (0, import_path16.join)(
138015
+ process.env.LOCALAPPDATA ?? (0, import_path16.join)((0, import_os8.homedir)(), "AppData", "Local"),
137786
138016
  "Microsoft",
137787
138017
  "WindowsApps",
137788
138018
  "codex.exe"
137789
138019
  )
137790
138020
  ];
137791
138021
  for (const p2 of candidates) {
137792
- if ((0, import_fs19.existsSync)(p2)) {
138022
+ if ((0, import_fs20.existsSync)(p2)) {
137793
138023
  _codexExe = p2;
137794
138024
  return _codexExe;
137795
138025
  }
@@ -137800,7 +138030,7 @@ function resolveCodexExe() {
137800
138030
  encoding: "utf-8",
137801
138031
  timeout: 3e3
137802
138032
  }).trim().split("\n")[0].trim();
137803
- if (found && (0, import_fs19.existsSync)(found)) {
138033
+ if (found && (0, import_fs20.existsSync)(found)) {
137804
138034
  _codexExe = found;
137805
138035
  return _codexExe;
137806
138036
  }
@@ -137809,10 +138039,10 @@ function resolveCodexExe() {
137809
138039
  const candidates = [
137810
138040
  "/opt/homebrew/bin/codex",
137811
138041
  "/usr/local/bin/codex",
137812
- (0, import_path15.join)((0, import_os8.homedir)(), ".local", "bin", "codex")
138042
+ (0, import_path16.join)((0, import_os8.homedir)(), ".local", "bin", "codex")
137813
138043
  ];
137814
138044
  for (const p2 of candidates) {
137815
- if ((0, import_fs19.existsSync)(p2)) {
138045
+ if ((0, import_fs20.existsSync)(p2)) {
137816
138046
  _codexExe = p2;
137817
138047
  return _codexExe;
137818
138048
  }
@@ -137905,7 +138135,7 @@ var CodexPtyRunner = class {
137905
138135
  }
137906
138136
  async doStart(sessionId, options) {
137907
138137
  const nodePty = await loadPty();
137908
- const projectName = options.projectName ?? (0, import_path16.basename)(options.projectPath);
138138
+ const projectName = options.projectName ?? (0, import_path17.basename)(options.projectPath);
137909
138139
  const proc = nodePty.spawn(
137910
138140
  resolveCodexExe(),
137911
138141
  ["resume", sessionId, "--cd", options.projectPath, "--no-alt-screen"],
@@ -137950,7 +138180,7 @@ var CodexPtyRunner = class {
137950
138180
  async startFresh(options) {
137951
138181
  const nodePty = await loadPty();
137952
138182
  const sessionId = (0, import_crypto6.randomUUID)();
137953
- const projectName = options.projectName ?? (0, import_path16.basename)(options.projectPath);
138183
+ const projectName = options.projectName ?? (0, import_path17.basename)(options.projectPath);
137954
138184
  const args = ["--cd", options.projectPath, "--no-alt-screen"];
137955
138185
  if (options.systemPrompt) {
137956
138186
  args.push(options.systemPrompt);
@@ -138242,7 +138472,7 @@ var CodexPtyRunner = class {
138242
138472
  session.status = "idle";
138243
138473
  const elapsedMs = session.completedAt.getTime() - session.startedAt.getTime();
138244
138474
  if (exitCode !== 0 && elapsedMs < 2e3 && session.lastOutput === "") {
138245
- if (!(0, import_fs20.existsSync)(session.projectPath)) {
138475
+ if (!(0, import_fs21.existsSync)(session.projectPath)) {
138246
138476
  session.failureReason = `Project directory not found: ${session.projectPath}`;
138247
138477
  } else {
138248
138478
  session.failureReason = `Codex process exited immediately (code ${exitCode}).`;
@@ -138279,8 +138509,8 @@ function stripAnsi(str) {
138279
138509
  // src/pty-manager.ts
138280
138510
  var import_headless2 = __toESM(require_xterm_headless(), 1);
138281
138511
  var import_crypto7 = require("crypto");
138282
- var import_fs21 = require("fs");
138283
- var import_path17 = require("path");
138512
+ var import_fs22 = require("fs");
138513
+ var import_path18 = require("path");
138284
138514
  init_logger();
138285
138515
 
138286
138516
  // src/services/questions/detectPermissionGate.ts
@@ -138632,7 +138862,7 @@ var PTYManager = class {
138632
138862
  }
138633
138863
  async doStart(sessionId, options) {
138634
138864
  const nodePty = await loadPty2();
138635
- const projectName = options.projectName ?? (0, import_path17.basename)(options.projectPath);
138865
+ const projectName = options.projectName ?? (0, import_path18.basename)(options.projectPath);
138636
138866
  const proc = nodePty.spawn(
138637
138867
  resolveClaudeExe(),
138638
138868
  [
@@ -138683,7 +138913,7 @@ var PTYManager = class {
138683
138913
  async startFresh(options) {
138684
138914
  const nodePty = await loadPty2();
138685
138915
  const sessionId = (0, import_crypto7.randomUUID)();
138686
- const projectName = options.projectName ?? (0, import_path17.basename)(options.projectPath);
138916
+ const projectName = options.projectName ?? (0, import_path18.basename)(options.projectPath);
138687
138917
  const args = [
138688
138918
  "--permission-mode",
138689
138919
  options.permissionMode ?? "acceptEdits",
@@ -139127,7 +139357,7 @@ var PTYManager = class {
139127
139357
  session.status = "idle";
139128
139358
  const elapsedMs = session.completedAt.getTime() - session.startedAt.getTime();
139129
139359
  if (exitCode !== 0 && elapsedMs < 2e3 && session.lastOutput === "") {
139130
- if (!(0, import_fs21.existsSync)(session.projectPath)) {
139360
+ if (!(0, import_fs22.existsSync)(session.projectPath)) {
139131
139361
  session.failureReason = `Project directory not found: ${session.projectPath}`;
139132
139362
  } else {
139133
139363
  session.failureReason = `Process exited immediately (code ${exitCode}). Check that the Claude binary is installed and accessible.`;
@@ -139255,7 +139485,7 @@ var LiveSessionManager = class {
139255
139485
  const runner = this.runners.get(provider);
139256
139486
  if (runner) return runner;
139257
139487
  const err = new Error(
139258
- `Live ${provider} sessions are not implemented yet for ${(0, import_path18.basename)(projectPath)}`
139488
+ `Live ${provider} sessions are not implemented yet for ${(0, import_path19.basename)(projectPath)}`
139259
139489
  );
139260
139490
  err.statusCode = 501;
139261
139491
  throw err;
@@ -139322,7 +139552,7 @@ var PairTokenStore = class {
139322
139552
  // src/process-discovery.ts
139323
139553
  var import_child_process2 = require("child_process");
139324
139554
  var import_os9 = require("os");
139325
- var import_path19 = require("path");
139555
+ var import_path20 = require("path");
139326
139556
  async function discoverClaudeProcesses() {
139327
139557
  if ((0, import_os9.platform)() === "win32") return discoverWindows();
139328
139558
  return discoverUnix();
@@ -139341,7 +139571,7 @@ async function discoverUnix() {
139341
139571
  return {
139342
139572
  pid,
139343
139573
  projectPath: cwd,
139344
- projectName: (0, import_path19.basename)(cwd),
139574
+ projectName: (0, import_path20.basename)(cwd),
139345
139575
  branch: await readGitBranch2(cwd),
139346
139576
  conversationId,
139347
139577
  startedAt
@@ -139363,7 +139593,7 @@ async function discoverWindows() {
139363
139593
  return {
139364
139594
  pid,
139365
139595
  projectPath: info.cwd,
139366
- projectName: (0, import_path19.basename)(info.cwd),
139596
+ projectName: (0, import_path20.basename)(info.cwd),
139367
139597
  branch: await readGitBranch2(info.cwd),
139368
139598
  conversationId: extractResumeId(info.args),
139369
139599
  startedAt: info.startedAt
@@ -139444,7 +139674,7 @@ async function getProcessInfoWindows(pid) {
139444
139674
  const startedAt = /* @__PURE__ */ new Date(`${year}-${month}-${day}T${hour}:${min}:${sec}`);
139445
139675
  if (Number.isNaN(startedAt.getTime())) return null;
139446
139676
  const exePath = parts[3] ?? "";
139447
- const cwd = exePath ? (0, import_path19.dirname)(exePath) : "";
139677
+ const cwd = exePath ? (0, import_path20.dirname)(exePath) : "";
139448
139678
  return { cwd, args, startedAt };
139449
139679
  } catch {
139450
139680
  return null;
@@ -139486,11 +139716,11 @@ function seal(plaintext, recipientPublicKeyBase64) {
139486
139716
  // node_modules/chokidar/index.js
139487
139717
  var import_node_events2 = require("events");
139488
139718
  var import_node_fs7 = require("fs");
139489
- var import_promises12 = require("fs/promises");
139719
+ var import_promises14 = require("fs/promises");
139490
139720
  var sp2 = __toESM(require("path"), 1);
139491
139721
 
139492
139722
  // node_modules/readdirp/index.js
139493
- var import_promises10 = require("fs/promises");
139723
+ var import_promises12 = require("fs/promises");
139494
139724
  var import_node_path9 = require("path");
139495
139725
  var import_node_stream2 = require("stream");
139496
139726
  var EntryTypes2 = {
@@ -139571,7 +139801,7 @@ var ReaddirpStream2 = class extends import_node_stream2.Readable {
139571
139801
  const { root, type } = opts;
139572
139802
  this._fileFilter = normalizeFilter2(opts.fileFilter);
139573
139803
  this._directoryFilter = normalizeFilter2(opts.directoryFilter);
139574
- const statMethod = opts.lstat ? import_promises10.lstat : import_promises10.stat;
139804
+ const statMethod = opts.lstat ? import_promises12.lstat : import_promises12.stat;
139575
139805
  if (wantBigintFsStats2) {
139576
139806
  this._stat = (path2) => statMethod(path2, { bigint: true });
139577
139807
  } else {
@@ -139642,7 +139872,7 @@ var ReaddirpStream2 = class extends import_node_stream2.Readable {
139642
139872
  async _exploreDir(path2, depth) {
139643
139873
  let files;
139644
139874
  try {
139645
- files = await (0, import_promises10.readdir)(path2, this._rdOptions);
139875
+ files = await (0, import_promises12.readdir)(path2, this._rdOptions);
139646
139876
  } catch (error51) {
139647
139877
  this._onError(error51);
139648
139878
  }
@@ -139650,10 +139880,10 @@ var ReaddirpStream2 = class extends import_node_stream2.Readable {
139650
139880
  }
139651
139881
  async _formatEntry(dirent, path2) {
139652
139882
  let entry;
139653
- const basename11 = this._isDirent ? dirent.name : dirent;
139883
+ const basename12 = this._isDirent ? dirent.name : dirent;
139654
139884
  try {
139655
- const fullPath = (0, import_node_path9.resolve)((0, import_node_path9.join)(path2, basename11));
139656
- entry = { path: (0, import_node_path9.relative)(this._root, fullPath), fullPath, basename: basename11 };
139885
+ const fullPath = (0, import_node_path9.resolve)((0, import_node_path9.join)(path2, basename12));
139886
+ entry = { path: (0, import_node_path9.relative)(this._root, fullPath), fullPath, basename: basename12 };
139657
139887
  entry[this._statsProp] = this._isDirent ? dirent : await this._stat(fullPath);
139658
139888
  } catch (err) {
139659
139889
  this._onError(err);
@@ -139680,8 +139910,8 @@ var ReaddirpStream2 = class extends import_node_stream2.Readable {
139680
139910
  if (stats && stats.isSymbolicLink()) {
139681
139911
  const full = entry.fullPath;
139682
139912
  try {
139683
- const entryRealPath = await (0, import_promises10.realpath)(full);
139684
- const entryRealPathStats = await (0, import_promises10.lstat)(entryRealPath);
139913
+ const entryRealPath = await (0, import_promises12.realpath)(full);
139914
+ const entryRealPathStats = await (0, import_promises12.lstat)(entryRealPath);
139685
139915
  if (entryRealPathStats.isFile()) {
139686
139916
  return "file";
139687
139917
  }
@@ -139724,7 +139954,7 @@ function readdirp2(root, options = {}) {
139724
139954
 
139725
139955
  // node_modules/chokidar/handler.js
139726
139956
  var import_node_fs6 = require("fs");
139727
- var import_promises11 = require("fs/promises");
139957
+ var import_promises13 = require("fs/promises");
139728
139958
  var import_node_os3 = require("os");
139729
139959
  var sp = __toESM(require("path"), 1);
139730
139960
  var STR_DATA2 = "data";
@@ -139751,7 +139981,7 @@ var EVENTS2 = {
139751
139981
  };
139752
139982
  var EV2 = EVENTS2;
139753
139983
  var THROTTLE_MODE_WATCH2 = "watch";
139754
- var statMethods2 = { lstat: import_promises11.lstat, stat: import_promises11.stat };
139984
+ var statMethods2 = { lstat: import_promises13.lstat, stat: import_promises13.stat };
139755
139985
  var KEY_LISTENERS2 = "listeners";
139756
139986
  var KEY_ERR2 = "errHandlers";
139757
139987
  var KEY_RAW2 = "rawEmitters";
@@ -140108,7 +140338,7 @@ var setFsWatchListener2 = (path2, fullPath, options, handlers) => {
140108
140338
  cont.watcherUnusable = true;
140109
140339
  if (isWindows3 && error51.code === "EPERM") {
140110
140340
  try {
140111
- const fd = await (0, import_promises11.open)(path2, "r");
140341
+ const fd = await (0, import_promises13.open)(path2, "r");
140112
140342
  await fd.close();
140113
140343
  broadcastErr(error51);
140114
140344
  } catch (err) {
@@ -140194,9 +140424,9 @@ var NodeFsHandler2 = class {
140194
140424
  _watchWithNodeFs(path2, listener) {
140195
140425
  const opts = this.fsw.options;
140196
140426
  const directory = sp.dirname(path2);
140197
- const basename11 = sp.basename(path2);
140427
+ const basename12 = sp.basename(path2);
140198
140428
  const parent = this.fsw._getWatchedDir(directory);
140199
- parent.add(basename11);
140429
+ parent.add(basename12);
140200
140430
  const absolutePath = sp.resolve(path2);
140201
140431
  const options = {
140202
140432
  persistent: opts.persistent
@@ -140206,7 +140436,7 @@ var NodeFsHandler2 = class {
140206
140436
  let closer;
140207
140437
  if (opts.usePolling) {
140208
140438
  const enableBin = opts.interval !== opts.binaryInterval;
140209
- options.interval = enableBin && isBinaryPath2(basename11) ? opts.binaryInterval : opts.interval;
140439
+ options.interval = enableBin && isBinaryPath2(basename12) ? opts.binaryInterval : opts.interval;
140210
140440
  closer = setFsWatchFileListener2(path2, absolutePath, options, {
140211
140441
  listener,
140212
140442
  rawEmitter: this.fsw._emitRaw
@@ -140229,17 +140459,17 @@ var NodeFsHandler2 = class {
140229
140459
  return;
140230
140460
  }
140231
140461
  const dirname17 = sp.dirname(file2);
140232
- const basename11 = sp.basename(file2);
140462
+ const basename12 = sp.basename(file2);
140233
140463
  const parent = this.fsw._getWatchedDir(dirname17);
140234
140464
  let prevStats = stats;
140235
- if (parent.has(basename11))
140465
+ if (parent.has(basename12))
140236
140466
  return;
140237
140467
  const listener = async (path2, newStats) => {
140238
140468
  if (!this.fsw._throttle(THROTTLE_MODE_WATCH2, file2, 5))
140239
140469
  return;
140240
140470
  if (!newStats || newStats.mtimeMs === 0) {
140241
140471
  try {
140242
- const newStats2 = await (0, import_promises11.stat)(file2);
140472
+ const newStats2 = await (0, import_promises13.stat)(file2);
140243
140473
  if (this.fsw.closed)
140244
140474
  return;
140245
140475
  const at2 = newStats2.atimeMs;
@@ -140257,9 +140487,9 @@ var NodeFsHandler2 = class {
140257
140487
  prevStats = newStats2;
140258
140488
  }
140259
140489
  } catch (error51) {
140260
- this.fsw._remove(dirname17, basename11);
140490
+ this.fsw._remove(dirname17, basename12);
140261
140491
  }
140262
- } else if (parent.has(basename11)) {
140492
+ } else if (parent.has(basename12)) {
140263
140493
  const at2 = newStats.atimeMs;
140264
140494
  const mt2 = newStats.mtimeMs;
140265
140495
  if (!at2 || at2 <= mt2 || mt2 !== prevStats.mtimeMs) {
@@ -140294,7 +140524,7 @@ var NodeFsHandler2 = class {
140294
140524
  this.fsw._incrReadyCount();
140295
140525
  let linkPath;
140296
140526
  try {
140297
- linkPath = await (0, import_promises11.realpath)(path2);
140527
+ linkPath = await (0, import_promises13.realpath)(path2);
140298
140528
  } catch (e) {
140299
140529
  this.fsw._emitReady();
140300
140530
  return true;
@@ -140443,7 +140673,7 @@ var NodeFsHandler2 = class {
140443
140673
  let closer;
140444
140674
  if (stats.isDirectory()) {
140445
140675
  const absPath = sp.resolve(path2);
140446
- const targetPath = follow ? await (0, import_promises11.realpath)(path2) : path2;
140676
+ const targetPath = follow ? await (0, import_promises13.realpath)(path2) : path2;
140447
140677
  if (this.fsw.closed)
140448
140678
  return;
140449
140679
  closer = await this._handleDir(wh.watchPath, stats, initialAdd, depth, target, wh, targetPath);
@@ -140453,7 +140683,7 @@ var NodeFsHandler2 = class {
140453
140683
  this.fsw._symlinkPaths.set(absPath, targetPath);
140454
140684
  }
140455
140685
  } else if (stats.isSymbolicLink()) {
140456
- const targetPath = follow ? await (0, import_promises11.realpath)(path2) : path2;
140686
+ const targetPath = follow ? await (0, import_promises13.realpath)(path2) : path2;
140457
140687
  if (this.fsw.closed)
140458
140688
  return;
140459
140689
  const parent = sp.dirname(wh.watchPath);
@@ -140613,7 +140843,7 @@ var DirEntry2 = class {
140613
140843
  return;
140614
140844
  const dir = this.path;
140615
140845
  try {
140616
- await (0, import_promises12.readdir)(dir);
140846
+ await (0, import_promises14.readdir)(dir);
140617
140847
  } catch (err) {
140618
140848
  if (this._removeWatcher) {
140619
140849
  this._removeWatcher(sp2.dirname(dir), sp2.basename(dir));
@@ -140963,7 +141193,7 @@ var FSWatcher2 = class extends import_node_events2.EventEmitter {
140963
141193
  const fullPath = opts.cwd ? sp2.join(opts.cwd, path2) : path2;
140964
141194
  let stats2;
140965
141195
  try {
140966
- stats2 = await (0, import_promises12.stat)(fullPath);
141196
+ stats2 = await (0, import_promises14.stat)(fullPath);
140967
141197
  } catch (err) {
140968
141198
  }
140969
141199
  if (!stats2 || this.closed)
@@ -141216,8 +141446,8 @@ function watch2(paths, options = {}) {
141216
141446
  var chokidar_default = { watch: watch2, FSWatcher: FSWatcher2 };
141217
141447
 
141218
141448
  // src/services/conversations/conversationWatcher.ts
141219
- var import_fs22 = require("fs");
141220
- var import_promises13 = require("fs/promises");
141449
+ var import_fs23 = require("fs");
141450
+ var import_promises15 = require("fs/promises");
141221
141451
  var ConversationWatcher = class {
141222
141452
  files = /* @__PURE__ */ new Map();
141223
141453
  directories = /* @__PURE__ */ new Map();
@@ -141237,7 +141467,7 @@ var ConversationWatcher = class {
141237
141467
  if (this.files.has(filePath)) return;
141238
141468
  let offset;
141239
141469
  try {
141240
- offset = (0, import_fs22.statSync)(filePath).size;
141470
+ offset = (0, import_fs23.statSync)(filePath).size;
141241
141471
  } catch {
141242
141472
  offset = 0;
141243
141473
  }
@@ -141321,12 +141551,12 @@ var ConversationWatcher = class {
141321
141551
  entry.reading = true;
141322
141552
  try {
141323
141553
  for (; ; ) {
141324
- const st2 = await (0, import_promises13.stat)(filePath);
141554
+ const st2 = await (0, import_promises15.stat)(filePath);
141325
141555
  if (st2.size <= entry.offset) break;
141326
141556
  const readFrom = entry.offset;
141327
141557
  const bytesToRead = st2.size - readFrom;
141328
141558
  const buf = Buffer.alloc(bytesToRead);
141329
- const fh = await (0, import_promises13.open)(filePath, "r");
141559
+ const fh = await (0, import_promises15.open)(filePath, "r");
141330
141560
  try {
141331
141561
  await fh.read(buf, 0, bytesToRead, readFrom);
141332
141562
  } finally {
@@ -141408,14 +141638,14 @@ function findSearchTarget(messages, query) {
141408
141638
  }
141409
141639
 
141410
141640
  // src/services/conversations/pruneAgentConversations.ts
141411
- var import_fs23 = require("fs");
141641
+ var import_fs24 = require("fs");
141412
141642
  function pruneAgentConversations(cache) {
141413
141643
  const db = cache.getDatabase();
141414
141644
  const rows = db.prepare("SELECT id, file_path FROM conversation_meta").all();
141415
141645
  let pruned = 0;
141416
141646
  let missing = 0;
141417
141647
  for (const row of rows) {
141418
- if (!(0, import_fs23.existsSync)(row.file_path)) {
141648
+ if (!(0, import_fs24.existsSync)(row.file_path)) {
141419
141649
  missing += 1;
141420
141650
  continue;
141421
141651
  }
@@ -141775,9 +142005,9 @@ function discoveredToResponse(d, conversationId) {
141775
142005
 
141776
142006
  // src/uploads.ts
141777
142007
  var import_crypto9 = require("crypto");
141778
- var import_promises14 = require("fs/promises");
142008
+ var import_promises16 = require("fs/promises");
141779
142009
  var import_heic_convert = __toESM(require_heic_convert(), 1);
141780
- var import_path20 = require("path");
142010
+ var import_path21 = require("path");
141781
142011
  var UPLOAD_DIR_NAME = ".threadbase-uploads";
141782
142012
  var MAX_BYTES = 25 * 1024 * 1024;
141783
142013
  var HEIC_MIMES = /* @__PURE__ */ new Set(["image/heic", "image/heif"]);
@@ -141810,10 +142040,10 @@ async function saveUploadFile(input) {
141810
142040
  }
141811
142041
  const id = `up_${(0, import_crypto9.randomBytes)(8).toString("hex")}`;
141812
142042
  const safeName = sanitizeFilename(originalName) || `file${MIME_TO_EXT[mimeType] ?? ""}`;
141813
- const dir = (0, import_path20.join)(input.projectPath, UPLOAD_DIR_NAME, input.sessionId);
141814
- await (0, import_promises14.mkdir)(dir, { recursive: true });
141815
- const filePath = (0, import_path20.join)(dir, `${Date.now()}-${id}-${safeName}`);
141816
- await (0, import_promises14.writeFile)(filePath, buffer);
142043
+ const dir = (0, import_path21.join)(input.projectPath, UPLOAD_DIR_NAME, input.sessionId);
142044
+ await (0, import_promises16.mkdir)(dir, { recursive: true });
142045
+ const filePath = (0, import_path21.join)(dir, `${Date.now()}-${id}-${safeName}`);
142046
+ await (0, import_promises16.writeFile)(filePath, buffer);
141817
142047
  return {
141818
142048
  id,
141819
142049
  filePath,
@@ -142197,6 +142427,7 @@ var WSHub = class {
142197
142427
  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.`;
142198
142428
  var DEFAULT_SYSTEM_PROMPT = "When presenting options or choices to the user, limit the options to at most 3.";
142199
142429
  var DEFAULT_PTY_GRACE_PERIOD_MS = 27e4;
142430
+ var REFRESH_TTL_MS = 2e3;
142200
142431
  var START_READY_TIMEOUT_MS = 15e3;
142201
142432
  function parseIncludeAgentsEnv(raw2) {
142202
142433
  if (raw2 === void 0) return false;
@@ -142236,6 +142467,12 @@ var StreamerServer = class {
142236
142467
  // Set by onConversationChanged while a scan is in-flight; getScanner() does
142237
142468
  // a single rescan after the current one completes instead of restarting it.
142238
142469
  scannerStale = false;
142470
+ // Single-flight + TTL guard around scanner.refreshFile (see refreshFileGuarded).
142471
+ // A live file's mtime is always newer than the snapshot, so an unguarded
142472
+ // refresh fires on every request and re-parses the whole file from byte 0.
142473
+ // Keyed by filePath; entries drop on settle + TTL expiry, so the map stays
142474
+ // bounded by the active-file set.
142475
+ refreshInFlight = /* @__PURE__ */ new Map();
142239
142476
  // True only while bindWithRetry is actively retrying. The persistent
142240
142477
  // listener-level 'error' handler demotes EADDRINUSE to debug during this
142241
142478
  // window so the self-healing kickstart-relaunch race doesn't spam warn.
@@ -142313,11 +142550,11 @@ var StreamerServer = class {
142313
142550
  this.disableDb = config2.disableDb ?? false;
142314
142551
  this.scannerPersistenceDisabled = config2.scannerPersistent === false;
142315
142552
  this.scanProfiles = config2.scanProfiles;
142316
- this.codexRoots = config2.codexRoots ?? [(0, import_path21.join)((0, import_os10.homedir)(), ".codex", "sessions")];
142553
+ this.codexRoots = config2.codexRoots ?? [(0, import_path22.join)((0, import_os10.homedir)(), ".codex", "sessions")];
142317
142554
  this.ptyGracePeriodMs = config2.ptyGracePeriodMs ?? DEFAULT_PTY_GRACE_PERIOD_MS;
142318
142555
  this.defaultSystemPrompt = config2.defaultSystemPrompt ?? DEFAULT_SYSTEM_PROMPT;
142319
142556
  this.defaultPermissionMode = config2.defaultPermissionMode ?? loadDefaultPermissionMode() ?? "acceptEdits";
142320
- this.cacheDir = config2.cacheDir ?? loadCacheDir() ?? (0, import_path21.join)((0, import_os10.homedir)(), ".threadbase", "cache");
142557
+ this.cacheDir = config2.cacheDir ?? loadCacheDir() ?? (0, import_path22.join)((0, import_os10.homedir)(), ".threadbase", "cache");
142321
142558
  this.tailSize = config2.tailSize ?? loadTailSize() ?? 10;
142322
142559
  this.directoryDebounceMs = parseDirScanDebounceEnv(process.env.THREADBASE_DIR_SCAN_DEBOUNCE_MS) ?? config2.directoryScanDebounceMs ?? 1e3;
142323
142560
  this.markScannerStaleDebounced = debounce(() => {
@@ -142328,7 +142565,7 @@ var StreamerServer = class {
142328
142565
  this.agentEntrypoints = parseAgentEntrypointsEnv(process.env.THREADBASE_AGENT_ENTRYPOINTS);
142329
142566
  const rawRoot = process.env.THREADBASE_BROWSE_ROOT ?? loadBrowseRoot() ?? config2.browseRoot;
142330
142567
  if (rawRoot) {
142331
- (0, import_promises15.realpath)(rawRoot).then((resolved) => {
142568
+ (0, import_promises17.realpath)(rawRoot).then((resolved) => {
142332
142569
  this.browseRoot = resolved;
142333
142570
  if (this.verbose) this.log.info(`Browse root: ${resolved}`, { browseRoot: resolved });
142334
142571
  }).catch(() => {
@@ -142434,7 +142671,7 @@ var StreamerServer = class {
142434
142671
  if (session.status === "waiting_input" || session.status === "idle") {
142435
142672
  const filePath = this.sessionFileMap.get(session.id);
142436
142673
  if (filePath) {
142437
- this.getScanner().then((scanner) => scanner.refreshFile(filePath)).then((meta3) => {
142674
+ this.getScanner().then((scanner) => this.refreshFileGuarded(scanner, filePath)).then((meta3) => {
142438
142675
  this.log.info("scanner.refreshFile: ok", {
142439
142676
  event: "scanner.refresh",
142440
142677
  sessionId: session.id,
@@ -142484,7 +142721,7 @@ var StreamerServer = class {
142484
142721
  temporalClient,
142485
142722
  taskQueue: agentConfig.temporal.taskQueue
142486
142723
  });
142487
- const conversationsBaseDir = agentConfig.conversationsDir || (0, import_path21.join)((0, import_path21.dirname)(this.cacheDir), "conversations");
142724
+ const conversationsBaseDir = agentConfig.conversationsDir || (0, import_path22.join)((0, import_path22.dirname)(this.cacheDir), "conversations");
142488
142725
  conversationWriter = createConversationWriter({
142489
142726
  baseDir: conversationsBaseDir
142490
142727
  });
@@ -142708,7 +142945,7 @@ var StreamerServer = class {
142708
142945
  });
142709
142946
  try {
142710
142947
  this.cache = ConversationCache.open(
142711
- (0, import_path21.join)(this.cacheDir, "cache.db"),
142948
+ (0, import_path22.join)(this.cacheDir, "cache.db"),
142712
142949
  this.tailSize,
142713
142950
  void 0,
142714
142951
  {
@@ -142734,11 +142971,11 @@ var StreamerServer = class {
142734
142971
  if (this.scanProfiles && this.scanProfiles.length > 0) {
142735
142972
  for (const profile of this.scanProfiles) {
142736
142973
  if (profile.enabled) {
142737
- this.fileWatcher.watchDirectory((0, import_path21.join)(profile.configDir, "projects"));
142974
+ this.fileWatcher.watchDirectory((0, import_path22.join)(profile.configDir, "projects"));
142738
142975
  }
142739
142976
  }
142740
142977
  } else {
142741
- this.fileWatcher.watchDirectory((0, import_path21.join)((0, import_os10.homedir)(), ".claude", "projects"));
142978
+ this.fileWatcher.watchDirectory((0, import_path22.join)((0, import_os10.homedir)(), ".claude", "projects"));
142742
142979
  }
142743
142980
  } catch (err) {
142744
142981
  const message = err instanceof Error ? err.message : String(err);
@@ -142883,6 +143120,34 @@ var StreamerServer = class {
142883
143120
  this.inFlightCacheWrites.delete(guarded);
142884
143121
  });
142885
143122
  }
143123
+ // Single-flight + TTL wrapper for scanner.refreshFile. Both call sites (the
143124
+ // detail-stale branch and the per-turn refresh) route through here so that
143125
+ // N stacked retries on a live, actively-appended file cost one parse, not N:
143126
+ // - a refresh already in flight for the path → await the same promise;
143127
+ // - a refresh that settled within REFRESH_TTL_MS → skip, return null (the
143128
+ // caller keeps serving the current snapshot);
143129
+ // - otherwise start one, cache the promise, and stamp completedAt on settle.
143130
+ // The map is bounded by the active-file set (entries only live while a
143131
+ // refresh is in flight or within its TTL and are overwritten on the next
143132
+ // refresh of the same path).
143133
+ refreshFileGuarded(scanner, filePath) {
143134
+ const existing = this.refreshInFlight.get(filePath);
143135
+ if (existing) {
143136
+ const settled = existing.completedAt > 0;
143137
+ if (!settled) {
143138
+ return existing.promise;
143139
+ }
143140
+ if (Date.now() - existing.completedAt < REFRESH_TTL_MS) {
143141
+ return Promise.resolve(null);
143142
+ }
143143
+ }
143144
+ const entry = { promise: Promise.resolve(null), completedAt: 0 };
143145
+ entry.promise = scanner.refreshFile(filePath).finally(() => {
143146
+ entry.completedAt = Date.now();
143147
+ });
143148
+ this.refreshInFlight.set(filePath, entry);
143149
+ return entry.promise;
143150
+ }
142886
143151
  async close() {
142887
143152
  for (const timer of this.ptyGraceTimers.values()) clearTimeout(timer);
142888
143153
  this.ptyGraceTimers.clear();
@@ -143292,17 +143557,17 @@ var StreamerServer = class {
143292
143557
  return scanner;
143293
143558
  }
143294
143559
  findJsonlPath(uuid3) {
143295
- const projectsDir = (0, import_path21.join)((0, import_os10.homedir)(), ".claude", "projects");
143296
- if (!(0, import_fs24.existsSync)(projectsDir)) return null;
143560
+ const projectsDir = (0, import_path22.join)((0, import_os10.homedir)(), ".claude", "projects");
143561
+ if (!(0, import_fs25.existsSync)(projectsDir)) return null;
143297
143562
  const filename = `${uuid3}.jsonl`;
143298
- for (const dir of (0, import_fs24.readdirSync)(projectsDir)) {
143299
- const fp = (0, import_path21.join)(projectsDir, dir, filename);
143300
- if ((0, import_fs24.existsSync)(fp)) return fp;
143301
- const projectDir = (0, import_path21.join)(projectsDir, dir);
143563
+ for (const dir of (0, import_fs25.readdirSync)(projectsDir)) {
143564
+ const fp = (0, import_path22.join)(projectsDir, dir, filename);
143565
+ if ((0, import_fs25.existsSync)(fp)) return fp;
143566
+ const projectDir = (0, import_path22.join)(projectsDir, dir);
143302
143567
  try {
143303
- for (const sub of (0, import_fs24.readdirSync)(projectDir)) {
143304
- const subagentPath = (0, import_path21.join)(projectDir, sub, "subagents", filename);
143305
- if ((0, import_fs24.existsSync)(subagentPath)) return subagentPath;
143568
+ for (const sub of (0, import_fs25.readdirSync)(projectDir)) {
143569
+ const subagentPath = (0, import_path22.join)(projectDir, sub, "subagents", filename);
143570
+ if ((0, import_fs25.existsSync)(subagentPath)) return subagentPath;
143306
143571
  }
143307
143572
  } catch {
143308
143573
  }
@@ -143311,7 +143576,7 @@ var StreamerServer = class {
143311
143576
  }
143312
143577
  async readCwdFromJsonl(filePath) {
143313
143578
  return new Promise((resolve6) => {
143314
- const rl = (0, import_readline4.createInterface)({ input: (0, import_fs24.createReadStream)(filePath), crlfDelay: Infinity });
143579
+ const rl = (0, import_readline4.createInterface)({ input: (0, import_fs25.createReadStream)(filePath), crlfDelay: Infinity });
143315
143580
  let found = false;
143316
143581
  rl.on("line", (line) => {
143317
143582
  if (found) return;
@@ -143347,10 +143612,22 @@ var StreamerServer = class {
143347
143612
  const scanner = await this.getScanner(true);
143348
143613
  const fromIndex = await scanner.getConversation(uuid3);
143349
143614
  if (fromIndex) {
143615
+ if (this.ptyManager.hasSession(uuid3)) {
143616
+ return fromIndex;
143617
+ }
143350
143618
  if (fromIndex.filePath && this.isConversationSnapshotStale(fromIndex)) {
143351
- const refreshedMeta = await scanner.refreshFile(fromIndex.filePath);
143352
- if (!refreshedMeta) return null;
143353
- return await scanner.getConversation(uuid3) ?? fromIndex;
143619
+ const filePath2 = fromIndex.filePath;
143620
+ this.trackCacheWrite(
143621
+ this.refreshFileGuarded(scanner, filePath2).catch((err) => {
143622
+ this.log.warn("scanner.refreshFile: failed", {
143623
+ event: "scanner.refresh_failed",
143624
+ conversationId: uuid3,
143625
+ filePath: filePath2,
143626
+ trigger: "detail-swr",
143627
+ err
143628
+ });
143629
+ })
143630
+ );
143354
143631
  }
143355
143632
  return fromIndex;
143356
143633
  }
@@ -143368,7 +143645,7 @@ var StreamerServer = class {
143368
143645
  if (!conv.filePath) return false;
143369
143646
  let mtimeMs = null;
143370
143647
  try {
143371
- mtimeMs = (0, import_fs24.statSync)(conv.filePath).mtimeMs;
143648
+ mtimeMs = (0, import_fs25.statSync)(conv.filePath).mtimeMs;
143372
143649
  } catch {
143373
143650
  return false;
143374
143651
  }
@@ -143698,7 +143975,7 @@ var StreamerServer = class {
143698
143975
  handleGetSession(sessionId, res) {
143699
143976
  const session = this.sessionStore.get(sessionId, this.ptyAttachedIds());
143700
143977
  if (session) {
143701
- if (!(0, import_fs24.existsSync)(session.projectPath)) {
143978
+ if (!(0, import_fs25.existsSync)(session.projectPath)) {
143702
143979
  session.failureReason = `Project directory not found: ${session.projectPath}`;
143703
143980
  }
143704
143981
  json2(res, 200, session);
@@ -144094,7 +144371,7 @@ var StreamerServer = class {
144094
144371
  sessionStore: this.sessionStore,
144095
144372
  // biome-ignore lint/style/noNonNullAssertion: agentClient is set when agentConfig.enabled is true
144096
144373
  agentClient: this.agentClient,
144097
- conversationsDir: this.cacheDir ? (0, import_path21.join)((0, import_path21.dirname)(this.cacheDir), "conversations") : "",
144374
+ conversationsDir: this.cacheDir ? (0, import_path22.join)((0, import_path22.dirname)(this.cacheDir), "conversations") : "",
144098
144375
  agentConfig: this.agentConfig
144099
144376
  });
144100
144377
  json2(res, result.status, result.body);
@@ -144235,9 +144512,9 @@ var StreamerServer = class {
144235
144512
  // was passed to Claude via --session-id so the filename matches from the start.
144236
144513
  watchForJsonl(sessionId, projectPath) {
144237
144514
  const encoded = projectPath.replace(/[/\\:.]/g, "-");
144238
- const projectsDir = (0, import_path21.join)((0, import_os10.homedir)(), ".claude", "projects", encoded);
144515
+ const projectsDir = (0, import_path22.join)((0, import_os10.homedir)(), ".claude", "projects", encoded);
144239
144516
  const expectedFile = `${sessionId}.jsonl`;
144240
- const filePath = (0, import_path21.join)(projectsDir, expectedFile);
144517
+ const filePath = (0, import_path22.join)(projectsDir, expectedFile);
144241
144518
  const deadline = Date.now() + 12e4;
144242
144519
  let watcher = null;
144243
144520
  const cleanup = () => {
@@ -144255,12 +144532,12 @@ var StreamerServer = class {
144255
144532
  cleanup();
144256
144533
  return;
144257
144534
  }
144258
- let resolvedFilePath = (0, import_fs24.existsSync)(filePath) ? filePath : null;
144259
- if (!resolvedFilePath && (0, import_fs24.existsSync)(projectsDir)) {
144535
+ let resolvedFilePath = (0, import_fs25.existsSync)(filePath) ? filePath : null;
144536
+ if (!resolvedFilePath && (0, import_fs25.existsSync)(projectsDir)) {
144260
144537
  try {
144261
144538
  const now = Date.now();
144262
- const recent = (0, import_fs24.readdirSync)(projectsDir).filter((f2) => f2.endsWith(".jsonl")).map((f2) => ({ f: f2, mtime: (0, import_fs24.statSync)((0, import_path21.join)(projectsDir, f2)).mtimeMs })).filter(({ mtime }) => now - mtime < 5e3).sort((a, b2) => b2.mtime - a.mtime)[0];
144263
- if (recent) resolvedFilePath = (0, import_path21.join)(projectsDir, recent.f);
144539
+ 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];
144540
+ if (recent) resolvedFilePath = (0, import_path22.join)(projectsDir, recent.f);
144264
144541
  } catch {
144265
144542
  }
144266
144543
  }
@@ -144269,7 +144546,7 @@ var StreamerServer = class {
144269
144546
  this.sessionFileMap.set(sessionId, resolvedFilePath);
144270
144547
  this.fileWatcher.watch(resolvedFilePath);
144271
144548
  try {
144272
- const existing = (0, import_fs24.readFileSync)(resolvedFilePath, "utf8").split("\n").filter(Boolean);
144549
+ const existing = (0, import_fs25.readFileSync)(resolvedFilePath, "utf8").split("\n").filter(Boolean);
144273
144550
  if (existing.length > 0) {
144274
144551
  this.wsHub.broadcast({ type: "conversation_events", sessionId, lines: existing });
144275
144552
  for (const line of existing) {
@@ -144295,7 +144572,7 @@ var StreamerServer = class {
144295
144572
  if (this.sessionFileMap.has(sessionId)) return;
144296
144573
  try {
144297
144574
  require("fs").mkdirSync(projectsDir, { recursive: true });
144298
- watcher = (0, import_fs24.watch)(projectsDir, tryWire);
144575
+ watcher = (0, import_fs25.watch)(projectsDir, tryWire);
144299
144576
  watcher.on("error", cleanup);
144300
144577
  } catch {
144301
144578
  }
@@ -144311,7 +144588,7 @@ var StreamerServer = class {
144311
144588
  watchForCodexRollout(sessionId, projectPath) {
144312
144589
  const deadline = Date.now() + 12e4;
144313
144590
  const now = /* @__PURE__ */ new Date();
144314
- const dateDir = (0, import_path21.join)(
144591
+ const dateDir = (0, import_path22.join)(
144315
144592
  String(now.getFullYear()),
144316
144593
  String(now.getMonth() + 1).padStart(2, "0"),
144317
144594
  String(now.getDate()).padStart(2, "0")
@@ -144324,7 +144601,7 @@ var StreamerServer = class {
144324
144601
  };
144325
144602
  const matchesProjectPath = (candidatePath) => {
144326
144603
  try {
144327
- const firstLine = (0, import_fs24.readFileSync)(candidatePath, "utf8").split("\n", 1)[0];
144604
+ const firstLine = (0, import_fs25.readFileSync)(candidatePath, "utf8").split("\n", 1)[0];
144328
144605
  if (!firstLine) return null;
144329
144606
  const parsed = JSON.parse(firstLine);
144330
144607
  if (parsed?.type !== "session_meta") return null;
@@ -144352,18 +144629,18 @@ var StreamerServer = class {
144352
144629
  this.sessionStore.listManaged().filter((s3) => s3.id !== sessionId && s3.boundConversationId != null).map((s3) => s3.boundConversationId)
144353
144630
  );
144354
144631
  for (const root of this.codexRoots) {
144355
- const sessionsDir = (0, import_path21.join)(root, dateDir);
144356
- if (!(0, import_fs24.existsSync)(sessionsDir)) continue;
144632
+ const sessionsDir = (0, import_path22.join)(root, dateDir);
144633
+ if (!(0, import_fs25.existsSync)(sessionsDir)) continue;
144357
144634
  let candidateFiles;
144358
144635
  try {
144359
- candidateFiles = (0, import_fs24.readdirSync)(sessionsDir).filter((f2) => f2.endsWith(".jsonl"));
144636
+ candidateFiles = (0, import_fs25.readdirSync)(sessionsDir).filter((f2) => f2.endsWith(".jsonl"));
144360
144637
  } catch {
144361
144638
  continue;
144362
144639
  }
144363
144640
  const nowMs = Date.now();
144364
- const recentCandidates = candidateFiles.map((f2) => ({ f: f2, mtime: (0, import_fs24.statSync)((0, import_path21.join)(sessionsDir, f2)).mtimeMs })).filter(({ mtime }) => nowMs - mtime < 1e4).sort((a, b2) => b2.mtime - a.mtime);
144641
+ 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);
144365
144642
  for (const { f: f2 } of recentCandidates) {
144366
- const candidatePath = (0, import_path21.join)(sessionsDir, f2);
144643
+ const candidatePath = (0, import_path22.join)(sessionsDir, f2);
144367
144644
  const match2 = matchesProjectPath(candidatePath);
144368
144645
  if (!match2) continue;
144369
144646
  if (boundElsewhere.has(match2.id)) continue;
@@ -144373,7 +144650,7 @@ var StreamerServer = class {
144373
144650
  this.sessionFileMap.set(sessionId, candidatePath);
144374
144651
  this.fileWatcher.watch(candidatePath);
144375
144652
  try {
144376
- const existing = (0, import_fs24.readFileSync)(candidatePath, "utf8").split("\n").filter(Boolean);
144653
+ const existing = (0, import_fs25.readFileSync)(candidatePath, "utf8").split("\n").filter(Boolean);
144377
144654
  if (existing.length > 0) {
144378
144655
  this.wsHub.broadcast({ type: "conversation_events", sessionId, lines: existing });
144379
144656
  for (const line of existing) {
@@ -144498,7 +144775,7 @@ var StreamerServer = class {
144498
144775
  };
144499
144776
  function classifyResumability(cwd) {
144500
144777
  if (!cwd) return { resumable: true };
144501
- if ((0, import_fs24.existsSync)(cwd)) return { resumable: true };
144778
+ if ((0, import_fs25.existsSync)(cwd)) return { resumable: true };
144502
144779
  const ranInWorktree = /\/\.worktrees\//.test(cwd) || /\/\.claude\/worktrees\//.test(cwd);
144503
144780
  return {
144504
144781
  resumable: false,
@@ -144817,7 +145094,7 @@ function isBrewInstall(scriptPath = process.argv[1] ?? "") {
144817
145094
  var import_node_crypto4 = require("crypto");
144818
145095
  var import_node_fs8 = require("fs");
144819
145096
  var import_node_path10 = require("path");
144820
- var import_promises16 = require("stream/promises");
145097
+ var import_promises18 = require("stream/promises");
144821
145098
 
144822
145099
  // src/updater/manifest.ts
144823
145100
  init_zod();
@@ -144892,7 +145169,7 @@ async function downloadAndVerify(opts) {
144892
145169
  }
144893
145170
  });
144894
145171
  try {
144895
- await (0, import_promises16.pipeline)(res.body.pipeThrough(measured), out);
145172
+ await (0, import_promises18.pipeline)(res.body.pipeThrough(measured), out);
144896
145173
  } catch (err) {
144897
145174
  (0, import_node_fs8.rmSync)(targetPath, { force: true });
144898
145175
  throw err;
@@ -145078,13 +145355,13 @@ var import_node_fs17 = require("fs");
145078
145355
 
145079
145356
  // node_modules/tar/dist/esm/index.min.js
145080
145357
  var import_events4 = __toESM(require("events"), 1);
145081
- var import_fs25 = __toESM(require("fs"), 1);
145358
+ var import_fs26 = __toESM(require("fs"), 1);
145082
145359
  var import_node_events3 = require("events");
145083
145360
  var import_node_stream3 = __toESM(require("stream"), 1);
145084
145361
  var import_node_string_decoder = require("string_decoder");
145085
145362
  var import_node_path14 = __toESM(require("path"), 1);
145086
145363
  var import_node_fs11 = __toESM(require("fs"), 1);
145087
- var import_path22 = require("path");
145364
+ var import_path23 = require("path");
145088
145365
  var import_events5 = require("events");
145089
145366
  var import_assert = __toESM(require("assert"), 1);
145090
145367
  var import_buffer2 = require("buffer");
@@ -145092,21 +145369,21 @@ var Ps = __toESM(require("zlib"), 1);
145092
145369
  var import_zlib = __toESM(require("zlib"), 1);
145093
145370
  var import_node_path15 = require("path");
145094
145371
  var import_node_path16 = require("path");
145095
- var import_fs26 = __toESM(require("fs"), 1);
145096
145372
  var import_fs27 = __toESM(require("fs"), 1);
145097
- var import_path23 = __toESM(require("path"), 1);
145098
- var import_node_path17 = require("path");
145373
+ var import_fs28 = __toESM(require("fs"), 1);
145099
145374
  var import_path24 = __toESM(require("path"), 1);
145375
+ var import_node_path17 = require("path");
145376
+ var import_path25 = __toESM(require("path"), 1);
145100
145377
  var import_node_fs12 = __toESM(require("fs"), 1);
145101
145378
  var import_node_assert = __toESM(require("assert"), 1);
145102
145379
  var import_node_crypto5 = require("crypto");
145103
145380
  var import_node_fs13 = __toESM(require("fs"), 1);
145104
145381
  var import_node_path18 = __toESM(require("path"), 1);
145105
- var import_fs28 = __toESM(require("fs"), 1);
145382
+ var import_fs29 = __toESM(require("fs"), 1);
145106
145383
  var import_node_fs14 = __toESM(require("fs"), 1);
145107
145384
  var import_node_path19 = __toESM(require("path"), 1);
145108
145385
  var import_node_fs15 = __toESM(require("fs"), 1);
145109
- var import_promises17 = __toESM(require("fs/promises"), 1);
145386
+ var import_promises19 = __toESM(require("fs/promises"), 1);
145110
145387
  var import_node_path20 = __toESM(require("path"), 1);
145111
145388
  var import_node_path21 = require("path");
145112
145389
  var import_node_fs16 = __toESM(require("fs"), 1);
@@ -145454,7 +145731,7 @@ var A = class extends import_node_events3.EventEmitter {
145454
145731
  return Wr;
145455
145732
  }
145456
145733
  };
145457
- var Jr = import_fs25.default.writev;
145734
+ var Jr = import_fs26.default.writev;
145458
145735
  var ht = /* @__PURE__ */ Symbol("_autoClose");
145459
145736
  var H = /* @__PURE__ */ Symbol("_close");
145460
145737
  var te = /* @__PURE__ */ Symbol("_ended");
@@ -145509,7 +145786,7 @@ var _t = class extends A {
145509
145786
  throw new TypeError("this is a readable stream");
145510
145787
  }
145511
145788
  [at]() {
145512
- import_fs25.default.open(this[U2], "r", (t2, e) => this[Ht](t2, e));
145789
+ import_fs26.default.open(this[U2], "r", (t2, e) => this[Ht](t2, e));
145513
145790
  }
145514
145791
  [Ht](t2, e) {
145515
145792
  t2 ? this[Ut](t2) : (this[u2] = e, this.emit("open", e), this[zt]());
@@ -145522,7 +145799,7 @@ var _t = class extends A {
145522
145799
  this[j] = true;
145523
145800
  let t2 = this[vi]();
145524
145801
  if (t2.length === 0) return process.nextTick(() => this[Ii](null, 0, t2));
145525
- import_fs25.default.read(this[u2], t2, 0, t2.length, null, (e, i, r) => this[Ii](e, i, r));
145802
+ import_fs26.default.read(this[u2], t2, 0, t2.length, null, (e, i, r) => this[Ii](e, i, r));
145526
145803
  }
145527
145804
  }
145528
145805
  [Ii](t2, e, i) {
@@ -145531,7 +145808,7 @@ var _t = class extends A {
145531
145808
  [H]() {
145532
145809
  if (this[ht] && typeof this[u2] == "number") {
145533
145810
  let t2 = this[u2];
145534
- this[u2] = void 0, import_fs25.default.close(t2, (e) => e ? this.emit("error", e) : this.emit("close"));
145811
+ this[u2] = void 0, import_fs26.default.close(t2, (e) => e ? this.emit("error", e) : this.emit("close"));
145535
145812
  }
145536
145813
  }
145537
145814
  [Ut](t2) {
@@ -145559,7 +145836,7 @@ var Be = class extends _t {
145559
145836
  [at]() {
145560
145837
  let t2 = true;
145561
145838
  try {
145562
- this[Ht](null, import_fs25.default.openSync(this[U2], "r")), t2 = false;
145839
+ this[Ht](null, import_fs26.default.openSync(this[U2], "r")), t2 = false;
145563
145840
  } finally {
145564
145841
  t2 && this[H]();
145565
145842
  }
@@ -145570,7 +145847,7 @@ var Be = class extends _t {
145570
145847
  if (!this[j]) {
145571
145848
  this[j] = true;
145572
145849
  do {
145573
- let e = this[vi](), i = e.length === 0 ? 0 : import_fs25.default.readSync(this[u2], e, 0, e.length, null);
145850
+ let e = this[vi](), i = e.length === 0 ? 0 : import_fs26.default.readSync(this[u2], e, 0, e.length, null);
145574
145851
  if (!this[ki](i, e)) break;
145575
145852
  } while (true);
145576
145853
  this[j] = false;
@@ -145583,7 +145860,7 @@ var Be = class extends _t {
145583
145860
  [H]() {
145584
145861
  if (this[ht] && typeof this[u2] == "number") {
145585
145862
  let t2 = this[u2];
145586
- this[u2] = void 0, import_fs25.default.closeSync(t2), this.emit("close");
145863
+ this[u2] = void 0, import_fs26.default.closeSync(t2), this.emit("close");
145587
145864
  }
145588
145865
  }
145589
145866
  };
@@ -145625,7 +145902,7 @@ var et = class extends import_events4.default {
145625
145902
  this[H](), this[gt] = true, this.emit("error", t2);
145626
145903
  }
145627
145904
  [at]() {
145628
- import_fs25.default.open(this[U2], this[tt], this[ie], (t2, e) => this[Ht](t2, e));
145905
+ import_fs26.default.open(this[U2], this[tt], this[ie], (t2, e) => this[Ht](t2, e));
145629
145906
  }
145630
145907
  [Ht](t2, e) {
145631
145908
  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]());
@@ -145637,7 +145914,7 @@ var et = class extends import_events4.default {
145637
145914
  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);
145638
145915
  }
145639
145916
  [ve](t2) {
145640
- import_fs25.default.write(this[u2], t2, 0, t2.length, this[ot], (e, i) => this[Pt](e, i));
145917
+ import_fs26.default.write(this[u2], t2, 0, t2.length, this[ot], (e, i) => this[Pt](e, i));
145641
145918
  }
145642
145919
  [Pt](t2, e) {
145643
145920
  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"))));
@@ -145653,7 +145930,7 @@ var et = class extends import_events4.default {
145653
145930
  [H]() {
145654
145931
  if (this[ht] && typeof this[u2] == "number") {
145655
145932
  let t2 = this[u2];
145656
- this[u2] = void 0, import_fs25.default.close(t2, (e) => e ? this.emit("error", e) : this.emit("close"));
145933
+ this[u2] = void 0, import_fs26.default.close(t2, (e) => e ? this.emit("error", e) : this.emit("close"));
145657
145934
  }
145658
145935
  }
145659
145936
  };
@@ -145661,24 +145938,24 @@ var Wt = class extends et {
145661
145938
  [at]() {
145662
145939
  let t2;
145663
145940
  if (this[Me] && this[tt] === "r+") try {
145664
- t2 = import_fs25.default.openSync(this[U2], this[tt], this[ie]);
145941
+ t2 = import_fs26.default.openSync(this[U2], this[tt], this[ie]);
145665
145942
  } catch (e) {
145666
145943
  if (e?.code === "ENOENT") return this[tt] = "w", this[at]();
145667
145944
  throw e;
145668
145945
  }
145669
- else t2 = import_fs25.default.openSync(this[U2], this[tt], this[ie]);
145946
+ else t2 = import_fs26.default.openSync(this[U2], this[tt], this[ie]);
145670
145947
  this[Ht](null, t2);
145671
145948
  }
145672
145949
  [H]() {
145673
145950
  if (this[ht] && typeof this[u2] == "number") {
145674
145951
  let t2 = this[u2];
145675
- this[u2] = void 0, import_fs25.default.closeSync(t2), this.emit("close");
145952
+ this[u2] = void 0, import_fs26.default.closeSync(t2), this.emit("close");
145676
145953
  }
145677
145954
  }
145678
145955
  [ve](t2) {
145679
145956
  let e = true;
145680
145957
  try {
145681
- this[Pt](null, import_fs25.default.writeSync(this[u2], t2, 0, t2.length, this[ot])), e = false;
145958
+ this[Pt](null, import_fs26.default.writeSync(this[u2], t2, 0, t2.length, this[ot])), e = false;
145682
145959
  } finally {
145683
145960
  if (e) try {
145684
145961
  this[H]();
@@ -146461,11 +146738,11 @@ var vn = (s3) => {
146461
146738
  };
146462
146739
  var Qi = (s3, t2) => {
146463
146740
  let e = new Map(t2.map((n) => [ut(n), true])), i = s3.filter, r = (n, o = "") => {
146464
- let h = o || (0, import_path22.parse)(n).root || ".", a;
146741
+ let h = o || (0, import_path23.parse)(n).root || ".", a;
146465
146742
  if (n === h) a = false;
146466
146743
  else {
146467
146744
  let l = e.get(n);
146468
- a = l !== void 0 ? l : r((0, import_path22.dirname)(n), h);
146745
+ a = l !== void 0 ? l : r((0, import_path23.dirname)(n), h);
146469
146746
  }
146470
146747
  return e.set(n, a), a;
146471
146748
  };
@@ -146585,7 +146862,7 @@ var de = class extends A {
146585
146862
  let [o, h] = ce(this.path);
146586
146863
  o && typeof h == "string" && (this.path = h, r = o);
146587
146864
  }
146588
- this.win32 = !!i.win32 || process.platform === "win32", this.win32 && (this.path = Qs(this.path.replaceAll(/\\/g, "/")), t2 = t2.replaceAll(/\\/g, "/")), this.absolute = f(i.absolute || import_path23.default.resolve(this.cwd, t2)), this.path === "" && (this.path = "./"), r && this.warn("TAR_ENTRY_INFO", `stripping ${r} from absolute path`, { entry: this, path: r + this.path });
146865
+ this.win32 = !!i.win32 || process.platform === "win32", this.win32 && (this.path = Qs(this.path.replaceAll(/\\/g, "/")), t2 = t2.replaceAll(/\\/g, "/")), this.absolute = f(i.absolute || import_path24.default.resolve(this.cwd, t2)), this.path === "" && (this.path = "./"), r && this.warn("TAR_ENTRY_INFO", `stripping ${r} from absolute path`, { entry: this, path: r + this.path });
146589
146866
  let n = this.statCache.get(this.absolute);
146590
146867
  n ? this[si](n) : this[ss]();
146591
146868
  }
@@ -146596,7 +146873,7 @@ var de = class extends A {
146596
146873
  return t2 === "error" && (this.#t = true), super.emit(t2, ...e);
146597
146874
  }
146598
146875
  [ss]() {
146599
- import_fs27.default.lstat(this.absolute, (t2, e) => {
146876
+ import_fs28.default.lstat(this.absolute, (t2, e) => {
146600
146877
  if (t2) return this.emit("error", t2);
146601
146878
  this[si](e);
146602
146879
  });
@@ -146634,7 +146911,7 @@ var de = class extends A {
146634
146911
  this.path.slice(-1) !== "/" && (this.path += "/"), this.stat.size = 0, this[fe](), this.end();
146635
146912
  }
146636
146913
  [is]() {
146637
- import_fs27.default.readlink(this.absolute, (t2, e) => {
146914
+ import_fs28.default.readlink(this.absolute, (t2, e) => {
146638
146915
  if (t2) return this.emit("error", t2);
146639
146916
  this[ns](e);
146640
146917
  });
@@ -146644,7 +146921,7 @@ var de = class extends A {
146644
146921
  }
146645
146922
  [sr](t2) {
146646
146923
  if (!this.stat) throw new Error("cannot create link entry without stat");
146647
- this.type = "Link", this.linkpath = f(import_path23.default.relative(this.cwd, t2)), this.stat.size = 0, this[fe](), this.end();
146924
+ this.type = "Link", this.linkpath = f(import_path24.default.relative(this.cwd, t2)), this.stat.size = 0, this[fe](), this.end();
146648
146925
  }
146649
146926
  [er]() {
146650
146927
  if (!this.stat) throw new Error("cannot create file entry without stat");
@@ -146657,7 +146934,7 @@ var de = class extends A {
146657
146934
  this[os]();
146658
146935
  }
146659
146936
  [os]() {
146660
- import_fs27.default.open(this.absolute, "r", (t2, e) => {
146937
+ import_fs28.default.open(this.absolute, "r", (t2, e) => {
146661
146938
  if (t2) return this.emit("error", t2);
146662
146939
  this[hs](e);
146663
146940
  });
@@ -146672,14 +146949,14 @@ var de = class extends A {
146672
146949
  [ii]() {
146673
146950
  let { fd: t2, buf: e, offset: i, length: r, pos: n } = this;
146674
146951
  if (t2 === void 0 || e === void 0) throw new Error("cannot read file without first opening");
146675
- import_fs27.default.read(t2, e, i, r, n, (o, h) => {
146952
+ import_fs28.default.read(t2, e, i, r, n, (o, h) => {
146676
146953
  if (o) return this[pt](() => this.emit("error", o));
146677
146954
  this[rs](h);
146678
146955
  });
146679
146956
  }
146680
146957
  [pt](t2 = () => {
146681
146958
  }) {
146682
- this.fd !== void 0 && import_fs27.default.close(this.fd, t2);
146959
+ this.fd !== void 0 && import_fs28.default.close(this.fd, t2);
146683
146960
  }
146684
146961
  [rs](t2) {
146685
146962
  if (t2 <= 0 && this.remain > 0) {
@@ -146714,20 +146991,20 @@ var de = class extends A {
146714
146991
  var ni = class extends de {
146715
146992
  sync = true;
146716
146993
  [ss]() {
146717
- this[si](import_fs27.default.lstatSync(this.absolute));
146994
+ this[si](import_fs28.default.lstatSync(this.absolute));
146718
146995
  }
146719
146996
  [is]() {
146720
- this[ns](import_fs27.default.readlinkSync(this.absolute));
146997
+ this[ns](import_fs28.default.readlinkSync(this.absolute));
146721
146998
  }
146722
146999
  [os]() {
146723
- this[hs](import_fs27.default.openSync(this.absolute, "r"));
147000
+ this[hs](import_fs28.default.openSync(this.absolute, "r"));
146724
147001
  }
146725
147002
  [ii]() {
146726
147003
  let t2 = true;
146727
147004
  try {
146728
147005
  let { fd: e, buf: i, offset: r, length: n, pos: o } = this;
146729
147006
  if (e === void 0 || i === void 0) throw new Error("fd and buf must be set in READ method");
146730
- let h = import_fs27.default.readSync(e, i, r, n, o);
147007
+ let h = import_fs28.default.readSync(e, i, r, n, o);
146731
147008
  this[rs](h), t2 = false;
146732
147009
  } finally {
146733
147010
  if (t2) try {
@@ -146742,7 +147019,7 @@ var ni = class extends de {
146742
147019
  }
146743
147020
  [pt](t2 = () => {
146744
147021
  }) {
146745
- this.fd !== void 0 && import_fs27.default.closeSync(this.fd), t2();
147022
+ this.fd !== void 0 && import_fs28.default.closeSync(this.fd), t2();
146746
147023
  }
146747
147024
  };
146748
147025
  var oi = class extends A {
@@ -147058,7 +147335,7 @@ var wt = class extends A {
147058
147335
  return typeof t2 == "string" ? this[ci](t2) : this[or](t2), this.flowing;
147059
147336
  }
147060
147337
  [or](t2) {
147061
- let e = f(import_path24.default.resolve(this.cwd, t2.path));
147338
+ let e = f(import_path25.default.resolve(this.cwd, t2.path));
147062
147339
  if (!this.filter(t2.path, t2)) t2.resume();
147063
147340
  else {
147064
147341
  let i = new pi(t2.path, e);
@@ -147067,13 +147344,13 @@ var wt = class extends A {
147067
147344
  this[Ft]();
147068
147345
  }
147069
147346
  [ci](t2) {
147070
- let e = f(import_path24.default.resolve(this.cwd, t2));
147347
+ let e = f(import_path25.default.resolve(this.cwd, t2));
147071
147348
  this[W].push(new pi(t2, e)), this[Ft]();
147072
147349
  }
147073
147350
  [ds](t2) {
147074
147351
  t2.pending = true, this[G2] += 1;
147075
147352
  let e = this.follow ? "stat" : "lstat";
147076
- import_fs26.default[e](t2.absolute, (i, r) => {
147353
+ import_fs27.default[e](t2.absolute, (i, r) => {
147077
147354
  t2.pending = false, this[G2] -= 1, i ? this.emit("error", i) : this[li](t2, r);
147078
147355
  });
147079
147356
  }
@@ -147087,7 +147364,7 @@ var wt = class extends A {
147087
147364
  this[Ft]();
147088
147365
  }
147089
147366
  [ms](t2) {
147090
- t2.pending = true, this[G2] += 1, import_fs26.default.readdir(t2.absolute, (e, i) => {
147367
+ t2.pending = true, this[G2] += 1, import_fs27.default.readdir(t2.absolute, (e, i) => {
147091
147368
  if (t2.pending = false, this[G2] -= 1, e) return this.emit("error", e);
147092
147369
  this[fi](t2, i);
147093
147370
  });
@@ -147188,10 +147465,10 @@ var kt = class extends wt {
147188
147465
  }
147189
147466
  [ds](t2) {
147190
147467
  let e = this.follow ? "statSync" : "lstatSync";
147191
- this[li](t2, import_fs26.default[e](t2.absolute));
147468
+ this[li](t2, import_fs27.default[e](t2.absolute));
147192
147469
  }
147193
147470
  [ms](t2) {
147194
- this[fi](t2, import_fs26.default.readdirSync(t2.absolute));
147471
+ this[fi](t2, import_fs27.default.readdirSync(t2.absolute));
147195
147472
  }
147196
147473
  [di](t2) {
147197
147474
  let e = t2.entry, i = this.zip;
@@ -147242,8 +147519,8 @@ var Qn = K2(Vn, $n, Xn, qn, (s3, t2) => {
147242
147519
  });
147243
147520
  var Jn = process.env.__FAKE_PLATFORM__ || process.platform;
147244
147521
  var Er = Jn === "win32";
147245
- var { O_CREAT: wr, O_NOFOLLOW: mr, O_TRUNC: Sr, O_WRONLY: yr } = import_fs28.default.constants;
147246
- var Rr = Number(process.env.__FAKE_FS_O_FILENAME__) || import_fs28.default.constants.UV_FS_O_FILEMAP || 0;
147522
+ var { O_CREAT: wr, O_NOFOLLOW: mr, O_TRUNC: Sr, O_WRONLY: yr } = import_fs29.default.constants;
147523
+ var Rr = Number(process.env.__FAKE_FS_O_FILENAME__) || import_fs29.default.constants.UV_FS_O_FILEMAP || 0;
147247
147524
  var jn = Er && !!Rr;
147248
147525
  var to = 512 * 1024;
147249
147526
  var eo = Rr | Sr | wr | yr;
@@ -147338,7 +147615,7 @@ var gr = (s3, t2, e) => {
147338
147615
  E2 ? e(E2) : x2 && a ? Es(x2, o, h, (Le) => S2(Le)) : n ? import_node_fs15.default.chmod(s3, r, e) : e();
147339
147616
  };
147340
147617
  if (s3 === d) return no(s3, S2);
147341
- if (l) return import_promises17.default.mkdir(s3, { mode: r, recursive: true }).then((E2) => S2(null, E2 ?? void 0), S2);
147618
+ if (l) return import_promises19.default.mkdir(s3, { mode: r, recursive: true }).then((E2) => S2(null, E2 ?? void 0), S2);
147342
147619
  let D2 = f(import_node_path20.default.relative(d, s3)).split("/");
147343
147620
  Ss(d, D2, r, c, d, void 0, S2);
147344
147621
  };