chat-recall 0.5.30 → 0.5.32

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/mcp.js CHANGED
@@ -6468,6 +6468,64 @@ var init_chunker = __esm({
6468
6468
  }
6469
6469
  });
6470
6470
 
6471
+ // ../engine/dist/core/project-dir-name.js
6472
+ import { readdirSync as readdirSync5 } from "node:fs";
6473
+ function looksWindowsEncoded(dirName) {
6474
+ return /^[A-Za-z]--/.test(dirName);
6475
+ }
6476
+ function decodeProjectDirName(dirName) {
6477
+ if (!dirName)
6478
+ return "";
6479
+ if (looksWindowsEncoded(dirName)) {
6480
+ const drive = dirName[0].toUpperCase();
6481
+ const rest = dirName.slice(3).replace(/-/g, "\\");
6482
+ return `${drive}:\\${rest}`;
6483
+ }
6484
+ return "/" + dirName.replace(/^-/, "").replace(/-/g, "/");
6485
+ }
6486
+ function resolveProjectDirName(dirName, deps = {}) {
6487
+ const structural = decodeProjectDirName(dirName);
6488
+ if (!dirName)
6489
+ return structural;
6490
+ if (looksWindowsEncoded(dirName))
6491
+ return structural;
6492
+ const readdir3 = deps.readdir ?? ((p) => readdirSync5(p, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name));
6493
+ const encodeName = (name) => name.replace(/[-_.]/g, "-");
6494
+ let remaining = dirName.replace(/^-/, "");
6495
+ let current = "/";
6496
+ while (remaining) {
6497
+ let children;
6498
+ try {
6499
+ children = readdir3(current);
6500
+ } catch {
6501
+ break;
6502
+ }
6503
+ let best = "";
6504
+ for (const child of children) {
6505
+ const encoded = encodeName(child);
6506
+ if (!encoded || encoded.length < best.length)
6507
+ continue;
6508
+ if (!remaining.startsWith(encoded))
6509
+ continue;
6510
+ const next = remaining[encoded.length];
6511
+ if (next !== void 0 && next !== "-")
6512
+ continue;
6513
+ if (encoded.length > best.length)
6514
+ best = child;
6515
+ }
6516
+ if (!best)
6517
+ break;
6518
+ current = current === "/" ? `/${best}` : `${current}/${best}`;
6519
+ remaining = remaining.slice(encodeName(best).length).replace(/^-/, "");
6520
+ }
6521
+ return remaining ? structural : current;
6522
+ }
6523
+ var init_project_dir_name = __esm({
6524
+ "../engine/dist/core/project-dir-name.js"() {
6525
+ "use strict";
6526
+ }
6527
+ });
6528
+
6471
6529
  // ../engine/dist/core/model-pricing.js
6472
6530
  function pricingFor(modelId) {
6473
6531
  if (!modelId)
@@ -6639,7 +6697,7 @@ var init_model_pricing = __esm({
6639
6697
  });
6640
6698
 
6641
6699
  // ../engine/dist/parsers/session.js
6642
- import { createReadStream, existsSync as existsSync6, readdirSync as readdirSync5, readFileSync as readFileSync3, statSync as statSync5, openSync, readSync, closeSync } from "fs";
6700
+ import { createReadStream, existsSync as existsSync6, readdirSync as readdirSync6, readFileSync as readFileSync3, statSync as statSync5, openSync, readSync, closeSync } from "fs";
6643
6701
  import { createInterface } from "readline";
6644
6702
  import { join as join6, basename as basename3 } from "path";
6645
6703
  function removeCodeBlocks(text) {
@@ -6710,7 +6768,7 @@ function* iterAllSessionIndices(claudeDir) {
6710
6768
  if (!existsSync6(dir)) {
6711
6769
  return;
6712
6770
  }
6713
- const entries = readdirSync5(dir, { withFileTypes: true });
6771
+ const entries = readdirSync6(dir, { withFileTypes: true });
6714
6772
  for (const entry of entries) {
6715
6773
  if (!entry.isDirectory())
6716
6774
  continue;
@@ -6732,7 +6790,7 @@ function getSubagentPaths(sessionPath) {
6732
6790
  const subagentsDir = join6(sessionPath.slice(0, -6), "subagents");
6733
6791
  if (!existsSync6(subagentsDir))
6734
6792
  return [];
6735
- return readdirSync5(subagentsDir).filter((f) => f.endsWith(".jsonl")).sort().map((f) => join6(subagentsDir, f));
6793
+ return readdirSync6(subagentsDir).filter((f) => f.endsWith(".jsonl")).sort().map((f) => join6(subagentsDir, f));
6736
6794
  }
6737
6795
  function getSubagentProjectPath(sessionPath, folderDerivedPath) {
6738
6796
  const subagentPaths = getSubagentPaths(sessionPath);
@@ -7049,40 +7107,6 @@ ${resultText}` : resultText;
7049
7107
  });
7050
7108
  return content;
7051
7109
  }
7052
- function decodeDirName(dirName) {
7053
- const segments = dirName.replace(/^-/, "").split("-");
7054
- let currentPath = "/";
7055
- let i = 0;
7056
- while (i < segments.length) {
7057
- let matched = false;
7058
- const singleCandidate = join6(currentPath, segments[i]);
7059
- if (existsSync6(singleCandidate)) {
7060
- currentPath = singleCandidate;
7061
- i++;
7062
- matched = true;
7063
- continue;
7064
- }
7065
- for (let len = 2; len <= segments.length - i; len++) {
7066
- const joinedSegments = segments.slice(i, i + len);
7067
- for (const sep4 of ["-", "_", "."]) {
7068
- const candidate = join6(currentPath, joinedSegments.join(sep4));
7069
- if (existsSync6(candidate)) {
7070
- currentPath = candidate;
7071
- i += len;
7072
- matched = true;
7073
- break;
7074
- }
7075
- }
7076
- if (matched)
7077
- break;
7078
- }
7079
- if (!matched) {
7080
- currentPath = join6(currentPath, segments[i]);
7081
- i++;
7082
- }
7083
- }
7084
- return currentPath;
7085
- }
7086
7110
  function* getAllSessions(claudeDir) {
7087
7111
  const seenSessionIds = /* @__PURE__ */ new Set();
7088
7112
  const projectDirs = claudeDir ? [claudeDir] : claudeProjectDirs();
@@ -7097,12 +7121,12 @@ function* getAllSessions(claudeDir) {
7097
7121
  }
7098
7122
  if (!existsSync6(dir))
7099
7123
  continue;
7100
- const dirEntries = readdirSync5(dir, { withFileTypes: true });
7124
+ const dirEntries = readdirSync6(dir, { withFileTypes: true });
7101
7125
  for (const projDirEntry of dirEntries) {
7102
7126
  if (!projDirEntry.isDirectory())
7103
7127
  continue;
7104
7128
  const projectPath = join6(dir, projDirEntry.name);
7105
- const files = readdirSync5(projectPath);
7129
+ const files = readdirSync6(projectPath);
7106
7130
  for (const file of files) {
7107
7131
  if (!file.endsWith(".jsonl"))
7108
7132
  continue;
@@ -7116,7 +7140,7 @@ function* getAllSessions(claudeDir) {
7116
7140
  const fullPath = join6(projectPath, file);
7117
7141
  try {
7118
7142
  const stat3 = statSync5(fullPath);
7119
- const derivedProjectPath = decodeDirName(projDirEntry.name);
7143
+ const derivedProjectPath = resolveProjectDirName(projDirEntry.name);
7120
7144
  const effectiveMtime = getSessionMtime(fullPath);
7121
7145
  let projectPath2 = "";
7122
7146
  if (hasSubagentsDir(fullPath)) {
@@ -7155,6 +7179,7 @@ var init_session = __esm({
7155
7179
  init_chunker();
7156
7180
  init_claude2();
7157
7181
  init_tool_paths();
7182
+ init_project_dir_name();
7158
7183
  init_model_pricing();
7159
7184
  }
7160
7185
  });
@@ -7813,7 +7838,7 @@ async function archiveRawSession(store2, sessionId) {
7813
7838
  return await store2.putRawSession(sessionId, exp.tool, Math.floor(exp.mtime), gz, size);
7814
7839
  }
7815
7840
  function detectForkPredecessor(sessionPath) {
7816
- const { readFileSync: readFileSync44, readdirSync: readdirSync35 } = requireFs();
7841
+ const { readFileSync: readFileSync44, readdirSync: readdirSync36 } = requireFs();
7817
7842
  const { dirname: dirname20, join: join53, basename: basename25 } = requirePath();
7818
7843
  let text;
7819
7844
  try {
@@ -7843,7 +7868,7 @@ function detectForkPredecessor(sessionPath) {
7843
7868
  const self = basename25(sessionPath);
7844
7869
  let entries;
7845
7870
  try {
7846
- entries = readdirSync35(dir);
7871
+ entries = readdirSync36(dir);
7847
7872
  } catch {
7848
7873
  return null;
7849
7874
  }
@@ -8066,28 +8091,8 @@ var init_shadow = __esm({
8066
8091
  }
8067
8092
  });
8068
8093
 
8069
- // ../engine/dist/core/project-dir-name.js
8070
- function looksWindowsEncoded(dirName) {
8071
- return /^[A-Za-z]--/.test(dirName);
8072
- }
8073
- function decodeProjectDirName(dirName) {
8074
- if (!dirName)
8075
- return "";
8076
- if (looksWindowsEncoded(dirName)) {
8077
- const drive = dirName[0].toUpperCase();
8078
- const rest = dirName.slice(3).replace(/-/g, "\\");
8079
- return `${drive}:\\${rest}`;
8080
- }
8081
- return "/" + dirName.replace(/^-/, "").replace(/-/g, "/");
8082
- }
8083
- var init_project_dir_name = __esm({
8084
- "../engine/dist/core/project-dir-name.js"() {
8085
- "use strict";
8086
- }
8087
- });
8088
-
8089
8094
  // ../engine/dist/core/live-session-scan.js
8090
- import { existsSync as existsSync8, readdirSync as readdirSync6, readFileSync as readFileSync5, statSync as statSync7, openSync as openSync2, readSync as readSync2, closeSync as closeSync2 } from "fs";
8095
+ import { existsSync as existsSync8, readdirSync as readdirSync7, readFileSync as readFileSync5, statSync as statSync7, openSync as openSync2, readSync as readSync2, closeSync as closeSync2 } from "fs";
8091
8096
  import { join as join10, basename as basename6 } from "path";
8092
8097
  import { createHash as createHash4 } from "crypto";
8093
8098
  function lazyGeminiProjectsJson() {
@@ -8124,7 +8129,7 @@ function sessionFileIndex() {
8124
8129
  seenRoots.add(root);
8125
8130
  let entries;
8126
8131
  try {
8127
- entries = readdirSync6(root, { withFileTypes: true });
8132
+ entries = readdirSync7(root, { withFileTypes: true });
8128
8133
  } catch {
8129
8134
  continue;
8130
8135
  }
@@ -8134,7 +8139,7 @@ function sessionFileIndex() {
8134
8139
  const dir = join10(root, entry.name);
8135
8140
  let names;
8136
8141
  try {
8137
- names = readdirSync6(dir);
8142
+ names = readdirSync7(dir);
8138
8143
  } catch {
8139
8144
  continue;
8140
8145
  }
@@ -8145,7 +8150,7 @@ function sessionFileIndex() {
8145
8150
  const located = {
8146
8151
  path: join10(dir, name),
8147
8152
  projectDir: entry.name,
8148
- projectPath: decodeProjectDirName(entry.name)
8153
+ projectPath: resolveProjectDirName(entry.name)
8149
8154
  };
8150
8155
  const prior = byId.get(id);
8151
8156
  if (prior)
@@ -8232,7 +8237,7 @@ function resolveSessionContentPaths(sessionFile) {
8232
8237
  const subDir = join10(sessionFile.slice(0, -6), "subagents");
8233
8238
  if (!existsSync8(subDir))
8234
8239
  return [sessionFile];
8235
- const subPaths = readdirSync6(subDir).filter((f) => f.endsWith(".jsonl")).sort().map((f) => join10(subDir, f));
8240
+ const subPaths = readdirSync7(subDir).filter((f) => f.endsWith(".jsonl")).sort().map((f) => join10(subDir, f));
8236
8241
  return [sessionFile, ...subPaths];
8237
8242
  }
8238
8243
  function loadGeminiProjectMap() {
@@ -8280,7 +8285,7 @@ function geminiIndex() {
8280
8285
  continue;
8281
8286
  let projs;
8282
8287
  try {
8283
- projs = readdirSync6(tmpRoot, { withFileTypes: true });
8288
+ projs = readdirSync7(tmpRoot, { withFileTypes: true });
8284
8289
  } catch {
8285
8290
  continue;
8286
8291
  }
@@ -8292,7 +8297,7 @@ function geminiIndex() {
8292
8297
  continue;
8293
8298
  let files;
8294
8299
  try {
8295
- files = readdirSync6(chats);
8300
+ files = readdirSync7(chats);
8296
8301
  } catch {
8297
8302
  continue;
8298
8303
  }
@@ -8411,21 +8416,21 @@ function findCodexSessionFile(sessionId) {
8411
8416
  function findCodexSessionFileIn(root, sessionId) {
8412
8417
  if (!existsSync8(root))
8413
8418
  return null;
8414
- for (const year of readdirSync6(root, { withFileTypes: true })) {
8419
+ for (const year of readdirSync7(root, { withFileTypes: true })) {
8415
8420
  if (!year.isDirectory())
8416
8421
  continue;
8417
8422
  const yearPath = join10(root, year.name);
8418
- for (const month of readdirSync6(yearPath, { withFileTypes: true })) {
8423
+ for (const month of readdirSync7(yearPath, { withFileTypes: true })) {
8419
8424
  if (!month.isDirectory())
8420
8425
  continue;
8421
8426
  const monthPath = join10(yearPath, month.name);
8422
- for (const day of readdirSync6(monthPath, { withFileTypes: true })) {
8427
+ for (const day of readdirSync7(monthPath, { withFileTypes: true })) {
8423
8428
  if (!day.isDirectory())
8424
8429
  continue;
8425
8430
  const dayPath = join10(monthPath, day.name);
8426
8431
  let files;
8427
8432
  try {
8428
- files = readdirSync6(dayPath);
8433
+ files = readdirSync7(dayPath);
8429
8434
  } catch {
8430
8435
  continue;
8431
8436
  }
@@ -8440,7 +8445,7 @@ function findCodexSessionFileIn(root, sessionId) {
8440
8445
  }
8441
8446
  }
8442
8447
  function scanDir(dir) {
8443
- for (const entry of readdirSync6(dir, { withFileTypes: true })) {
8448
+ for (const entry of readdirSync7(dir, { withFileTypes: true })) {
8444
8449
  if (entry.isDirectory()) {
8445
8450
  const found = scanDir(join10(dir, entry.name));
8446
8451
  if (found)
@@ -9385,7 +9390,7 @@ var init_generic_engine = __esm({
9385
9390
  });
9386
9391
 
9387
9392
  // ../engine/dist/core/backends/claude.js
9388
- import { existsSync as existsSync11, readdirSync as readdirSync7, readFileSync as readFileSync6, statSync as statSync9, openSync as openSync5, readSync as readSync5, closeSync as closeSync5 } from "fs";
9393
+ import { existsSync as existsSync11, readdirSync as readdirSync8, readFileSync as readFileSync6, statSync as statSync9, openSync as openSync5, readSync as readSync5, closeSync as closeSync5 } from "fs";
9389
9394
  import { join as join11, basename as basename9 } from "path";
9390
9395
  function stripReminders(text) {
9391
9396
  return text.replace(/<system-reminder>[\s\S]*?<\/system-reminder>/g, "").trim();
@@ -9540,13 +9545,13 @@ var init_claude2 = __esm({
9540
9545
  collectSessionsFromRoot(root, cutoff, filter, seen, out) {
9541
9546
  if (!existsSync11(root))
9542
9547
  return;
9543
- for (const proj of readdirSync7(root, { withFileTypes: true })) {
9548
+ for (const proj of readdirSync8(root, { withFileTypes: true })) {
9544
9549
  if (!proj.isDirectory())
9545
9550
  continue;
9546
9551
  if (filter && !proj.name.toLowerCase().includes(filter))
9547
9552
  continue;
9548
9553
  const projPath = join11(root, proj.name);
9549
- const projectPath = decodeProjectDirName(proj.name);
9554
+ const projectPath = resolveProjectDirName(proj.name);
9550
9555
  const indexPath = join11(projPath, "sessions-index.json");
9551
9556
  if (existsSync11(indexPath)) {
9552
9557
  try {
@@ -9577,7 +9582,7 @@ var init_claude2 = __esm({
9577
9582
  }
9578
9583
  let files;
9579
9584
  try {
9580
- files = readdirSync7(projPath);
9585
+ files = readdirSync8(projPath);
9581
9586
  } catch {
9582
9587
  continue;
9583
9588
  }
@@ -9846,7 +9851,7 @@ var init_claude2 = __esm({
9846
9851
  for (const root of claudeProjectDirs()) {
9847
9852
  if (!existsSync11(root))
9848
9853
  continue;
9849
- for (const projEntry of readdirSync7(root, { withFileTypes: true })) {
9854
+ for (const projEntry of readdirSync8(root, { withFileTypes: true })) {
9850
9855
  if (!projEntry.isDirectory())
9851
9856
  continue;
9852
9857
  if (opts.projectFilter && !projEntry.name.toLowerCase().includes(opts.projectFilter.toLowerCase()))
@@ -9854,7 +9859,7 @@ var init_claude2 = __esm({
9854
9859
  const projPath = join11(root, projEntry.name);
9855
9860
  let files;
9856
9861
  try {
9857
- files = readdirSync7(projPath);
9862
+ files = readdirSync8(projPath);
9858
9863
  } catch {
9859
9864
  continue;
9860
9865
  }
@@ -9867,7 +9872,7 @@ var init_claude2 = __esm({
9867
9872
  let mtime = st.mtimeMs;
9868
9873
  const subDir = join11(projPath, f.slice(0, -6), "subagents");
9869
9874
  if (existsSync11(subDir)) {
9870
- for (const sub of readdirSync7(subDir)) {
9875
+ for (const sub of readdirSync8(subDir)) {
9871
9876
  try {
9872
9877
  const subSt = statSync9(join11(subDir, sub));
9873
9878
  if (subSt.mtimeMs > mtime)
@@ -9972,7 +9977,7 @@ var init_claude2 = __esm({
9972
9977
 
9973
9978
  // ../engine/dist/core/backends/gemini.js
9974
9979
  import { createHash as createHash5 } from "crypto";
9975
- import { existsSync as existsSync12, readdirSync as readdirSync8, readFileSync as readFileSync7, statSync as statSync10 } from "fs";
9980
+ import { existsSync as existsSync12, readdirSync as readdirSync9, readFileSync as readFileSync7, statSync as statSync10 } from "fs";
9976
9981
  import { basename as basename10, join as join12 } from "path";
9977
9982
  function readSessionId(path, format) {
9978
9983
  try {
@@ -10086,7 +10091,7 @@ var init_gemini2 = __esm({
10086
10091
  const out = [];
10087
10092
  const seen = /* @__PURE__ */ new Map();
10088
10093
  for (const root of geminiTmpDirs()) {
10089
- for (const projDir of readdirSync8(root, { withFileTypes: true })) {
10094
+ for (const projDir of readdirSync9(root, { withFileTypes: true })) {
10090
10095
  if (!projDir.isDirectory())
10091
10096
  continue;
10092
10097
  const projectPath = projMap.get(projDir.name) || "";
@@ -10097,7 +10102,7 @@ var init_gemini2 = __esm({
10097
10102
  continue;
10098
10103
  let files;
10099
10104
  try {
10100
- files = readdirSync8(chatsDir);
10105
+ files = readdirSync9(chatsDir);
10101
10106
  } catch {
10102
10107
  continue;
10103
10108
  }
@@ -10320,7 +10325,7 @@ var init_gemini2 = __esm({
10320
10325
  return [];
10321
10326
  const projMap = this.loadProjectMap();
10322
10327
  const candidates2 = [];
10323
- for (const proj of readdirSync8(tmpRoot, { withFileTypes: true })) {
10328
+ for (const proj of readdirSync9(tmpRoot, { withFileTypes: true })) {
10324
10329
  if (!proj.isDirectory())
10325
10330
  continue;
10326
10331
  const projectPath = projMap.get(proj.name) || "";
@@ -10334,7 +10339,7 @@ var init_gemini2 = __esm({
10334
10339
  continue;
10335
10340
  let files;
10336
10341
  try {
10337
- files = readdirSync8(chats);
10342
+ files = readdirSync9(chats);
10338
10343
  } catch {
10339
10344
  continue;
10340
10345
  }
@@ -11000,7 +11005,7 @@ var init_opencode = __esm({
11000
11005
  });
11001
11006
 
11002
11007
  // ../engine/dist/core/backends/codex.js
11003
- import { readdirSync as readdirSync9, readFileSync as readFileSync8, statSync as statSync11, openSync as openSync6, readSync as readSync6, closeSync as closeSync6 } from "fs";
11008
+ import { readdirSync as readdirSync10, readFileSync as readFileSync8, statSync as statSync11, openSync as openSync6, readSync as readSync6, closeSync as closeSync6 } from "fs";
11004
11009
  import { basename as basename11, dirname as dirname11, join as join14 } from "path";
11005
11010
  function parseShellWrites(cmd) {
11006
11011
  const out = [];
@@ -11096,7 +11101,7 @@ function parseCodexPatch(input) {
11096
11101
  function* walkRollouts(root) {
11097
11102
  let entries;
11098
11103
  try {
11099
- entries = readdirSync9(root, { withFileTypes: true });
11104
+ entries = readdirSync10(root, { withFileTypes: true });
11100
11105
  } catch {
11101
11106
  return;
11102
11107
  }
@@ -11388,7 +11393,7 @@ var init_codex2 = __esm({
11388
11393
  const dayDir = located.path.substring(0, located.path.lastIndexOf("/"));
11389
11394
  let entries = [];
11390
11395
  try {
11391
- entries = readdirSync9(dayDir);
11396
+ entries = readdirSync10(dayDir);
11392
11397
  } catch {
11393
11398
  }
11394
11399
  for (const entry of entries) {
@@ -11574,7 +11579,7 @@ var init_codex2 = __esm({
11574
11579
  const scanDir = (dir) => {
11575
11580
  let entries;
11576
11581
  try {
11577
- entries = readdirSync9(dir, { withFileTypes: true });
11582
+ entries = readdirSync10(dir, { withFileTypes: true });
11578
11583
  } catch {
11579
11584
  return;
11580
11585
  }
@@ -11667,7 +11672,7 @@ var init_codex2 = __esm({
11667
11672
  if (parentId) {
11668
11673
  const dayDir = dirname11(loc.path);
11669
11674
  try {
11670
- for (const f of readdirSync9(dayDir)) {
11675
+ for (const f of readdirSync10(dayDir)) {
11671
11676
  if (!f.endsWith(".jsonl") || !f.startsWith("rollout-"))
11672
11677
  continue;
11673
11678
  const p = join14(dayDir, f);
@@ -11714,21 +11719,8 @@ var init_codex2 = __esm({
11714
11719
  });
11715
11720
 
11716
11721
  // ../engine/dist/core/backends/agy.js
11717
- import { existsSync as existsSync14, readdirSync as readdirSync10, readFileSync as readFileSync9, statSync as statSync12 } from "fs";
11722
+ import { existsSync as existsSync14, readdirSync as readdirSync11, readFileSync as readFileSync9, statSync as statSync12 } from "fs";
11718
11723
  import { basename as basename12, dirname as dirname12, join as join15 } from "path";
11719
- function getFallbackProjectPath(homeDir) {
11720
- try {
11721
- const settingsPath2 = join15(homeDir, "settings.json");
11722
- if (existsSync14(settingsPath2)) {
11723
- const json = JSON.parse(readFileSync9(settingsPath2, "utf-8"));
11724
- if (Array.isArray(json?.trustedWorkspaces) && json.trustedWorkspaces[0]) {
11725
- return json.trustedWorkspaces[0];
11726
- }
11727
- }
11728
- } catch {
11729
- }
11730
- return "";
11731
- }
11732
11724
  function agyTranscriptPath(logsDir) {
11733
11725
  const full = join15(logsDir, "transcript_full.jsonl");
11734
11726
  if (existsSync14(full))
@@ -11741,8 +11733,8 @@ function agyTranscriptPath(logsDir) {
11741
11733
  function resolveAgyProject(logsDir, homeDir) {
11742
11734
  const deriveFrom = agyTranscriptPath(logsDir);
11743
11735
  if (!deriveFrom)
11744
- return getFallbackProjectPath(homeDir);
11745
- return extractProjectPathFromTranscript(deriveFrom, homeDir) || getFallbackProjectPath(homeDir);
11736
+ return "";
11737
+ return extractProjectPathFromTranscript(deriveFrom, homeDir);
11746
11738
  }
11747
11739
  function extractProjectPathFromTranscript(path, homeDir) {
11748
11740
  let content;
@@ -11896,7 +11888,7 @@ var init_agy = __esm({
11896
11888
  for (const brainDir of agyBrainDirs()) {
11897
11889
  let sessionDirs;
11898
11890
  try {
11899
- sessionDirs = readdirSync10(brainDir);
11891
+ sessionDirs = readdirSync11(brainDir);
11900
11892
  } catch {
11901
11893
  continue;
11902
11894
  }
@@ -12171,7 +12163,7 @@ var init_agy = __esm({
12171
12163
  const candidates2 = [];
12172
12164
  let sessionDirs;
12173
12165
  try {
12174
- sessionDirs = readdirSync10(brainDir);
12166
+ sessionDirs = readdirSync11(brainDir);
12175
12167
  } catch {
12176
12168
  return [];
12177
12169
  }
@@ -12247,7 +12239,7 @@ var init_agy = __esm({
12247
12239
  });
12248
12240
 
12249
12241
  // ../engine/dist/core/backends/cursor-store.js
12250
- import { existsSync as existsSync15, readdirSync as readdirSync11, readFileSync as readFileSync10, statSync as statSync13 } from "fs";
12242
+ import { existsSync as existsSync15, readdirSync as readdirSync12, readFileSync as readFileSync10, statSync as statSync13 } from "fs";
12251
12243
  import { join as join16 } from "path";
12252
12244
  function cursorProjectSlug(absPath) {
12253
12245
  return absPath.replace(/[^a-zA-Z0-9]/g, "-").replace(/-+/g, "-").replace(/^-+|-+$/g, "");
@@ -12256,7 +12248,7 @@ function listChatsIn(chatsRoot) {
12256
12248
  const out = [];
12257
12249
  let hashDirs;
12258
12250
  try {
12259
- hashDirs = readdirSync11(chatsRoot);
12251
+ hashDirs = readdirSync12(chatsRoot);
12260
12252
  } catch {
12261
12253
  return out;
12262
12254
  }
@@ -12266,7 +12258,7 @@ function listChatsIn(chatsRoot) {
12266
12258
  try {
12267
12259
  if (!statSync13(hashPath2).isDirectory())
12268
12260
  continue;
12269
- chatIds = readdirSync11(hashPath2);
12261
+ chatIds = readdirSync12(hashPath2);
12270
12262
  } catch {
12271
12263
  continue;
12272
12264
  }
@@ -12311,7 +12303,7 @@ function findChat(chatsRoots, chatId) {
12311
12303
  for (const root of chatsRoots) {
12312
12304
  let hashDirs;
12313
12305
  try {
12314
- hashDirs = readdirSync11(root);
12306
+ hashDirs = readdirSync12(root);
12315
12307
  } catch {
12316
12308
  continue;
12317
12309
  }
@@ -12632,7 +12624,7 @@ var init_cursor_store = __esm({
12632
12624
  });
12633
12625
 
12634
12626
  // ../engine/dist/core/backends/cursor-ide.js
12635
- import { existsSync as existsSync16, readFileSync as readFileSync11, readdirSync as readdirSync12, statSync as statSync14 } from "fs";
12627
+ import { existsSync as existsSync16, readFileSync as readFileSync11, readdirSync as readdirSync13, statSync as statSync14 } from "fs";
12636
12628
  import { dirname as dirname13, join as join17 } from "path";
12637
12629
  function jsonOf(value) {
12638
12630
  if (value == null)
@@ -12695,7 +12687,7 @@ function workspaceIndex(workspaceRoots) {
12695
12687
  for (const root of workspaceRoots) {
12696
12688
  let entries;
12697
12689
  try {
12698
- entries = readdirSync12(root);
12690
+ entries = readdirSync13(root);
12699
12691
  } catch {
12700
12692
  continue;
12701
12693
  }
@@ -12782,7 +12774,7 @@ function listComposers(globalDbPath, workspaceRoots) {
12782
12774
  for (const root of workspaceRoots) {
12783
12775
  let entries;
12784
12776
  try {
12785
- entries = readdirSync12(root);
12777
+ entries = readdirSync13(root);
12786
12778
  } catch {
12787
12779
  continue;
12788
12780
  }
@@ -15171,7 +15163,7 @@ var init_collector = __esm({
15171
15163
 
15172
15164
  // ../engine/dist/core/source-discovery.js
15173
15165
  import { createHash as createHash9 } from "crypto";
15174
- import { existsSync as existsSync24, readdirSync as readdirSync13, statSync as statSync20 } from "fs";
15166
+ import { existsSync as existsSync24, readdirSync as readdirSync14, statSync as statSync20 } from "fs";
15175
15167
  import { join as join27 } from "path";
15176
15168
  function sourceId(path) {
15177
15169
  return "src_" + createHash9("sha256").update(path).digest("hex").slice(0, 12);
@@ -15208,7 +15200,7 @@ function countTranscripts(root, tool) {
15208
15200
  return;
15209
15201
  let entries;
15210
15202
  try {
15211
- entries = readdirSync13(dir, { withFileTypes: true });
15203
+ entries = readdirSync14(dir, { withFileTypes: true });
15212
15204
  } catch {
15213
15205
  return;
15214
15206
  }
@@ -15278,7 +15270,7 @@ var init_source_discovery = __esm({
15278
15270
 
15279
15271
  // ../engine/dist/core/home-discovery.js
15280
15272
  import { execFileSync as execFileSync2 } from "child_process";
15281
- import { existsSync as existsSync25, readdirSync as readdirSync14, readFileSync as readFileSync19, realpathSync as realpathSync3, statSync as statSync21 } from "fs";
15273
+ import { existsSync as existsSync25, readdirSync as readdirSync15, readFileSync as readFileSync19, realpathSync as realpathSync3, statSync as statSync21 } from "fs";
15282
15274
  import { homedir as homedir7, platform as osPlatform } from "os";
15283
15275
  import { join as join28 } from "path";
15284
15276
  function candidateRoots(plat = osPlatform(), env = process.env) {
@@ -15322,7 +15314,7 @@ function dirHasTranscript(root, match, depth) {
15322
15314
  return false;
15323
15315
  let entries;
15324
15316
  try {
15325
- entries = readdirSync14(root, { withFileTypes: true });
15317
+ entries = readdirSync15(root, { withFileTypes: true });
15326
15318
  } catch {
15327
15319
  return false;
15328
15320
  }
@@ -15354,7 +15346,7 @@ function countSessions(dir, tool) {
15354
15346
  return;
15355
15347
  let entries;
15356
15348
  try {
15357
- entries = readdirSync14(d, { withFileTypes: true });
15349
+ entries = readdirSync15(d, { withFileTypes: true });
15358
15350
  } catch {
15359
15351
  return;
15360
15352
  }
@@ -15423,7 +15415,7 @@ function runningToolHomes(plat = osPlatform()) {
15423
15415
  if (plat === "linux") {
15424
15416
  let pids;
15425
15417
  try {
15426
- pids = readdirSync14("/proc").filter((p) => /^\d+$/.test(p));
15418
+ pids = readdirSync15("/proc").filter((p) => /^\d+$/.test(p));
15427
15419
  } catch {
15428
15420
  return out;
15429
15421
  }
@@ -15503,7 +15495,7 @@ function walkForHomes(dir, depth, visit) {
15503
15495
  return;
15504
15496
  let entries;
15505
15497
  try {
15506
- entries = readdirSync14(dir, { withFileTypes: true });
15498
+ entries = readdirSync15(dir, { withFileTypes: true });
15507
15499
  } catch {
15508
15500
  return;
15509
15501
  }
@@ -16599,7 +16591,7 @@ var init_session_source = __esm({
16599
16591
  });
16600
16592
 
16601
16593
  // ../engine/dist/core/utils.js
16602
- import { existsSync as existsSync26, readdirSync as readdirSync15 } from "fs";
16594
+ import { existsSync as existsSync26, readdirSync as readdirSync16 } from "fs";
16603
16595
  import { homedir as homedir8 } from "os";
16604
16596
  import { join as join29 } from "path";
16605
16597
  function splitByHeaders(markdown) {
@@ -16650,7 +16642,7 @@ function getClaudeDirs() {
16650
16642
  }
16651
16643
  add(join29(home, ".claude"));
16652
16644
  try {
16653
- const entries = readdirSync15(home, { withFileTypes: true });
16645
+ const entries = readdirSync16(home, { withFileTypes: true });
16654
16646
  for (const entry of entries) {
16655
16647
  if (entry.isDirectory() && entry.name.startsWith(".claude-") && entry.name !== ".claude-code") {
16656
16648
  const candidate = join29(home, entry.name);
@@ -16680,7 +16672,7 @@ var init_utils = __esm({
16680
16672
  });
16681
16673
 
16682
16674
  // ../engine/dist/parsers/plan-source.js
16683
- import { existsSync as existsSync27, readdirSync as readdirSync16, readFileSync as readFileSync20, statSync as statSync24 } from "fs";
16675
+ import { existsSync as existsSync27, readdirSync as readdirSync17, readFileSync as readFileSync20, statSync as statSync24 } from "fs";
16684
16676
  import { homedir as homedir9 } from "os";
16685
16677
  import { join as join30, basename as basename14 } from "path";
16686
16678
  import { createHash as createHash10 } from "crypto";
@@ -16707,7 +16699,7 @@ function parseFrontmatter(content) {
16707
16699
  }
16708
16700
  function safeReaddir(dir) {
16709
16701
  try {
16710
- return readdirSync16(dir);
16702
+ return readdirSync17(dir);
16711
16703
  } catch {
16712
16704
  return [];
16713
16705
  }
@@ -16743,11 +16735,11 @@ var init_plan_source = __esm({
16743
16735
  if (!existsSync27(projectsDir))
16744
16736
  return this._knownProjectDirs;
16745
16737
  try {
16746
- const entries = readdirSync16(projectsDir, { withFileTypes: true });
16738
+ const entries = readdirSync17(projectsDir, { withFileTypes: true });
16747
16739
  for (const entry of entries) {
16748
16740
  if (!entry.isDirectory() || entry.name.startsWith("."))
16749
16741
  continue;
16750
- const projectPath = decodeProjectDirName(entry.name);
16742
+ const projectPath = resolveProjectDirName(entry.name);
16751
16743
  if (existsSync27(projectPath)) {
16752
16744
  this._knownProjectDirs.push(projectPath);
16753
16745
  }
@@ -16775,7 +16767,7 @@ var init_plan_source = __esm({
16775
16767
  for (const plansDir of this.plansDirs) {
16776
16768
  if (!existsSync27(plansDir))
16777
16769
  continue;
16778
- const files = readdirSync16(plansDir).filter((f) => f.endsWith(".md"));
16770
+ const files = readdirSync17(plansDir).filter((f) => f.endsWith(".md"));
16779
16771
  for (const file of files) {
16780
16772
  if (seenClaude.has(file))
16781
16773
  continue;
@@ -16819,7 +16811,7 @@ var init_plan_source = __esm({
16819
16811
  return;
16820
16812
  let files;
16821
16813
  try {
16822
- files = readdirSync16(plansDir).filter((f) => f.endsWith(".md"));
16814
+ files = readdirSync17(plansDir).filter((f) => f.endsWith(".md"));
16823
16815
  } catch {
16824
16816
  return;
16825
16817
  }
@@ -16866,7 +16858,7 @@ var init_plan_source = __esm({
16866
16858
  }
16867
16859
  let projDirs;
16868
16860
  try {
16869
- projDirs = readdirSync16(tmpRoot);
16861
+ projDirs = readdirSync17(tmpRoot);
16870
16862
  } catch {
16871
16863
  return;
16872
16864
  }
@@ -16875,7 +16867,7 @@ var init_plan_source = __esm({
16875
16867
  const projRoot = join30(tmpRoot, projDir);
16876
16868
  let sessions;
16877
16869
  try {
16878
- sessions = readdirSync16(projRoot);
16870
+ sessions = readdirSync17(projRoot);
16879
16871
  } catch {
16880
16872
  continue;
16881
16873
  }
@@ -16885,7 +16877,7 @@ var init_plan_source = __esm({
16885
16877
  continue;
16886
16878
  let files;
16887
16879
  try {
16888
- files = readdirSync16(plansDir).filter((f) => f.endsWith(".md"));
16880
+ files = readdirSync17(plansDir).filter((f) => f.endsWith(".md"));
16889
16881
  } catch {
16890
16882
  continue;
16891
16883
  }
@@ -17094,7 +17086,7 @@ var init_plan_source = __esm({
17094
17086
  return;
17095
17087
  let sessionDirs;
17096
17088
  try {
17097
- sessionDirs = readdirSync16(brainDir);
17089
+ sessionDirs = readdirSync17(brainDir);
17098
17090
  } catch {
17099
17091
  return;
17100
17092
  }
@@ -17108,7 +17100,7 @@ var init_plan_source = __esm({
17108
17100
  }
17109
17101
  let files;
17110
17102
  try {
17111
- files = readdirSync16(sessionPath).filter((f) => f.endsWith(".md"));
17103
+ files = readdirSync17(sessionPath).filter((f) => f.endsWith(".md"));
17112
17104
  } catch {
17113
17105
  continue;
17114
17106
  }
@@ -17145,7 +17137,7 @@ var init_plan_source = __esm({
17145
17137
  });
17146
17138
 
17147
17139
  // ../engine/dist/parsers/task-source.js
17148
- import { existsSync as existsSync28, readdirSync as readdirSync17, readFileSync as readFileSync21, statSync as statSync25 } from "fs";
17140
+ import { existsSync as existsSync28, readdirSync as readdirSync18, readFileSync as readFileSync21, statSync as statSync25 } from "fs";
17149
17141
  import { join as join31 } from "path";
17150
17142
  var MAX_CHUNK_CHARS2, TaskSource;
17151
17143
  var init_task_source = __esm({
@@ -17179,7 +17171,7 @@ var init_task_source = __esm({
17179
17171
  return;
17180
17172
  let files;
17181
17173
  try {
17182
- files = readdirSync17(todosDir).filter((f) => f.endsWith(".json"));
17174
+ files = readdirSync18(todosDir).filter((f) => f.endsWith(".json"));
17183
17175
  } catch {
17184
17176
  return;
17185
17177
  }
@@ -17228,7 +17220,7 @@ var init_task_source = __esm({
17228
17220
  async *discoverInDir(tasksDir) {
17229
17221
  if (!existsSync28(tasksDir))
17230
17222
  return;
17231
- const entries = readdirSync17(tasksDir, { withFileTypes: true });
17223
+ const entries = readdirSync18(tasksDir, { withFileTypes: true });
17232
17224
  for (const entry of entries) {
17233
17225
  if (!entry.isDirectory())
17234
17226
  continue;
@@ -17236,7 +17228,7 @@ var init_task_source = __esm({
17236
17228
  const taskDir = join31(tasksDir, sessionUuid);
17237
17229
  try {
17238
17230
  const stat3 = statSync25(taskDir);
17239
- const taskFiles = readdirSync17(taskDir).filter((f) => f.endsWith(".json"));
17231
+ const taskFiles = readdirSync18(taskDir).filter((f) => f.endsWith(".json"));
17240
17232
  if (taskFiles.length === 0)
17241
17233
  continue;
17242
17234
  const tasks = this.readTasks(taskDir, taskFiles);
@@ -17270,7 +17262,7 @@ var init_task_source = __esm({
17270
17262
  const taskDir = item.filePath;
17271
17263
  if (!existsSync28(taskDir))
17272
17264
  return [];
17273
- const taskFiles = readdirSync17(taskDir).filter((f) => f.endsWith(".json"));
17265
+ const taskFiles = readdirSync18(taskDir).filter((f) => f.endsWith(".json"));
17274
17266
  const tasks = this.readTasks(taskDir, taskFiles);
17275
17267
  if (tasks.length === 0)
17276
17268
  return [];
@@ -17381,7 +17373,7 @@ ${task.description}`.slice(0, MAX_CHUNK_CHARS2);
17381
17373
  });
17382
17374
 
17383
17375
  // ../engine/dist/parsers/claude-md-source.js
17384
- import { existsSync as existsSync29, readFileSync as readFileSync22, readdirSync as readdirSync18, statSync as statSync26 } from "fs";
17376
+ import { existsSync as existsSync29, readFileSync as readFileSync22, readdirSync as readdirSync19, statSync as statSync26 } from "fs";
17385
17377
  import { homedir as homedir10 } from "os";
17386
17378
  import { join as join32, basename as basename15, dirname as dirname15 } from "path";
17387
17379
  import { createHash as createHash11 } from "crypto";
@@ -17398,11 +17390,11 @@ function discoverProjectDirs(claudeDir) {
17398
17390
  if (!existsSync29(projectsDir))
17399
17391
  return;
17400
17392
  try {
17401
- const entries = readdirSync18(projectsDir, { withFileTypes: true });
17393
+ const entries = readdirSync19(projectsDir, { withFileTypes: true });
17402
17394
  for (const entry of entries) {
17403
17395
  if (!entry.isDirectory() || entry.name.startsWith("."))
17404
17396
  continue;
17405
- const projectPath = decodeProjectDirName(entry.name);
17397
+ const projectPath = resolveProjectDirName(entry.name);
17406
17398
  addProject(projectPath);
17407
17399
  }
17408
17400
  } catch {
@@ -17415,7 +17407,7 @@ function discoverProjectDirs(claudeDir) {
17415
17407
  const home = homedir10();
17416
17408
  scanProjectsDir(claudeBackend.projectsDir());
17417
17409
  try {
17418
- for (const entry of readdirSync18(home, { withFileTypes: true })) {
17410
+ for (const entry of readdirSync19(home, { withFileTypes: true })) {
17419
17411
  if (entry.isDirectory() && entry.name.startsWith(".claude-") && entry.name !== ".claude-code") {
17420
17412
  scanProjectsDir(join32(home, entry.name, "projects"));
17421
17413
  }
@@ -17517,7 +17509,7 @@ var init_claude_md_source = __esm({
17517
17509
  }
17518
17510
  }
17519
17511
  try {
17520
- const entries = readdirSync18(searchDir, { withFileTypes: true });
17512
+ const entries = readdirSync19(searchDir, { withFileTypes: true });
17521
17513
  for (const entry of entries) {
17522
17514
  if (!entry.isDirectory())
17523
17515
  continue;
@@ -17607,7 +17599,7 @@ var init_claude_md_source = __esm({
17607
17599
  });
17608
17600
 
17609
17601
  // ../engine/dist/parsers/agent-memory-source.js
17610
- import { existsSync as existsSync30, readFileSync as readFileSync23, readdirSync as readdirSync19, statSync as statSync27 } from "fs";
17602
+ import { existsSync as existsSync30, readFileSync as readFileSync23, readdirSync as readdirSync20, statSync as statSync27 } from "fs";
17611
17603
  import { homedir as homedir11 } from "os";
17612
17604
  import { join as join33, basename as basename16 } from "path";
17613
17605
  function parseFrontmatter2(content) {
@@ -17635,7 +17627,7 @@ function parseFrontmatter2(content) {
17635
17627
  return { fm, body };
17636
17628
  }
17637
17629
  function projectHashToPath(hashDir) {
17638
- return decodeProjectDirName(hashDir);
17630
+ return resolveProjectDirName(hashDir);
17639
17631
  }
17640
17632
  function discoverMemoryDirs() {
17641
17633
  const out = [];
@@ -17649,7 +17641,7 @@ function discoverMemoryDirs() {
17649
17641
  const home = homedir11();
17650
17642
  const claudeRoots = [claudeBackend.projectsDir()];
17651
17643
  try {
17652
- for (const entry of readdirSync19(home, { withFileTypes: true })) {
17644
+ for (const entry of readdirSync20(home, { withFileTypes: true })) {
17653
17645
  if (entry.isDirectory() && entry.name.startsWith(".claude-") && entry.name !== ".claude-code") {
17654
17646
  claudeRoots.push(join33(home, entry.name, "projects"));
17655
17647
  }
@@ -17660,7 +17652,7 @@ function discoverMemoryDirs() {
17660
17652
  if (!existsSync30(projectsDir))
17661
17653
  continue;
17662
17654
  try {
17663
- for (const entry of readdirSync19(projectsDir, { withFileTypes: true })) {
17655
+ for (const entry of readdirSync20(projectsDir, { withFileTypes: true })) {
17664
17656
  if (!entry.isDirectory() || entry.name.startsWith("."))
17665
17657
  continue;
17666
17658
  add(join33(projectsDir, entry.name, "memory"), entry.name);
@@ -17689,7 +17681,7 @@ var init_agent_memory_source = __esm({
17689
17681
  for (const { memoryDir, projectHash } of discoverMemoryDirs()) {
17690
17682
  const projectPath = projectHashToPath(projectHash);
17691
17683
  try {
17692
- for (const entry of readdirSync19(memoryDir, { withFileTypes: true })) {
17684
+ for (const entry of readdirSync20(memoryDir, { withFileTypes: true })) {
17693
17685
  if (!entry.isFile() || !entry.name.endsWith(".md"))
17694
17686
  continue;
17695
17687
  const filePath = join33(memoryDir, entry.name);
@@ -17792,7 +17784,7 @@ var init_agent_memory_source = __esm({
17792
17784
  });
17793
17785
 
17794
17786
  // ../engine/dist/parsers/history-source.js
17795
- import { existsSync as existsSync31, readdirSync as readdirSync20, statSync as statSync28 } from "fs";
17787
+ import { existsSync as existsSync31, readdirSync as readdirSync21, statSync as statSync28 } from "fs";
17796
17788
  import { createReadStream as createReadStream3 } from "fs";
17797
17789
  import { createInterface as createInterface2 } from "readline";
17798
17790
  import { homedir as homedir12 } from "os";
@@ -17819,7 +17811,7 @@ var init_history_source = __esm({
17819
17811
  };
17820
17812
  tryAdd(claudeBackend.historyFile());
17821
17813
  try {
17822
- for (const entry of readdirSync20(home, { withFileTypes: true })) {
17814
+ for (const entry of readdirSync21(home, { withFileTypes: true })) {
17823
17815
  if (entry.isDirectory() && entry.name.startsWith(".claude-") && entry.name !== ".claude-code") {
17824
17816
  tryAdd(join34(home, entry.name, "history.jsonl"));
17825
17817
  }
@@ -17976,7 +17968,7 @@ var init_history_source = __esm({
17976
17968
  });
17977
17969
 
17978
17970
  // ../engine/dist/parsers/paste-source.js
17979
- import { existsSync as existsSync32, readdirSync as readdirSync21, readFileSync as readFileSync24, statSync as statSync29 } from "fs";
17971
+ import { existsSync as existsSync32, readdirSync as readdirSync22, readFileSync as readFileSync24, statSync as statSync29 } from "fs";
17980
17972
  import { homedir as homedir13 } from "os";
17981
17973
  import { join as join35, basename as basename17 } from "path";
17982
17974
  var MAX_CHUNK_CHARS6, MAX_FILE_SIZE, PasteSource;
@@ -18002,7 +17994,7 @@ var init_paste_source = __esm({
18002
17994
  };
18003
17995
  tryAdd(claudeBackend.pasteCacheDir());
18004
17996
  try {
18005
- for (const entry of readdirSync21(home, { withFileTypes: true })) {
17997
+ for (const entry of readdirSync22(home, { withFileTypes: true })) {
18006
17998
  if (entry.isDirectory() && entry.name.startsWith(".claude-") && entry.name !== ".claude-code") {
18007
17999
  tryAdd(join35(home, entry.name, "paste-cache"));
18008
18000
  }
@@ -18019,7 +18011,7 @@ var init_paste_source = __esm({
18019
18011
  for (const cacheDir of this.cacheDirs) {
18020
18012
  if (!existsSync32(cacheDir))
18021
18013
  continue;
18022
- const files = readdirSync21(cacheDir).filter((f) => f.endsWith(".txt"));
18014
+ const files = readdirSync22(cacheDir).filter((f) => f.endsWith(".txt"));
18023
18015
  for (const file of files) {
18024
18016
  if (seen.has(file))
18025
18017
  continue;
@@ -18076,7 +18068,7 @@ var init_paste_source = __esm({
18076
18068
  });
18077
18069
 
18078
18070
  // ../engine/dist/parsers/gemini-source.js
18079
- import { existsSync as existsSync33, readdirSync as readdirSync22, readFileSync as readFileSync25, statSync as statSync30 } from "fs";
18071
+ import { existsSync as existsSync33, readdirSync as readdirSync23, readFileSync as readFileSync25, statSync as statSync30 } from "fs";
18080
18072
  import { join as join36, basename as basename18 } from "path";
18081
18073
  import { createHash as createHash12 } from "crypto";
18082
18074
  function loadGeminiProjectMap2() {
@@ -18118,13 +18110,13 @@ var init_gemini_source = __esm({
18118
18110
  return;
18119
18111
  const seen = /* @__PURE__ */ new Set();
18120
18112
  try {
18121
- for (const projectDirEntry of readdirSync22(tmpDir, { withFileTypes: true })) {
18113
+ for (const projectDirEntry of readdirSync23(tmpDir, { withFileTypes: true })) {
18122
18114
  if (!projectDirEntry.isDirectory())
18123
18115
  continue;
18124
18116
  const chatsDir = join36(tmpDir, projectDirEntry.name, "chats");
18125
18117
  if (!existsSync33(chatsDir))
18126
18118
  continue;
18127
- for (const file of readdirSync22(chatsDir)) {
18119
+ for (const file of readdirSync23(chatsDir)) {
18128
18120
  if (!file.endsWith(".json") || !file.startsWith("session-"))
18129
18121
  continue;
18130
18122
  const filePath = join36(chatsDir, file);
@@ -18259,7 +18251,7 @@ var init_gemini_source = __esm({
18259
18251
  });
18260
18252
 
18261
18253
  // ../engine/dist/parsers/gemini-brain-source.js
18262
- import { existsSync as existsSync34, readdirSync as readdirSync23, readFileSync as readFileSync26, statSync as statSync31 } from "fs";
18254
+ import { existsSync as existsSync34, readdirSync as readdirSync24, readFileSync as readFileSync26, statSync as statSync31 } from "fs";
18263
18255
  import { join as join37 } from "path";
18264
18256
  var MAX_CHUNK_CHARS8, GeminiBrainSource;
18265
18257
  var init_gemini_brain_source = __esm({
@@ -18280,12 +18272,12 @@ var init_gemini_brain_source = __esm({
18280
18272
  return;
18281
18273
  if (!existsSync34(this.brainDir))
18282
18274
  return;
18283
- const sessions = readdirSync23(this.brainDir, { withFileTypes: true });
18275
+ const sessions = readdirSync24(this.brainDir, { withFileTypes: true });
18284
18276
  for (const entry of sessions) {
18285
18277
  if (!entry.isDirectory())
18286
18278
  continue;
18287
18279
  const sessionDir = join37(this.brainDir, entry.name);
18288
- const files = readdirSync23(sessionDir).filter((f) => f.endsWith(".md") && !f.includes(".resolved") && !f.includes(".metadata"));
18280
+ const files = readdirSync24(sessionDir).filter((f) => f.endsWith(".md") && !f.includes(".resolved") && !f.includes(".metadata"));
18289
18281
  if (files.length === 0)
18290
18282
  continue;
18291
18283
  for (const file of files) {
@@ -18673,7 +18665,7 @@ var init_opencode_todo_source = __esm({
18673
18665
  });
18674
18666
 
18675
18667
  // ../engine/dist/parsers/codex-session-source.js
18676
- import { existsSync as existsSync37, readdirSync as readdirSync24, readFileSync as readFileSync27, statSync as statSync32 } from "fs";
18668
+ import { existsSync as existsSync37, readdirSync as readdirSync25, readFileSync as readFileSync27, statSync as statSync32 } from "fs";
18677
18669
  import { join as join38, basename as basename19 } from "path";
18678
18670
  function getCodexSessionsDir() {
18679
18671
  return codexBackend.sessionsDir();
@@ -18894,7 +18886,7 @@ var init_codex_session_source = __esm({
18894
18886
  const results = [];
18895
18887
  if (!existsSync37(dir))
18896
18888
  return results;
18897
- for (const entry of readdirSync24(dir, { withFileTypes: true })) {
18889
+ for (const entry of readdirSync25(dir, { withFileTypes: true })) {
18898
18890
  const fullPath = join38(dir, entry.name);
18899
18891
  if (entry.isDirectory()) {
18900
18892
  results.push(...this.collectJsonlFiles(fullPath));
@@ -18909,7 +18901,7 @@ var init_codex_session_source = __esm({
18909
18901
  });
18910
18902
 
18911
18903
  // ../engine/dist/parsers/diary-source.js
18912
- import { existsSync as existsSync38, mkdirSync as mkdirSync8, readdirSync as readdirSync25, readFileSync as readFileSync28, writeFileSync as writeFileSync6, statSync as statSync33 } from "fs";
18904
+ import { existsSync as existsSync38, mkdirSync as mkdirSync8, readdirSync as readdirSync26, readFileSync as readFileSync28, writeFileSync as writeFileSync6, statSync as statSync33 } from "fs";
18913
18905
  import { join as join39, basename as basename20 } from "path";
18914
18906
  var MAX_CHUNK_CHARS11, DiarySource;
18915
18907
  var init_diary_source = __esm({
@@ -18927,10 +18919,10 @@ var init_diary_source = __esm({
18927
18919
  async *discover() {
18928
18920
  if (!existsSync38(this.diaryDir))
18929
18921
  return;
18930
- const agents = readdirSync25(this.diaryDir, { withFileTypes: true }).filter((d) => d.isDirectory());
18922
+ const agents = readdirSync26(this.diaryDir, { withFileTypes: true }).filter((d) => d.isDirectory());
18931
18923
  for (const agentDir of agents) {
18932
18924
  const agentPath = join39(this.diaryDir, agentDir.name);
18933
- const files = readdirSync25(agentPath).filter((f) => f.endsWith(".json"));
18925
+ const files = readdirSync26(agentPath).filter((f) => f.endsWith(".json"));
18934
18926
  for (const file of files) {
18935
18927
  const filePath = join39(agentPath, file);
18936
18928
  try {
@@ -19021,7 +19013,7 @@ var init_diary_source = __esm({
19021
19013
  const agentDir = join39(dir, agentName.toLowerCase().replace(/[^a-z0-9_-]/g, "_"));
19022
19014
  if (!existsSync38(agentDir))
19023
19015
  return [];
19024
- const files = readdirSync25(agentDir).filter((f) => f.endsWith(".json")).sort().reverse().slice(0, lastN);
19016
+ const files = readdirSync26(agentDir).filter((f) => f.endsWith(".json")).sort().reverse().slice(0, lastN);
19025
19017
  const entries = [];
19026
19018
  for (const file of files) {
19027
19019
  try {
@@ -19070,7 +19062,7 @@ var init_redact_inline = __esm({
19070
19062
  });
19071
19063
 
19072
19064
  // ../engine/dist/parsers/skills-source.js
19073
- import { existsSync as existsSync39, readdirSync as readdirSync26, readFileSync as readFileSync29, statSync as statSync34 } from "fs";
19065
+ import { existsSync as existsSync39, readdirSync as readdirSync27, readFileSync as readFileSync29, statSync as statSync34 } from "fs";
19074
19066
  import { homedir as homedir14 } from "os";
19075
19067
  import { join as join40 } from "path";
19076
19068
  function rebuildBody(content) {
@@ -19151,7 +19143,7 @@ var init_skills_source = __esm({
19151
19143
  return;
19152
19144
  const codexPluginsDir = codexBackend.pluginsDir();
19153
19145
  if (existsSync39(codexPluginsDir)) {
19154
- for (const pluginName of readdirSync26(codexPluginsDir)) {
19146
+ for (const pluginName of readdirSync27(codexPluginsDir)) {
19155
19147
  const skillsDir = join40(codexPluginsDir, pluginName, "skills");
19156
19148
  if (!existsSync39(skillsDir))
19157
19149
  continue;
@@ -19162,7 +19154,7 @@ var init_skills_source = __esm({
19162
19154
  async *fromSkillRoot(root, pluginName) {
19163
19155
  let entries;
19164
19156
  try {
19165
- entries = readdirSync26(root.path);
19157
+ entries = readdirSync27(root.path);
19166
19158
  } catch {
19167
19159
  return;
19168
19160
  }
@@ -19196,14 +19188,14 @@ var init_skills_source = __esm({
19196
19188
  }
19197
19189
  const subdirs = {};
19198
19190
  try {
19199
- for (const sub of readdirSync26(skillDir)) {
19191
+ for (const sub of readdirSync27(skillDir)) {
19200
19192
  const subPath = join40(skillDir, sub);
19201
19193
  try {
19202
19194
  const ss = statSync34(subPath);
19203
19195
  if (ss.isDirectory()) {
19204
19196
  let count = 0;
19205
19197
  try {
19206
- count = readdirSync26(subPath).length;
19198
+ count = readdirSync27(subPath).length;
19207
19199
  } catch {
19208
19200
  }
19209
19201
  subdirs[sub] = count;
@@ -19269,7 +19261,7 @@ var init_skills_source = __esm({
19269
19261
  });
19270
19262
 
19271
19263
  // ../engine/dist/parsers/mcps-source.js
19272
- import { existsSync as existsSync40, readdirSync as readdirSync27, readFileSync as readFileSync30, statSync as statSync35 } from "fs";
19264
+ import { existsSync as existsSync40, readdirSync as readdirSync28, readFileSync as readFileSync30, statSync as statSync35 } from "fs";
19273
19265
  import { homedir as homedir15 } from "os";
19274
19266
  import { join as join41 } from "path";
19275
19267
  function readJson(path) {
@@ -19383,7 +19375,7 @@ var init_mcps_source = __esm({
19383
19375
  yield* this.fromCodexToml(codexBackend.configToml());
19384
19376
  const pluginsDir = codexBackend.pluginsDir();
19385
19377
  if (existsSync40(pluginsDir)) {
19386
- for (const plugin of readdirSync27(pluginsDir)) {
19378
+ for (const plugin of readdirSync28(pluginsDir)) {
19387
19379
  const mcpPath = join41(pluginsDir, plugin, ".mcp.json");
19388
19380
  yield* this.fromObject(readJson(mcpPath)?.mcpServers, {
19389
19381
  tool: "codex",
@@ -19590,7 +19582,7 @@ var init_toolkit_format = __esm({
19590
19582
  });
19591
19583
 
19592
19584
  // ../engine/dist/parsers/slash-commands-source.js
19593
- import { existsSync as existsSync41, readdirSync as readdirSync28, readFileSync as readFileSync31, statSync as statSync36 } from "fs";
19585
+ import { existsSync as existsSync41, readdirSync as readdirSync29, readFileSync as readFileSync31, statSync as statSync36 } from "fs";
19594
19586
  import { join as join42, basename as basename21 } from "path";
19595
19587
  function rebuildBody2(content) {
19596
19588
  const { text, redacted } = redactInlineSecrets(content);
@@ -19645,10 +19637,10 @@ var init_slash_commands_source = __esm({
19645
19637
  const projectsRoot = claudeBackend.projectsDir();
19646
19638
  if (existsSync41(projectsRoot)) {
19647
19639
  try {
19648
- for (const entry of readdirSync28(projectsRoot, { withFileTypes: true })) {
19640
+ for (const entry of readdirSync29(projectsRoot, { withFileTypes: true })) {
19649
19641
  if (!entry.isDirectory() || entry.name.startsWith("."))
19650
19642
  continue;
19651
- const projectPath = decodeProjectDirName(entry.name);
19643
+ const projectPath = resolveProjectDirName(entry.name);
19652
19644
  const cmdDir = join42(projectPath, ".claude", "commands");
19653
19645
  if (existsSync41(cmdDir))
19654
19646
  roots.push({ path: cmdDir, tool: "claude", scope: "project", projectPath, format: "md" });
@@ -19676,7 +19668,7 @@ var init_slash_commands_source = __esm({
19676
19668
  const ext = root.format === "toml" ? ".toml" : ".md";
19677
19669
  let files;
19678
19670
  try {
19679
- files = readdirSync28(root.path).filter((f) => f.endsWith(ext));
19671
+ files = readdirSync29(root.path).filter((f) => f.endsWith(ext));
19680
19672
  } catch {
19681
19673
  continue;
19682
19674
  }
@@ -19736,7 +19728,7 @@ var init_slash_commands_source = __esm({
19736
19728
  });
19737
19729
 
19738
19730
  // ../engine/dist/parsers/subagents-source.js
19739
- import { existsSync as existsSync42, readdirSync as readdirSync29, readFileSync as readFileSync32, statSync as statSync37 } from "fs";
19731
+ import { existsSync as existsSync42, readdirSync as readdirSync30, readFileSync as readFileSync32, statSync as statSync37 } from "fs";
19740
19732
  import { join as join43, basename as basename22 } from "path";
19741
19733
  function rebuildBody3(content) {
19742
19734
  const { text, redacted } = redactInlineSecrets(content);
@@ -19793,10 +19785,10 @@ var init_subagents_source = __esm({
19793
19785
  const projectsRoot = claudeBackend.projectsDir();
19794
19786
  if (existsSync42(projectsRoot)) {
19795
19787
  try {
19796
- for (const entry of readdirSync29(projectsRoot, { withFileTypes: true })) {
19788
+ for (const entry of readdirSync30(projectsRoot, { withFileTypes: true })) {
19797
19789
  if (!entry.isDirectory() || entry.name.startsWith("."))
19798
19790
  continue;
19799
- const projectPath = decodeProjectDirName(entry.name);
19791
+ const projectPath = resolveProjectDirName(entry.name);
19800
19792
  const agentDir = join43(projectPath, ".claude", "agents");
19801
19793
  if (existsSync42(agentDir))
19802
19794
  roots.push({ path: agentDir, tool: "claude", scope: "project", projectPath, format: "md" });
@@ -19824,7 +19816,7 @@ var init_subagents_source = __esm({
19824
19816
  const ext = root.format === "toml" ? ".toml" : ".md";
19825
19817
  let files;
19826
19818
  try {
19827
- files = readdirSync29(root.path).filter((f) => f.endsWith(ext));
19819
+ files = readdirSync30(root.path).filter((f) => f.endsWith(ext));
19828
19820
  } catch {
19829
19821
  continue;
19830
19822
  }
@@ -19885,7 +19877,7 @@ var init_subagents_source = __esm({
19885
19877
  });
19886
19878
 
19887
19879
  // ../engine/dist/parsers/hooks-source.js
19888
- import { existsSync as existsSync43, readFileSync as readFileSync33, readdirSync as readdirSync30, statSync as statSync38 } from "fs";
19880
+ import { existsSync as existsSync43, readFileSync as readFileSync33, readdirSync as readdirSync31, statSync as statSync38 } from "fs";
19889
19881
  import { join as join44 } from "path";
19890
19882
  function readJson2(path) {
19891
19883
  if (!existsSync43(path))
@@ -19912,10 +19904,10 @@ var init_hooks_source = __esm({
19912
19904
  const projectsRoot = claudeBackend.projectsDir();
19913
19905
  if (existsSync43(projectsRoot)) {
19914
19906
  try {
19915
- for (const entry of readdirSync30(projectsRoot, { withFileTypes: true })) {
19907
+ for (const entry of readdirSync31(projectsRoot, { withFileTypes: true })) {
19916
19908
  if (!entry.isDirectory() || entry.name.startsWith("."))
19917
19909
  continue;
19918
- const projectPath = decodeProjectDirName(entry.name);
19910
+ const projectPath = resolveProjectDirName(entry.name);
19919
19911
  const settingsPath2 = join44(projectPath, ".claude", "settings.json");
19920
19912
  if (existsSync43(settingsPath2)) {
19921
19913
  yield* this.fromSettings(settingsPath2, "project", projectPath);
@@ -20008,7 +20000,7 @@ var init_hooks_source = __esm({
20008
20000
  });
20009
20001
 
20010
20002
  // ../engine/dist/parsers/plugins-source.js
20011
- import { existsSync as existsSync44, readFileSync as readFileSync34, readdirSync as readdirSync31, statSync as statSync39 } from "fs";
20003
+ import { existsSync as existsSync44, readFileSync as readFileSync34, readdirSync as readdirSync32, statSync as statSync39 } from "fs";
20012
20004
  import { homedir as homedir16 } from "os";
20013
20005
  import { join as join45 } from "path";
20014
20006
  function readJson3(path) {
@@ -20070,7 +20062,7 @@ var init_plugins_source = __esm({
20070
20062
  if (isSourceEnabled("gemini", "extensions") && existsSync44(gemRoot)) {
20071
20063
  let entries;
20072
20064
  try {
20073
- entries = readdirSync31(gemRoot);
20065
+ entries = readdirSync32(gemRoot);
20074
20066
  } catch {
20075
20067
  entries = [];
20076
20068
  }
@@ -20118,7 +20110,7 @@ var init_plugins_source = __esm({
20118
20110
  if (isSourceEnabled("codex", "plugins") && existsSync44(codexPluginsRoot)) {
20119
20111
  let entries;
20120
20112
  try {
20121
- entries = readdirSync31(codexPluginsRoot);
20113
+ entries = readdirSync32(codexPluginsRoot);
20122
20114
  } catch {
20123
20115
  entries = [];
20124
20116
  }
@@ -20274,7 +20266,7 @@ var init_extractor_version = __esm({
20274
20266
  command: 1
20275
20267
  };
20276
20268
  TOOL_EXTRACTOR_BUMP = {
20277
- agy: 2,
20269
+ agy: 3,
20278
20270
  claude: 1,
20279
20271
  codex: 1
20280
20272
  };
@@ -20653,7 +20645,7 @@ var init_http = __esm({
20653
20645
  CLI_VERSION = JSON.parse(readFileSync37(new URL("../package.json", import.meta.url), "utf-8")).version || CLI_VERSION;
20654
20646
  } catch {
20655
20647
  try {
20656
- if (true) CLI_VERSION = "0.5.30";
20648
+ if (true) CLI_VERSION = "0.5.32";
20657
20649
  } catch {
20658
20650
  }
20659
20651
  }
@@ -21003,9 +20995,9 @@ function cooldownFor(failures) {
21003
20995
  function breakerState(serverUrl, now = Date.now()) {
21004
20996
  const s = state.get(key(serverUrl));
21005
20997
  if (!s || s.openUntil <= now) {
21006
- return { open: false, retryInMs: 0, failures: s?.failures ?? 0, lastError: s?.lastError ?? "" };
20998
+ return { open: false, retryInMs: 0, failures: s?.failures ?? 0, lastError: s?.lastError ?? "", tripped: false };
21007
20999
  }
21008
- return { open: true, retryInMs: s.openUntil - now, failures: s.failures, lastError: s.lastError };
21000
+ return { open: true, retryInMs: s.openUntil - now, failures: s.failures, lastError: s.lastError, tripped: false };
21009
21001
  }
21010
21002
  function noteTargetSuccess(serverUrl) {
21011
21003
  state.delete(key(serverUrl));
@@ -21017,11 +21009,11 @@ function noteTargetFailure(serverUrl, error, now = Date.now()) {
21017
21009
  const lastError = error.slice(0, 200);
21018
21010
  if (failures < TRIP_AFTER_FAILURES) {
21019
21011
  state.set(k, { failures, openUntil: 0, lastError });
21020
- return { open: false, retryInMs: 0, failures, lastError };
21012
+ return { open: false, retryInMs: 0, failures, lastError, tripped: false };
21021
21013
  }
21022
21014
  const cooldown = cooldownFor(failures);
21023
21015
  state.set(k, { failures, openUntil: now + cooldown, lastError });
21024
- return { open: true, retryInMs: cooldown, failures, lastError };
21016
+ return { open: true, retryInMs: cooldown, failures, lastError, tripped: failures === TRIP_AFTER_FAILURES };
21025
21017
  }
21026
21018
  function breakerNotice(serverUrl, v) {
21027
21019
  if (!v.open) return null;
@@ -21148,6 +21140,14 @@ async function flush() {
21148
21140
  }
21149
21141
  }));
21150
21142
  }
21143
+ function stableMark(value) {
21144
+ try {
21145
+ const { createHash: createHash16 } = __require("node:crypto");
21146
+ return createHash16("sha256").update(value).digest("hex").slice(0, 12);
21147
+ } catch {
21148
+ return "";
21149
+ }
21150
+ }
21151
21151
  function hashHost() {
21152
21152
  try {
21153
21153
  const { createHash: createHash16 } = __require("node:crypto");
@@ -21165,7 +21165,7 @@ var init_telemetry = __esm({
21165
21165
  init_sync_client();
21166
21166
  cliVersion2 = () => {
21167
21167
  try {
21168
- return true ? "0.5.30" : "dev";
21168
+ return true ? "0.5.32" : "dev";
21169
21169
  } catch {
21170
21170
  return "dev";
21171
21171
  }
@@ -21329,7 +21329,7 @@ __export(auto_update_exports, {
21329
21329
  import { execSync as execSync4 } from "node:child_process";
21330
21330
  import { readFileSync as readFileSync38 } from "node:fs";
21331
21331
  import { fileURLToPath as fileURLToPath2 } from "node:url";
21332
- import { writeFileSync as writeFileSync9, mkdtempSync as mkdtempSync3, rmSync as rmSync5, readdirSync as readdirSync32, statSync as statSync41 } from "node:fs";
21332
+ import { writeFileSync as writeFileSync9, mkdtempSync as mkdtempSync3, rmSync as rmSync5, readdirSync as readdirSync33, statSync as statSync41 } from "node:fs";
21333
21333
  import { join as join48, dirname as dirname18, sep as sep3 } from "node:path";
21334
21334
  import { tmpdir as tmpdir2 } from "node:os";
21335
21335
  import { createHash as createHash13 } from "node:crypto";
@@ -21374,7 +21374,7 @@ function sweepStaleStaging(root = tmpdir2(), now = Date.now()) {
21374
21374
  let removed = 0;
21375
21375
  let entries;
21376
21376
  try {
21377
- entries = readdirSync32(root);
21377
+ entries = readdirSync33(root);
21378
21378
  } catch {
21379
21379
  return 0;
21380
21380
  }
@@ -21384,7 +21384,7 @@ function sweepStaleStaging(root = tmpdir2(), now = Date.now()) {
21384
21384
  try {
21385
21385
  const st = statSync41(dir);
21386
21386
  if (!st.isDirectory() || now - st.mtimeMs < COLD_MS) continue;
21387
- const inside = readdirSync32(dir);
21387
+ const inside = readdirSync33(dir);
21388
21388
  if (inside.length > 1 || inside.length === 1 && inside[0] !== "chat-recall.tgz") continue;
21389
21389
  rmSync5(dir, { recursive: true, force: true });
21390
21390
  removed++;
@@ -21473,7 +21473,17 @@ async function runAutoUpdate(base, authHeaders, ownVersion2, deps) {
21473
21473
  }
21474
21474
  const effectiveOwn = newerOf(ownVersion2, installedVersion());
21475
21475
  const plan = planAutoUpdate(base, caps, effectiveOwn, process.env.CHAT_RECALL_AUTO_UPDATE);
21476
- if (!plan.update) return { updated: false, reason: plan.reason };
21476
+ if (!plan.update) {
21477
+ if (/disabled|no CLI release/.test(plan.reason) && !reportedStandingSkip.has(base)) {
21478
+ reportedStandingSkip.add(base);
21479
+ try {
21480
+ const { reportClientEvent: reportClientEvent3 } = await Promise.resolve().then(() => (init_client_events(), client_events_exports));
21481
+ reportClientEvent3("auto_update_skipped", { message: `${plan.reason} (server offers ${caps.cli?.version ?? "?"}, this device runs ${effectiveOwn})` });
21482
+ } catch {
21483
+ }
21484
+ }
21485
+ return { updated: false, reason: plan.reason };
21486
+ }
21477
21487
  const result = await executeAutoUpdate(plan, {
21478
21488
  download: deps?.download ?? realDownload,
21479
21489
  install: deps?.install ?? realInstall,
@@ -21489,12 +21499,13 @@ async function runAutoUpdate(base, authHeaders, ownVersion2, deps) {
21489
21499
  }
21490
21500
  return result;
21491
21501
  }
21492
- var tarballUrl;
21502
+ var tarballUrl, reportedStandingSkip;
21493
21503
  var init_auto_update = __esm({
21494
21504
  "src/auto-update.ts"() {
21495
21505
  "use strict";
21496
21506
  init_http();
21497
21507
  tarballUrl = (base) => `${base.replace(/\/+$/, "")}/install/chat-recall.tgz`;
21508
+ reportedStandingSkip = /* @__PURE__ */ new Set();
21498
21509
  }
21499
21510
  });
21500
21511
 
@@ -21510,6 +21521,9 @@ __export(sync_client_exports, {
21510
21521
  batchScanExternal: () => batchScanExternal,
21511
21522
  buildConversationSync: () => buildConversationSync,
21512
21523
  buildConversationTail: () => buildConversationTail,
21524
+ classedError: () => classedError,
21525
+ classifyError: () => classifyError,
21526
+ isStandingFailure: () => isStandingFailure,
21513
21527
  isSyncSkip: () => isSyncSkip,
21514
21528
  loadAllCredentials: () => loadAllCredentials,
21515
21529
  loadCredentials: () => loadCredentials,
@@ -21525,22 +21539,37 @@ __export(sync_client_exports, {
21525
21539
  syncSessions: () => syncSessions
21526
21540
  });
21527
21541
  import { join as join49, dirname as dirname19, basename as basename23 } from "node:path";
21528
- import { readFileSync as readFileSync39, writeFileSync as writeFileSync10, mkdirSync as mkdirSync11, mkdtempSync as mkdtempSync4, rmSync as rmSync6, chmodSync as chmodSync5, unlinkSync as unlinkSync3, readdirSync as readdirSync33, statSync as statSync42 } from "node:fs";
21542
+ import { readFileSync as readFileSync39, writeFileSync as writeFileSync10, mkdirSync as mkdirSync11, mkdtempSync as mkdtempSync4, rmSync as rmSync6, chmodSync as chmodSync5, unlinkSync as unlinkSync3, readdirSync as readdirSync34, statSync as statSync42 } from "node:fs";
21529
21543
  import { tmpdir as tmpdir3, hostname as hostname2 } from "node:os";
21530
21544
  import { createHash as createHash14 } from "node:crypto";
21531
21545
  import { fileURLToPath as fileURLToPath3 } from "node:url";
21532
21546
  import { gzipSync as gzipSync3 } from "zlib";
21533
- function classifyError(msg) {
21547
+ function classedError(errorClass, message) {
21548
+ const e = new Error(message);
21549
+ Object.defineProperty(e, ERROR_CLASS, { value: errorClass, enumerable: false });
21550
+ return e;
21551
+ }
21552
+ function taggedClass(err) {
21553
+ const v = err?.[ERROR_CLASS];
21554
+ return typeof v === "string" && v ? v : null;
21555
+ }
21556
+ function isStandingFailure(err) {
21557
+ const c = taggedClass(err);
21558
+ return c !== null && STANDING_FAILURE.has(c);
21559
+ }
21560
+ function classifyError(msg, err) {
21561
+ const tagged = taggedClass(err);
21562
+ if (tagged) return tagged;
21534
21563
  const m = msg.toLowerCase();
21535
21564
  if (m.includes("429")) return "rate_limited";
21536
21565
  if (m.includes("402")) return "payment_required";
21537
21566
  if (m.includes("401") || m.includes("403") || m.includes("token")) return "auth";
21538
- if (m.includes("timed out") || m.includes("etimedout")) return "timeout";
21567
+ if (m.includes("timed out") || m.includes("etimedout") || m.includes("aborted due to timeout")) return "timeout";
21539
21568
  if (m.includes("econnrefused")) return "refused";
21540
21569
  if (m.includes("enotfound") || m.includes("dns")) return "dns";
21541
21570
  if (m.includes("fetch failed") || m.includes("econnreset")) return "network";
21542
- if (m.includes("plain http") || m.includes("https")) return "insecure_transport";
21543
- if (/5\d\d/.test(m)) return "server_error";
21571
+ if (m.includes("over plain http") || m.includes("unsupported scheme")) return "insecure_transport";
21572
+ if (/\b5\d\d\b/.test(m)) return "server_error";
21544
21573
  return "other";
21545
21574
  }
21546
21575
  function saveCredentials(c) {
@@ -21758,17 +21787,23 @@ async function syncSessions(opts = {}) {
21758
21787
  let agg = null;
21759
21788
  const errors = [];
21760
21789
  const skippedTargets = [];
21790
+ const perTarget = {};
21761
21791
  for (const cred of targets) {
21762
21792
  const verdict = breakerState(cred.serverUrl);
21763
21793
  if (verdict.open) {
21764
21794
  const notice = breakerNotice(cred.serverUrl, verdict);
21765
21795
  if (notice) console.error(`[sync] ${notice}`);
21766
21796
  skippedTargets.push(cred.serverUrl);
21797
+ perTarget[cred.serverUrl] = {
21798
+ ok: false,
21799
+ error: notice ?? `in failure cooldown for ~${Math.max(1, Math.round(verdict.retryInMs / 6e4))}m`
21800
+ };
21767
21801
  continue;
21768
21802
  }
21769
21803
  try {
21770
21804
  const r = await syncToTarget(cred, opts);
21771
21805
  noteTargetSuccess(cred.serverUrl);
21806
+ perTarget[cred.serverUrl] = { ok: true };
21772
21807
  agg = agg ? {
21773
21808
  uploaded: agg.uploaded + r.uploaded,
21774
21809
  skipped: agg.skipped + r.skipped,
@@ -21785,14 +21820,20 @@ async function syncSessions(opts = {}) {
21785
21820
  } catch (e) {
21786
21821
  const msg = e instanceof Error ? e.message : String(e);
21787
21822
  errors.push(`${cred.serverUrl}: ${msg}`);
21823
+ perTarget[cred.serverUrl] = { ok: false, error: msg };
21788
21824
  const next = noteTargetFailure(cred.serverUrl, msg);
21789
21825
  const notice = breakerNotice(cred.serverUrl, next);
21790
21826
  if (notice) console.error(`[sync] ${notice}`);
21791
21827
  record({
21792
- kind: next.open ? "breaker_trip" : "target_failure",
21828
+ // `tripped`, not `open`: an open breaker re-opens on every attempt until
21829
+ // a success clears it, so `open` counted elapsed time. Every failure is
21830
+ // still reported — as `target_failure`, carrying the streak in
21831
+ // `failures` — so nothing becomes invisible, it just stops being counted
21832
+ // as a fresh incident.
21833
+ kind: next.tripped ? "breaker_trip" : "target_failure",
21793
21834
  failures: next.failures,
21794
21835
  retryInMs: next.retryInMs,
21795
- errorClass: classifyError(msg),
21836
+ errorClass: classifyError(msg, e),
21796
21837
  local: isLocalHost(cred.serverUrl) ? 1 : 0
21797
21838
  });
21798
21839
  }
@@ -21823,7 +21864,7 @@ async function syncSessions(opts = {}) {
21823
21864
  ${errors.join("\n ")}`);
21824
21865
  if (errors.length > 0) console.error(`[sync] ${errors.length} target(s) failed (others succeeded):
21825
21866
  ${errors.join("\n ")}`);
21826
- return agg;
21867
+ return { ...agg, perTarget };
21827
21868
  }
21828
21869
  async function postFieldBatch(base, token, rows) {
21829
21870
  const headers = { "content-type": "application/json" };
@@ -21897,7 +21938,7 @@ function reapStaleScanDirs(dir = tmpdir3(), maxAgeMs = 6 * 36e5, now = Date.now(
21897
21938
  let reaped = 0;
21898
21939
  let names;
21899
21940
  try {
21900
- names = readdirSync33(dir);
21941
+ names = readdirSync34(dir);
21901
21942
  } catch {
21902
21943
  return 0;
21903
21944
  }
@@ -22010,7 +22051,7 @@ async function syncToTarget(cred, opts = {}) {
22010
22051
  }
22011
22052
  async function syncToTargetInScope(cred, opts = {}) {
22012
22053
  const risk = transportRisk(cred.serverUrl);
22013
- if (risk) throw new Error(risk);
22054
+ if (risk) throw classedError("insecure_transport", risk);
22014
22055
  const sync = loadSettings().sync;
22015
22056
  const serverCfg = await fetchTenantSyncConfig(cred);
22016
22057
  const excludeTools = /* @__PURE__ */ new Set([...sync?.excludeTools ?? [], ...serverCfg.excludeTools]);
@@ -22110,7 +22151,7 @@ async function syncToTargetInScope(cred, opts = {}) {
22110
22151
  const retryable = res.status === 429 || res.status >= 500;
22111
22152
  const text = await res.text().catch(() => "");
22112
22153
  if (res.status === 401 || res.status === 403) {
22113
- throw new Error(`server rejected this machine's device token (HTTP ${res.status} \u2014 revoked?). Reconnect with: chat-recall login ${base}`);
22154
+ throw classedError("auth", `server rejected this machine's device token (HTTP ${res.status} \u2014 revoked?). Reconnect with: chat-recall login ${base}`);
22114
22155
  }
22115
22156
  if (res.status === 402) {
22116
22157
  let detail = text;
@@ -22124,7 +22165,7 @@ async function syncToTargetInScope(cred, opts = {}) {
22124
22165
  ${body2.upgradeUrl}`;
22125
22166
  } catch {
22126
22167
  }
22127
- throw new Error(`sync paused by the server: ${detail}`);
22168
+ throw classedError("payment_required", `sync paused by the server: ${detail}`);
22128
22169
  }
22129
22170
  if (!retryable) throw new Error(`sync failed: HTTP ${res.status} ${text}`);
22130
22171
  if (attempt >= RETRY_DELAYS_MS.length) throw new Error(`sync failed after ${attempt + 1} attempts: HTTP ${res.status} ${text}`);
@@ -22134,7 +22175,7 @@ async function syncToTargetInScope(cred, opts = {}) {
22134
22175
  await sleep(waitMs);
22135
22176
  continue;
22136
22177
  } catch (err) {
22137
- const fatal = err instanceof Error && /HTTP 4\d\d|sync failed after/.test(err.message);
22178
+ const fatal = isStandingFailure(err) || err instanceof Error && /HTTP 4\d\d|sync failed after/.test(err.message);
22138
22179
  if (fatal || attempt >= RETRY_DELAYS_MS.length) throw err;
22139
22180
  console.error(`[sync] upload attempt ${attempt + 1} failed (${err instanceof Error ? err.message : err}) \u2014 retrying in ${RETRY_DELAYS_MS[attempt] / 1e3}s`);
22140
22181
  await sleep(RETRY_DELAYS_MS[attempt]);
@@ -22673,7 +22714,12 @@ async function buildConversationSync(ref, mtime, opts = {}) {
22673
22714
  const containerBytes = built ? built.files.reduce((n, f) => n + Buffer.byteLength(f.text), 0) : 0;
22674
22715
  if (containerBytes > FULL_BUILD_MAX_BYTES) {
22675
22716
  console.error(`[sync] ${ref.prefixedId} is ${(containerBytes / 1048576).toFixed(0)}MB (over the ${(FULL_BUILD_MAX_BYTES / 1048576).toFixed(0)}MB ceiling) \u2014 shipping without the raw archive and derived data to keep the walk in memory`);
22676
- record({ kind: "oversized_session", mb: Math.round(containerBytes / 1048576), tool: ref.toolId });
22717
+ record({
22718
+ kind: "oversized_session",
22719
+ mb: Math.round(containerBytes / 1048576),
22720
+ tool: ref.toolId,
22721
+ dedupeKey: stableMark(ref.prefixedId)
22722
+ });
22677
22723
  includeRaw = false;
22678
22724
  includeMeta = false;
22679
22725
  }
@@ -22984,7 +23030,7 @@ async function syncIncremental(opts = {}) {
22984
23030
  lock.release();
22985
23031
  }
22986
23032
  }
22987
- var ownVersion, walkProgressForUpload, lastServerPackSpec, credPath, _securityConfigCache, SECURITY_CONFIG_TTL_MS, _syncConfigCache, EMPTY_SYNC_CONFIG, _fetchTenantSyncConfigForTests, SYNC_RULES_REFUSAL, hashPath, MAX_DERIVED_ROW_BYTES, isLocalHost, CAPS_TTL_MS, capsOk, advertisedIngestConc, advertisedGzipBody, FULL_BUILD_MAX_BYTES, FULL_BUILD_TAIL_BYTES, BATCH_SCAN_MAX_BYTES;
23033
+ var ownVersion, ERROR_CLASS, STANDING_FAILURE, walkProgressForUpload, lastServerPackSpec, credPath, _securityConfigCache, SECURITY_CONFIG_TTL_MS, _syncConfigCache, EMPTY_SYNC_CONFIG, _fetchTenantSyncConfigForTests, SYNC_RULES_REFUSAL, hashPath, MAX_DERIVED_ROW_BYTES, isLocalHost, CAPS_TTL_MS, capsOk, advertisedIngestConc, advertisedGzipBody, FULL_BUILD_MAX_BYTES, FULL_BUILD_TAIL_BYTES, BATCH_SCAN_MAX_BYTES;
22988
23034
  var init_sync_client = __esm({
22989
23035
  "src/sync-client.ts"() {
22990
23036
  "use strict";
@@ -23030,10 +23076,16 @@ var init_sync_client = __esm({
23030
23076
  ownVersion = JSON.parse(readFileSync39(join49(dir, "../package.json"), "utf-8")).version || ownVersion;
23031
23077
  } catch {
23032
23078
  try {
23033
- if (true) ownVersion = "0.5.30";
23079
+ if (true) ownVersion = "0.5.32";
23034
23080
  } catch {
23035
23081
  }
23036
23082
  }
23083
+ ERROR_CLASS = "__chatRecallErrorClass";
23084
+ STANDING_FAILURE = /* @__PURE__ */ new Set([
23085
+ "auth",
23086
+ "payment_required",
23087
+ "insecure_transport"
23088
+ ]);
23037
23089
  walkProgressForUpload = null;
23038
23090
  lastServerPackSpec = null;
23039
23091
  credPath = () => join49(getDataDir(), "credentials.json");
@@ -23219,7 +23271,7 @@ __export(install_skills_exports, {
23219
23271
  skillsSourceDir: () => skillsSourceDir,
23220
23272
  uninstallSkills: () => uninstallSkills
23221
23273
  });
23222
- import { readdirSync as readdirSync34, existsSync as existsSync47, mkdirSync as mkdirSync12, rmSync as rmSync7, cpSync, writeFileSync as writeFileSync12, readFileSync as readFileSync42, statSync as statSync43, realpathSync as realpathSync4 } from "fs";
23274
+ import { readdirSync as readdirSync35, existsSync as existsSync47, mkdirSync as mkdirSync12, rmSync as rmSync7, cpSync, writeFileSync as writeFileSync12, readFileSync as readFileSync42, statSync as statSync43, realpathSync as realpathSync4 } from "fs";
23223
23275
  import { createHash as createHash15 } from "crypto";
23224
23276
  import { join as join51, basename as basename24 } from "path";
23225
23277
  function skillsSourceDir() {
@@ -23245,7 +23297,7 @@ function skillsFingerprint() {
23245
23297
  }
23246
23298
  function filesUnder(dir, prefix = "") {
23247
23299
  const out = [];
23248
- for (const e of readdirSync34(dir, { withFileTypes: true })) {
23300
+ for (const e of readdirSync35(dir, { withFileTypes: true })) {
23249
23301
  if (e.name === MARKER) continue;
23250
23302
  const rel = prefix ? `${prefix}/${e.name}` : e.name;
23251
23303
  if (e.isDirectory()) out.push(...filesUnder(join51(dir, e.name), rel));
@@ -23259,7 +23311,7 @@ function skillStamp() {
23259
23311
  function bundledSkillNames() {
23260
23312
  const src = skillsSourceDir();
23261
23313
  if (!existsSync47(src)) return [];
23262
- return readdirSync34(src, { withFileTypes: true }).filter((e) => e.isDirectory() && existsSync47(join51(src, e.name, "SKILL.md"))).map((e) => e.name).sort();
23314
+ return readdirSync35(src, { withFileTypes: true }).filter((e) => e.isDirectory() && existsSync47(join51(src, e.name, "SKILL.md"))).map((e) => e.name).sort();
23263
23315
  }
23264
23316
  function realPathOrSelf(p) {
23265
23317
  try {
@@ -23351,7 +23403,7 @@ function uninstallSkills() {
23351
23403
  perTarget.push({ id: t.id, label: t.label, removed });
23352
23404
  continue;
23353
23405
  }
23354
- for (const entry of readdirSync34(t.dir, { withFileTypes: true })) {
23406
+ for (const entry of readdirSync35(t.dir, { withFileTypes: true })) {
23355
23407
  if (!entry.isDirectory()) continue;
23356
23408
  const dir = join51(t.dir, entry.name);
23357
23409
  if (isManaged(dir) && (names.has(entry.name) || entry.name.startsWith("chat-recall"))) {