chat-recall 0.7.19 → 0.7.21

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.
Files changed (40) hide show
  1. package/README.md +38 -11
  2. package/dist/board-hooks.d.ts +37 -27
  3. package/dist/board-hooks.d.ts.map +1 -1
  4. package/dist/board-hooks.js +50 -80
  5. package/dist/board-hooks.js.map +1 -1
  6. package/dist/cli.js +19101 -10520
  7. package/dist/cli.js.map +1 -1
  8. package/dist/install-hooks.d.ts +95 -0
  9. package/dist/install-hooks.d.ts.map +1 -0
  10. package/dist/install-hooks.js +352 -0
  11. package/dist/install-hooks.js.map +1 -0
  12. package/dist/install-skills.d.ts.map +1 -1
  13. package/dist/install-skills.js +2 -0
  14. package/dist/install-skills.js.map +1 -1
  15. package/dist/intent-drain.d.ts +7 -1
  16. package/dist/intent-drain.d.ts.map +1 -1
  17. package/dist/intent-drain.js +19 -3
  18. package/dist/intent-drain.js.map +1 -1
  19. package/dist/mcp-relay.js +1 -1
  20. package/dist/mcp.js +17734 -8459
  21. package/dist/mcp.js.map +1 -1
  22. package/dist/message-hook-core.d.ts +67 -0
  23. package/dist/message-hook-core.d.ts.map +1 -0
  24. package/dist/message-hook-core.js +77 -0
  25. package/dist/message-hook-core.js.map +1 -0
  26. package/dist/message-hook.d.ts +2 -0
  27. package/dist/message-hook.d.ts.map +1 -0
  28. package/dist/message-hook.js +423 -0
  29. package/dist/message-hook.js.map +1 -0
  30. package/dist/scan-worker.js +927 -192
  31. package/dist/service-installer.d.ts.map +1 -1
  32. package/dist/service-installer.js +7 -0
  33. package/dist/service-installer.js.map +1 -1
  34. package/dist/sync-client.d.ts.map +1 -1
  35. package/dist/sync-client.js +9 -3
  36. package/dist/sync-client.js.map +1 -1
  37. package/dist/watch.js +13708 -5196
  38. package/package.json +1 -1
  39. package/skills/chat-recall/SKILL.md +6 -1
  40. package/skills/chat-recall-sessions/SKILL.md +155 -0
@@ -2040,7 +2040,7 @@ var require_thread_stream = __commonJS({
2040
2040
  var { version } = require_package();
2041
2041
  var { EventEmitter } = __require("events");
2042
2042
  var { Worker } = __require("worker_threads");
2043
- var { join: join14 } = __require("path");
2043
+ var { join: join15 } = __require("path");
2044
2044
  var { pathToFileURL } = __require("url");
2045
2045
  var { wait } = require_wait();
2046
2046
  var {
@@ -2083,7 +2083,7 @@ var require_thread_stream = __commonJS({
2083
2083
  function createWorker(stream, opts) {
2084
2084
  const { filename, workerData } = opts;
2085
2085
  const bundlerOverrides = "__bundlerPathsOverrides" in globalThis ? globalThis.__bundlerPathsOverrides : {};
2086
- const toExecute = bundlerOverrides["thread-stream-worker"] || join14(__dirname, "lib", "worker.js");
2086
+ const toExecute = bundlerOverrides["thread-stream-worker"] || join15(__dirname, "lib", "worker.js");
2087
2087
  const worker = new Worker(toExecute, {
2088
2088
  ...opts.workerOpts,
2089
2089
  trackUnmanagedFds: false,
@@ -2486,7 +2486,7 @@ var require_transport = __commonJS({
2486
2486
  "use strict";
2487
2487
  var { createRequire: createRequire3 } = __require("module");
2488
2488
  var getCallers = require_caller();
2489
- var { join: join14, isAbsolute, sep } = __require("node:path");
2489
+ var { join: join15, isAbsolute: isAbsolute2, sep } = __require("node:path");
2490
2490
  var sleep = require_atomic_sleep();
2491
2491
  var onExit = require_on_exit_leak_free();
2492
2492
  var ThreadStream = require_thread_stream();
@@ -2549,7 +2549,7 @@ var require_transport = __commonJS({
2549
2549
  throw new Error("only one of target or targets can be specified");
2550
2550
  }
2551
2551
  if (targets) {
2552
- target = bundlerOverrides["pino-worker"] || join14(__dirname, "worker.js");
2552
+ target = bundlerOverrides["pino-worker"] || join15(__dirname, "worker.js");
2553
2553
  options.targets = targets.filter((dest) => dest.target).map((dest) => {
2554
2554
  return {
2555
2555
  ...dest,
@@ -2567,7 +2567,7 @@ var require_transport = __commonJS({
2567
2567
  });
2568
2568
  });
2569
2569
  } else if (pipeline) {
2570
- target = bundlerOverrides["pino-worker"] || join14(__dirname, "worker.js");
2570
+ target = bundlerOverrides["pino-worker"] || join15(__dirname, "worker.js");
2571
2571
  options.pipelines = [pipeline.map((dest) => {
2572
2572
  return {
2573
2573
  ...dest,
@@ -2585,11 +2585,11 @@ var require_transport = __commonJS({
2585
2585
  return buildStream(fixTarget(target), options, worker, sync);
2586
2586
  function fixTarget(origin) {
2587
2587
  origin = bundlerOverrides[origin] || origin;
2588
- if (isAbsolute(origin) || origin.indexOf("file://") === 0) {
2588
+ if (isAbsolute2(origin) || origin.indexOf("file://") === 0) {
2589
2589
  return origin;
2590
2590
  }
2591
2591
  if (origin === "pino/file") {
2592
- return join14(__dirname, "..", "file.js");
2592
+ return join15(__dirname, "..", "file.js");
2593
2593
  }
2594
2594
  let fixTarget2;
2595
2595
  for (const filePath of callers) {
@@ -3578,7 +3578,7 @@ var require_safe_stable_stringify = __commonJS({
3578
3578
  return circularValue;
3579
3579
  }
3580
3580
  let res = "";
3581
- let join14 = ",";
3581
+ let join15 = ",";
3582
3582
  const originalIndentation = indentation;
3583
3583
  if (Array.isArray(value)) {
3584
3584
  if (value.length === 0) {
@@ -3592,7 +3592,7 @@ var require_safe_stable_stringify = __commonJS({
3592
3592
  indentation += spacer;
3593
3593
  res += `
3594
3594
  ${indentation}`;
3595
- join14 = `,
3595
+ join15 = `,
3596
3596
  ${indentation}`;
3597
3597
  }
3598
3598
  const maximumValuesToStringify = Math.min(value.length, maximumBreadth);
@@ -3600,13 +3600,13 @@ ${indentation}`;
3600
3600
  for (; i < maximumValuesToStringify - 1; i++) {
3601
3601
  const tmp2 = stringifyFnReplacer(String(i), value, stack, replacer, spacer, indentation);
3602
3602
  res += tmp2 !== void 0 ? tmp2 : "null";
3603
- res += join14;
3603
+ res += join15;
3604
3604
  }
3605
3605
  const tmp = stringifyFnReplacer(String(i), value, stack, replacer, spacer, indentation);
3606
3606
  res += tmp !== void 0 ? tmp : "null";
3607
3607
  if (value.length - 1 > maximumBreadth) {
3608
3608
  const removedKeys = value.length - maximumBreadth - 1;
3609
- res += `${join14}"... ${getItemCount(removedKeys)} not stringified"`;
3609
+ res += `${join15}"... ${getItemCount(removedKeys)} not stringified"`;
3610
3610
  }
3611
3611
  if (spacer !== "") {
3612
3612
  res += `
@@ -3627,7 +3627,7 @@ ${originalIndentation}`;
3627
3627
  let separator = "";
3628
3628
  if (spacer !== "") {
3629
3629
  indentation += spacer;
3630
- join14 = `,
3630
+ join15 = `,
3631
3631
  ${indentation}`;
3632
3632
  whitespace = " ";
3633
3633
  }
@@ -3641,13 +3641,13 @@ ${indentation}`;
3641
3641
  const tmp = stringifyFnReplacer(key2, value, stack, replacer, spacer, indentation);
3642
3642
  if (tmp !== void 0) {
3643
3643
  res += `${separator}${strEscape(key2)}:${whitespace}${tmp}`;
3644
- separator = join14;
3644
+ separator = join15;
3645
3645
  }
3646
3646
  }
3647
3647
  if (keyLength > maximumBreadth) {
3648
3648
  const removedKeys = keyLength - maximumBreadth;
3649
3649
  res += `${separator}"...":${whitespace}"${getItemCount(removedKeys)} not stringified"`;
3650
- separator = join14;
3650
+ separator = join15;
3651
3651
  }
3652
3652
  if (spacer !== "" && separator.length > 1) {
3653
3653
  res = `
@@ -3688,7 +3688,7 @@ ${originalIndentation}`;
3688
3688
  }
3689
3689
  const originalIndentation = indentation;
3690
3690
  let res = "";
3691
- let join14 = ",";
3691
+ let join15 = ",";
3692
3692
  if (Array.isArray(value)) {
3693
3693
  if (value.length === 0) {
3694
3694
  return "[]";
@@ -3701,7 +3701,7 @@ ${originalIndentation}`;
3701
3701
  indentation += spacer;
3702
3702
  res += `
3703
3703
  ${indentation}`;
3704
- join14 = `,
3704
+ join15 = `,
3705
3705
  ${indentation}`;
3706
3706
  }
3707
3707
  const maximumValuesToStringify = Math.min(value.length, maximumBreadth);
@@ -3709,13 +3709,13 @@ ${indentation}`;
3709
3709
  for (; i < maximumValuesToStringify - 1; i++) {
3710
3710
  const tmp2 = stringifyArrayReplacer(String(i), value[i], stack, replacer, spacer, indentation);
3711
3711
  res += tmp2 !== void 0 ? tmp2 : "null";
3712
- res += join14;
3712
+ res += join15;
3713
3713
  }
3714
3714
  const tmp = stringifyArrayReplacer(String(i), value[i], stack, replacer, spacer, indentation);
3715
3715
  res += tmp !== void 0 ? tmp : "null";
3716
3716
  if (value.length - 1 > maximumBreadth) {
3717
3717
  const removedKeys = value.length - maximumBreadth - 1;
3718
- res += `${join14}"... ${getItemCount(removedKeys)} not stringified"`;
3718
+ res += `${join15}"... ${getItemCount(removedKeys)} not stringified"`;
3719
3719
  }
3720
3720
  if (spacer !== "") {
3721
3721
  res += `
@@ -3728,7 +3728,7 @@ ${originalIndentation}`;
3728
3728
  let whitespace = "";
3729
3729
  if (spacer !== "") {
3730
3730
  indentation += spacer;
3731
- join14 = `,
3731
+ join15 = `,
3732
3732
  ${indentation}`;
3733
3733
  whitespace = " ";
3734
3734
  }
@@ -3737,7 +3737,7 @@ ${indentation}`;
3737
3737
  const tmp = stringifyArrayReplacer(key2, value[key2], stack, replacer, spacer, indentation);
3738
3738
  if (tmp !== void 0) {
3739
3739
  res += `${separator}${strEscape(key2)}:${whitespace}${tmp}`;
3740
- separator = join14;
3740
+ separator = join15;
3741
3741
  }
3742
3742
  }
3743
3743
  if (spacer !== "" && separator.length > 1) {
@@ -3795,20 +3795,20 @@ ${originalIndentation}`;
3795
3795
  indentation += spacer;
3796
3796
  let res2 = `
3797
3797
  ${indentation}`;
3798
- const join15 = `,
3798
+ const join16 = `,
3799
3799
  ${indentation}`;
3800
3800
  const maximumValuesToStringify = Math.min(value.length, maximumBreadth);
3801
3801
  let i = 0;
3802
3802
  for (; i < maximumValuesToStringify - 1; i++) {
3803
3803
  const tmp2 = stringifyIndent(String(i), value[i], stack, spacer, indentation);
3804
3804
  res2 += tmp2 !== void 0 ? tmp2 : "null";
3805
- res2 += join15;
3805
+ res2 += join16;
3806
3806
  }
3807
3807
  const tmp = stringifyIndent(String(i), value[i], stack, spacer, indentation);
3808
3808
  res2 += tmp !== void 0 ? tmp : "null";
3809
3809
  if (value.length - 1 > maximumBreadth) {
3810
3810
  const removedKeys = value.length - maximumBreadth - 1;
3811
- res2 += `${join15}"... ${getItemCount(removedKeys)} not stringified"`;
3811
+ res2 += `${join16}"... ${getItemCount(removedKeys)} not stringified"`;
3812
3812
  }
3813
3813
  res2 += `
3814
3814
  ${originalIndentation}`;
@@ -3824,16 +3824,16 @@ ${originalIndentation}`;
3824
3824
  return '"[Object]"';
3825
3825
  }
3826
3826
  indentation += spacer;
3827
- const join14 = `,
3827
+ const join15 = `,
3828
3828
  ${indentation}`;
3829
3829
  let res = "";
3830
3830
  let separator = "";
3831
3831
  let maximumPropertiesToStringify = Math.min(keyLength, maximumBreadth);
3832
3832
  if (isTypedArrayWithEntries(value)) {
3833
- res += stringifyTypedArray(value, join14, maximumBreadth);
3833
+ res += stringifyTypedArray(value, join15, maximumBreadth);
3834
3834
  keys = keys.slice(value.length);
3835
3835
  maximumPropertiesToStringify -= value.length;
3836
- separator = join14;
3836
+ separator = join15;
3837
3837
  }
3838
3838
  if (deterministic) {
3839
3839
  keys = sort(keys, comparator);
@@ -3844,13 +3844,13 @@ ${indentation}`;
3844
3844
  const tmp = stringifyIndent(key2, value[key2], stack, spacer, indentation);
3845
3845
  if (tmp !== void 0) {
3846
3846
  res += `${separator}${strEscape(key2)}: ${tmp}`;
3847
- separator = join14;
3847
+ separator = join15;
3848
3848
  }
3849
3849
  }
3850
3850
  if (keyLength > maximumBreadth) {
3851
3851
  const removedKeys = keyLength - maximumBreadth;
3852
3852
  res += `${separator}"...": "${getItemCount(removedKeys)} not stringified"`;
3853
- separator = join14;
3853
+ separator = join15;
3854
3854
  }
3855
3855
  if (separator !== "") {
3856
3856
  res = `
@@ -4437,20 +4437,28 @@ var init_logger = __esm({
4437
4437
  }
4438
4438
  });
4439
4439
 
4440
- // ../engine/dist/core/paths.js
4441
- import { homedir } from "os";
4442
- import { join, dirname } from "path";
4440
+ // ../engine/dist/core/data-dir.js
4441
+ import { homedir } from "node:os";
4442
+ import { join } from "node:path";
4443
4443
  function getDataDir() {
4444
4444
  const override = process.env.CHAT_RECALL_DATA_DIR;
4445
4445
  if (override && override.trim())
4446
4446
  return override.trim();
4447
4447
  return join(homedir(), ".chat-recall");
4448
4448
  }
4449
+ var init_data_dir = __esm({
4450
+ "../engine/dist/core/data-dir.js"() {
4451
+ "use strict";
4452
+ }
4453
+ });
4454
+
4455
+ // ../engine/dist/core/paths.js
4449
4456
  var log;
4450
4457
  var init_paths = __esm({
4451
4458
  "../engine/dist/core/paths.js"() {
4452
4459
  "use strict";
4453
4460
  init_logger();
4461
+ init_data_dir();
4454
4462
  log = createLogger("paths");
4455
4463
  }
4456
4464
  });
@@ -4458,7 +4466,7 @@ var init_paths = __esm({
4458
4466
  // ../engine/dist/core/settings.js
4459
4467
  import { existsSync, mkdirSync, readFileSync, writeFileSync, chmodSync, statSync } from "fs";
4460
4468
  import { delimiter } from "path";
4461
- import { dirname as dirname2, join as join2 } from "path";
4469
+ import { dirname, join as join2 } from "path";
4462
4470
  function whichSync(bin) {
4463
4471
  const path = process.env.PATH;
4464
4472
  if (!path)
@@ -4524,7 +4532,8 @@ function defaultSourcesEnabled() {
4524
4532
  commands: true
4525
4533
  },
4526
4534
  cursor: { sessions: true, skills: true, agents: true, commands: true },
4527
- hermes: { sessions: true },
4535
+ hermes: { sessions: true, skills: true },
4536
+ pi: { sessions: true, skills: true, commands: true },
4528
4537
  shared: { skills: true },
4529
4538
  common: { mcps: true, agentMd: true }
4530
4539
  };
@@ -4596,6 +4605,7 @@ function mergeSources(base, partial) {
4596
4605
  agy: { ...base.enabled.agy, ...inherited, ...partial.enabled?.agy ?? {} },
4597
4606
  cursor: { ...base.enabled.cursor, ...partial.enabled?.cursor ?? {} },
4598
4607
  hermes: { ...base.enabled.hermes, ...partial.enabled?.hermes ?? {} },
4608
+ pi: { ...base.enabled.pi, ...partial.enabled?.pi ?? {} },
4599
4609
  shared: { ...base.enabled.shared, ...partial.enabled?.shared ?? {} },
4600
4610
  common: { ...base.enabled.common, ...partial.enabled?.common ?? {} }
4601
4611
  };
@@ -4608,6 +4618,7 @@ function mergeSources(base, partial) {
4608
4618
  cursorHome: partial.cursorHome ?? base.cursorHome,
4609
4619
  cursorIdeHome: partial.cursorIdeHome ?? base.cursorIdeHome,
4610
4620
  hermesHome: partial.hermesHome ?? base.hermesHome,
4621
+ piHome: partial.piHome ?? base.piHome,
4611
4622
  extraClaudeHomes: partial.extraClaudeHomes ?? base.extraClaudeHomes,
4612
4623
  approvedHomes: partial.approvedHomes ?? base.approvedHomes,
4613
4624
  declinedHomes: partial.declinedHomes ?? base.declinedHomes,
@@ -4704,7 +4715,7 @@ function loadSecrets() {
4704
4715
  function writeSecrets(secrets) {
4705
4716
  _secretsCache = null;
4706
4717
  const p = secretsPath();
4707
- mkdirSync(dirname2(p), { recursive: true });
4718
+ mkdirSync(dirname(p), { recursive: true });
4708
4719
  const body = "# chat-recall secrets \u2014 NOT committed/synced. Mode 0600.\n" + Object.entries(secrets).filter(([, v]) => v).map(([k, v]) => `${k}=${v}`).join("\n") + "\n";
4709
4720
  writeFileSync(p, body);
4710
4721
  try {
@@ -4774,7 +4785,7 @@ function saveSettings(settings) {
4774
4785
  }
4775
4786
  writeSecrets(secrets);
4776
4787
  const path = settingsPath();
4777
- mkdirSync(dirname2(path), { recursive: true });
4788
+ mkdirSync(dirname(path), { recursive: true });
4778
4789
  writeFileSync(path, JSON.stringify(stripped, null, 2));
4779
4790
  try {
4780
4791
  chmodSync(path, 384);
@@ -5370,6 +5381,10 @@ var init_from_events = __esm({
5370
5381
  });
5371
5382
 
5372
5383
  // ../engine/dist/transcript/raw.js
5384
+ import { getHeapStatistics } from "v8";
5385
+ function rawParseMaxBytes(heapLimit) {
5386
+ return Math.max(0, Math.min(RAW_PARSE_CEILING, Math.floor((heapLimit - RAW_PARSE_HEAP_RESERVE) / RAW_PARSE_HEAP_PER_BYTE)));
5387
+ }
5373
5388
  function redactJsonLine(line, redact) {
5374
5389
  if (!line.includes('"'))
5375
5390
  return redact(line);
@@ -5435,7 +5450,7 @@ function redactContainer(c, redact) {
5435
5450
  }))
5436
5451
  };
5437
5452
  }
5438
- var RAW_PARSE_MAX_BYTES;
5453
+ var STREAM_PIECE_CHARS, RAW_PARSE_HEAP_PER_BYTE, RAW_PARSE_HEAP_RESERVE, RAW_PARSE_CEILING, RAW_PARSE_MAX_BYTES;
5439
5454
  var init_raw = __esm({
5440
5455
  "../engine/dist/transcript/raw.js"() {
5441
5456
  "use strict";
@@ -5443,7 +5458,11 @@ var init_raw = __esm({
5443
5458
  init_claude();
5444
5459
  init_codex();
5445
5460
  init_from_events();
5446
- RAW_PARSE_MAX_BYTES = 40 * 1024 * 1024;
5461
+ STREAM_PIECE_CHARS = 1 << 20;
5462
+ RAW_PARSE_HEAP_PER_BYTE = 6;
5463
+ RAW_PARSE_HEAP_RESERVE = 128 * 1024 * 1024;
5464
+ RAW_PARSE_CEILING = 40 * 1024 * 1024;
5465
+ RAW_PARSE_MAX_BYTES = rawParseMaxBytes(getHeapStatistics().heap_size_limit);
5447
5466
  }
5448
5467
  });
5449
5468
 
@@ -5457,7 +5476,7 @@ var init_banners = __esm({
5457
5476
  // ../engine/dist/core/home-approval.js
5458
5477
  import { existsSync as existsSync2, readdirSync, realpathSync } from "fs";
5459
5478
  import { homedir as homedir2 } from "os";
5460
- import { join as join3, dirname as dirname3 } from "path";
5479
+ import { join as join3, dirname as dirname2 } from "path";
5461
5480
  function normalizeHomePath(p) {
5462
5481
  const expanded = p.startsWith("~") ? join3(homedir2(), p.slice(1)) : p;
5463
5482
  const trimmed = expanded.replace(/[/\\]+$/, "");
@@ -5487,7 +5506,7 @@ function legacyAutoSyncedHomes() {
5487
5506
  ];
5488
5507
  for (const { base, marker } of bases) {
5489
5508
  add(base, marker);
5490
- const parent = dirname3(base);
5509
+ const parent = dirname2(base);
5491
5510
  const leaf = base.slice(parent.length + 1);
5492
5511
  try {
5493
5512
  for (const e of readdirSync(parent, { withFileTypes: true })) {
@@ -5531,6 +5550,9 @@ function grandfatherLegacyHomes() {
5531
5550
  }
5532
5551
  return { seeded };
5533
5552
  }
5553
+ function defaultPiHome() {
5554
+ return join3(homedir2(), ".pi", "agent");
5555
+ }
5534
5556
  function defaultHermesHome() {
5535
5557
  if (process.platform === "win32") {
5536
5558
  const local = process.env.LOCALAPPDATA?.trim() || join3(homedir2(), "AppData", "Local");
@@ -5555,7 +5577,8 @@ function primaryHomes() {
5555
5577
  env.CHAT_RECALL_AGY_HOME || s?.agyHome || join3(home, ".gemini", "antigravity-cli"),
5556
5578
  env.CHAT_RECALL_CURSOR_HOME || s?.cursorHome || join3(home, ".cursor"),
5557
5579
  dirOf(opencodeDb),
5558
- env.CHAT_RECALL_HERMES_HOME || s?.hermesHome || env.HERMES_HOME?.trim() || defaultHermesHome()
5580
+ env.CHAT_RECALL_HERMES_HOME || s?.hermesHome || env.HERMES_HOME?.trim() || defaultHermesHome(),
5581
+ env.CHAT_RECALL_PI_HOME || s?.piHome || env.PI_CODING_AGENT_DIR?.trim() || defaultPiHome()
5559
5582
  ];
5560
5583
  return candidates.map(normalizeHomePath);
5561
5584
  }
@@ -5586,14 +5609,14 @@ var init_home_approval = __esm({
5586
5609
  "../engine/dist/core/home-approval.js"() {
5587
5610
  "use strict";
5588
5611
  init_settings();
5589
- dirOf = (filePath) => dirname3(filePath);
5612
+ dirOf = (filePath) => dirname2(filePath);
5590
5613
  }
5591
5614
  });
5592
5615
 
5593
5616
  // ../engine/dist/core/tool-paths.js
5594
- import { existsSync as existsSync3, readdirSync as readdirSync2 } from "fs";
5617
+ import { existsSync as existsSync3, readdirSync as readdirSync2, readFileSync as readFileSync2, statSync as statSync3, realpathSync as realpathSync2 } from "fs";
5595
5618
  import { homedir as homedir3 } from "os";
5596
- import { join as join4, dirname as dirname4, basename } from "path";
5619
+ import { join as join4, dirname as dirname3, basename, isAbsolute } from "path";
5597
5620
  function claudeHomeDir() {
5598
5621
  return process.env.CHAT_RECALL_CLAUDE_HOME || sources().claudeHome || join4(homedir3(), ".claude");
5599
5622
  }
@@ -5649,6 +5672,98 @@ function cursorHomeDir() {
5649
5672
  function cursorIdeHomeDir() {
5650
5673
  return process.env.CHAT_RECALL_CURSOR_IDE_HOME || sources().cursorIdeHome || (process.platform === "darwin" ? join4(homedir3(), "Library", "Application Support", "Cursor") : join4(homedir3(), ".config", "Cursor"));
5651
5674
  }
5675
+ function piHomeDir() {
5676
+ const raw = process.env.CHAT_RECALL_PI_HOME || sources().piHome || process.env.PI_CODING_AGENT_DIR?.trim();
5677
+ return raw ? expandTildePath(raw) : join4(homedir3(), ".pi", "agent");
5678
+ }
5679
+ function expandTildePath(value) {
5680
+ const t = value.trim();
5681
+ if (t === "~")
5682
+ return homedir3();
5683
+ if (t.startsWith("~/") || t.startsWith("~\\"))
5684
+ return join4(homedir3(), t.slice(2));
5685
+ return t;
5686
+ }
5687
+ function piSessionDir() {
5688
+ const override = piSessionDirEnv();
5689
+ if (override)
5690
+ return override;
5691
+ return piSessionDirForHome(piHomeDir());
5692
+ }
5693
+ function piSessionDirEnv() {
5694
+ const raw = process.env.CHAT_RECALL_PI_SESSION_DIR || process.env.PI_CODING_AGENT_SESSION_DIR?.trim();
5695
+ return raw && raw.trim() ? expandTildePath(raw) : null;
5696
+ }
5697
+ function piSessionDirForHome(home) {
5698
+ const env = piSessionDirEnv();
5699
+ if (env && sameDir(home, piHomeDir()))
5700
+ return env;
5701
+ return piSessionDirFromSettings(join4(home, "settings.json")) || join4(home, "sessions");
5702
+ }
5703
+ function sameDir(a, b) {
5704
+ if (a === b)
5705
+ return true;
5706
+ try {
5707
+ return realpathSync2(a) === realpathSync2(b);
5708
+ } catch {
5709
+ return false;
5710
+ }
5711
+ }
5712
+ function piSessionDirFromSettings(file) {
5713
+ let sig;
5714
+ try {
5715
+ sig = statSync3(file).mtimeMs;
5716
+ } catch {
5717
+ return null;
5718
+ }
5719
+ if (piSettingsCache && piSettingsCache.path === file && piSettingsCache.sig === sig) {
5720
+ return piSettingsCache.dir;
5721
+ }
5722
+ let dir = null;
5723
+ try {
5724
+ const parsed = JSON.parse(readFileSync2(file, "utf-8"));
5725
+ const value = typeof parsed.sessionDir === "string" ? parsed.sessionDir.trim() : "";
5726
+ const expanded = value ? expandTildePath(value) : "";
5727
+ dir = expanded && isAbsolute(expanded) ? expanded : null;
5728
+ } catch {
5729
+ }
5730
+ piSettingsCache = { path: file, sig, dir };
5731
+ return dir;
5732
+ }
5733
+ function piSessionDirs(opts = {}) {
5734
+ const home = piHomeDir();
5735
+ const dir = piSessionDir();
5736
+ if (!existsSync3(dir))
5737
+ return [];
5738
+ if (opts.includeExcluded)
5739
+ return [dir];
5740
+ try {
5741
+ grandfatherLegacyHomes();
5742
+ } catch {
5743
+ }
5744
+ try {
5745
+ if (!isHomeSynced(home))
5746
+ return [];
5747
+ } catch {
5748
+ }
5749
+ try {
5750
+ if (homeDecision(dir) === "declined")
5751
+ return [];
5752
+ } catch {
5753
+ }
5754
+ if (_sourceExclusionFilter && _sourceExclusionFilter(dir))
5755
+ return [];
5756
+ return [dir];
5757
+ }
5758
+ function piSkillsDir() {
5759
+ return join4(piHomeDir(), "skills");
5760
+ }
5761
+ function piPromptsDir() {
5762
+ return join4(piHomeDir(), "prompts");
5763
+ }
5764
+ function piMcpConfigPath() {
5765
+ return join4(piHomeDir(), "mcp.json");
5766
+ }
5652
5767
  function siblingHomes(base, overridden, suffix) {
5653
5768
  const roots = [];
5654
5769
  const add = (home) => {
@@ -5658,7 +5773,7 @@ function siblingHomes(base, overridden, suffix) {
5658
5773
  };
5659
5774
  add(base);
5660
5775
  if (!overridden) {
5661
- const parent = dirname4(base);
5776
+ const parent = dirname3(base);
5662
5777
  const leaf = basename(base);
5663
5778
  try {
5664
5779
  for (const entry of readdirSync2(parent, { withFileTypes: true })) {
@@ -5680,7 +5795,7 @@ function applyDecisions(roots, includeExcluded) {
5680
5795
  if (!includeExcluded) {
5681
5796
  try {
5682
5797
  grandfatherLegacyHomes();
5683
- const approved = kept.filter((r) => isHomeSynced(dirname4(r)));
5798
+ const approved = kept.filter((r) => isHomeSynced(dirname3(r)));
5684
5799
  if (approved.length > 0)
5685
5800
  kept = approved;
5686
5801
  } catch {
@@ -5731,7 +5846,7 @@ function opencodeDbPaths(opts = {}) {
5731
5846
  const primary = opencodeDbPath();
5732
5847
  const overridden = !!(process.env.CHAT_RECALL_OPENCODE_DB || sources().opencodeDbPath);
5733
5848
  const dbFile = basename(primary);
5734
- const dirs = siblingHomes(dirname4(primary), overridden, "");
5849
+ const dirs = siblingHomes(dirname3(primary), overridden, "");
5735
5850
  const dbs = [];
5736
5851
  for (const d of dirs) {
5737
5852
  const p = join4(d, dbFile);
@@ -5758,7 +5873,7 @@ function hermesDbPaths(opts = {}) {
5758
5873
  }
5759
5874
  return applyExclusions(dbs, opts.includeExcluded);
5760
5875
  }
5761
- var sources, _sourceExclusionFilter;
5876
+ var sources, _sourceExclusionFilter, piSettingsCache;
5762
5877
  var init_tool_paths = __esm({
5763
5878
  "../engine/dist/core/tool-paths.js"() {
5764
5879
  "use strict";
@@ -5766,6 +5881,7 @@ var init_tool_paths = __esm({
5766
5881
  init_settings();
5767
5882
  sources = loadSourceSettings;
5768
5883
  _sourceExclusionFilter = null;
5884
+ piSettingsCache = null;
5769
5885
  }
5770
5886
  });
5771
5887
 
@@ -5883,15 +5999,15 @@ var init_session_sentiment = __esm({
5883
5999
 
5884
6000
  // ../engine/dist/core/session-replay.js
5885
6001
  import { existsSync as existsSync4 } from "fs";
5886
- import { dirname as dirname5, resolve as pathResolve } from "path";
6002
+ import { dirname as dirname4, resolve as pathResolve } from "path";
5887
6003
  function findRepoRoot(filePath) {
5888
6004
  if (!filePath)
5889
6005
  return null;
5890
- let dir = pathResolve(dirname5(filePath));
6006
+ let dir = pathResolve(dirname4(filePath));
5891
6007
  for (let i = 0; i < 64; i++) {
5892
6008
  if (existsSync4(`${dir}/.git`))
5893
6009
  return dir;
5894
- const parent = dirname5(dir);
6010
+ const parent = dirname4(dir);
5895
6011
  if (parent === dir)
5896
6012
  return null;
5897
6013
  dir = parent;
@@ -6382,7 +6498,7 @@ var init_flat_string = __esm({
6382
6498
  // ../engine/dist/core/backends/opencode.js
6383
6499
  import { existsSync as existsSync5 } from "fs";
6384
6500
  import { homedir as homedir4 } from "os";
6385
- import { dirname as dirname6, join as join5 } from "path";
6501
+ import { dirname as dirname5, join as join5 } from "path";
6386
6502
  function openReadonly(path) {
6387
6503
  return openSqliteReadonly(path);
6388
6504
  }
@@ -6409,7 +6525,7 @@ var init_opencode = __esm({
6409
6525
  return opencodeDbPath();
6410
6526
  }
6411
6527
  homeDir() {
6412
- return dirname6(this.dbPath());
6528
+ return dirname5(this.dbPath());
6413
6529
  }
6414
6530
  // ── Subpath helpers ────────────────────────────────────────────
6415
6531
  plansDir() {
@@ -6931,7 +7047,7 @@ var init_opencode = __esm({
6931
7047
  });
6932
7048
 
6933
7049
  // ../engine/dist/core/backends/tail-read.js
6934
- import { openSync, readSync, closeSync, statSync as statSync3, fstatSync } from "node:fs";
7050
+ import { openSync, readSync, closeSync, statSync as statSync4, fstatSync } from "node:fs";
6935
7051
  function readAt(fd, pos, len) {
6936
7052
  const buf = Buffer.alloc(len);
6937
7053
  let got = 0;
@@ -6992,7 +7108,7 @@ function linesBeforeOffset(path, offset) {
6992
7108
  function readTailFromOffset(path, offset, maxBytes = TAIL_READ_MAX_BYTES) {
6993
7109
  let size = 0;
6994
7110
  try {
6995
- size = statSync3(path).size;
7111
+ size = statSync4(path).size;
6996
7112
  } catch {
6997
7113
  return { text: "", newOffset: offset };
6998
7114
  }
@@ -7042,7 +7158,7 @@ function readSourcesFromOffset(paths, offset, maxBytes = TAIL_READ_MAX_BYTES) {
7042
7158
  const path = paths[i];
7043
7159
  let size = 0;
7044
7160
  try {
7045
- size = statSync3(path).size;
7161
+ size = statSync4(path).size;
7046
7162
  } catch {
7047
7163
  size = 0;
7048
7164
  }
@@ -7127,8 +7243,8 @@ var init_tail_read = __esm({
7127
7243
  });
7128
7244
 
7129
7245
  // ../engine/dist/core/backends/codex.js
7130
- import { readdirSync as readdirSync3, readFileSync as readFileSync2, statSync as statSync4, openSync as openSync2, readSync as readSync2, closeSync as closeSync2 } from "fs";
7131
- import { basename as basename4, dirname as dirname7, join as join6 } from "path";
7246
+ import { readdirSync as readdirSync3, readFileSync as readFileSync3, statSync as statSync5, openSync as openSync2, readSync as readSync2, closeSync as closeSync2 } from "fs";
7247
+ import { basename as basename4, dirname as dirname6, join as join6 } from "path";
7132
7248
  function parseShellWrites(cmd) {
7133
7249
  const out = [];
7134
7250
  const firstLine = cmd.split("\n", 1)[0].trim();
@@ -7256,7 +7372,7 @@ function flattenContent(content) {
7256
7372
  }
7257
7373
  function readFirstLine(path) {
7258
7374
  try {
7259
- const head = readFileSync2(path, "utf-8").split("\n", 1)[0] || "";
7375
+ const head = readFileSync3(path, "utf-8").split("\n", 1)[0] || "";
7260
7376
  if (!head)
7261
7377
  return null;
7262
7378
  return JSON.parse(head);
@@ -7362,7 +7478,7 @@ var init_codex2 = __esm({
7362
7478
  return null;
7363
7479
  let mtime = 0;
7364
7480
  try {
7365
- mtime = statSync4(located.path).mtimeMs;
7481
+ mtime = statSync5(located.path).mtimeMs;
7366
7482
  } catch {
7367
7483
  }
7368
7484
  return {
@@ -7382,7 +7498,7 @@ var init_codex2 = __esm({
7382
7498
  for (const filePath of walkRollouts(root)) {
7383
7499
  let stat;
7384
7500
  try {
7385
- stat = statSync4(filePath);
7501
+ stat = statSync5(filePath);
7386
7502
  } catch {
7387
7503
  continue;
7388
7504
  }
@@ -7402,7 +7518,7 @@ var init_codex2 = __esm({
7402
7518
  let messageCount = 0;
7403
7519
  if (opts.previews !== false)
7404
7520
  try {
7405
- const lines = readFileSync2(filePath, "utf-8").split("\n");
7521
+ const lines = readFileSync3(filePath, "utf-8").split("\n");
7406
7522
  for (const line of lines) {
7407
7523
  if (!line.trim())
7408
7524
  continue;
@@ -7554,7 +7670,7 @@ var init_codex2 = __esm({
7554
7670
  continue;
7555
7671
  let firstLine = "";
7556
7672
  try {
7557
- firstLine = readFileSync2(path, "utf-8").split("\n", 1)[0] || "";
7673
+ firstLine = readFileSync3(path, "utf-8").split("\n", 1)[0] || "";
7558
7674
  } catch {
7559
7675
  continue;
7560
7676
  }
@@ -7578,8 +7694,8 @@ var init_codex2 = __esm({
7578
7694
  let raw = "";
7579
7695
  let mtime = 0;
7580
7696
  try {
7581
- raw = readFileSync2(path, "utf-8");
7582
- mtime = statSync4(path).mtimeMs;
7697
+ raw = readFileSync3(path, "utf-8");
7698
+ mtime = statSync5(path).mtimeMs;
7583
7699
  } catch {
7584
7700
  return [];
7585
7701
  }
@@ -7679,7 +7795,7 @@ var init_codex2 = __esm({
7679
7795
  const events = this.readEvents(this.toRawId(id));
7680
7796
  let fileMtime = 0;
7681
7797
  try {
7682
- fileMtime = statSync4(located.path).mtimeMs;
7798
+ fileMtime = statSync5(located.path).mtimeMs;
7683
7799
  } catch {
7684
7800
  }
7685
7801
  return liveScanEditsFromEvents(events, this.fileToolMap, {
@@ -7743,7 +7859,7 @@ var init_codex2 = __esm({
7743
7859
  const p = join6(dir, entry.name);
7744
7860
  let st;
7745
7861
  try {
7746
- st = statSync4(p);
7862
+ st = statSync5(p);
7747
7863
  } catch {
7748
7864
  continue;
7749
7865
  }
@@ -7755,7 +7871,7 @@ var init_codex2 = __esm({
7755
7871
  let parentId = null;
7756
7872
  let isSubagent = false;
7757
7873
  try {
7758
- const first = readFileSync2(p, "utf-8").split("\n")[0];
7874
+ const first = readFileSync3(p, "utf-8").split("\n")[0];
7759
7875
  if (first) {
7760
7876
  const meta = JSON.parse(first);
7761
7877
  const payload = meta?.payload || {};
@@ -7810,8 +7926,8 @@ var init_codex2 = __esm({
7810
7926
  let mtime = 0;
7811
7927
  const push = (path, name) => {
7812
7928
  try {
7813
- const st = statSync4(path);
7814
- files.push({ name, bytes: readFileSync2(path) });
7929
+ const st = statSync5(path);
7930
+ files.push({ name, bytes: readFileSync3(path) });
7815
7931
  if (st.mtimeMs > mtime)
7816
7932
  mtime = st.mtimeMs;
7817
7933
  } catch {
@@ -7820,7 +7936,7 @@ var init_codex2 = __esm({
7820
7936
  push(loc.path, basename4(loc.path));
7821
7937
  const parentId = basename4(loc.path).match(/([a-f0-9-]{36})\.jsonl$/i)?.[1];
7822
7938
  if (parentId) {
7823
- const dayDir = dirname7(loc.path);
7939
+ const dayDir = dirname6(loc.path);
7824
7940
  try {
7825
7941
  for (const f of readdirSync3(dayDir)) {
7826
7942
  if (!f.endsWith(".jsonl") || !f.startsWith("rollout-"))
@@ -7852,7 +7968,7 @@ var init_codex2 = __esm({
7852
7968
  if (!loc)
7853
7969
  return 0;
7854
7970
  try {
7855
- return statSync4(loc.path).size;
7971
+ return statSync5(loc.path).size;
7856
7972
  } catch {
7857
7973
  return 0;
7858
7974
  }
@@ -7869,8 +7985,8 @@ var init_codex2 = __esm({
7869
7985
  });
7870
7986
 
7871
7987
  // ../engine/dist/core/backends/agy.js
7872
- import { existsSync as existsSync6, readdirSync as readdirSync4, readFileSync as readFileSync3, statSync as statSync5 } from "fs";
7873
- import { basename as basename5, dirname as dirname8, join as join7 } from "path";
7988
+ import { existsSync as existsSync6, readdirSync as readdirSync4, readFileSync as readFileSync4, statSync as statSync6 } from "fs";
7989
+ import { basename as basename5, dirname as dirname7, join as join7 } from "path";
7874
7990
  function agyTranscriptPath(logsDir) {
7875
7991
  const full = join7(logsDir, "transcript_full.jsonl");
7876
7992
  if (existsSync6(full))
@@ -7889,7 +8005,7 @@ function resolveAgyProject(logsDir, homeDir) {
7889
8005
  function extractProjectPathFromTranscript(path, homeDir) {
7890
8006
  let content;
7891
8007
  try {
7892
- content = readFileSync3(path, "utf-8");
8008
+ content = readFileSync4(path, "utf-8");
7893
8009
  } catch {
7894
8010
  return "";
7895
8011
  }
@@ -8062,10 +8178,10 @@ var init_agy = __esm({
8062
8178
  return null;
8063
8179
  let mtime = 0;
8064
8180
  try {
8065
- mtime = statSync5(path).mtimeMs;
8181
+ mtime = statSync6(path).mtimeMs;
8066
8182
  } catch {
8067
8183
  }
8068
- const projectPath = resolveAgyProject(dirname8(path), this.homeDir());
8184
+ const projectPath = resolveAgyProject(dirname7(path), this.homeDir());
8069
8185
  const projectDir = projectPath ? basename5(projectPath) : "";
8070
8186
  return {
8071
8187
  path,
@@ -8090,7 +8206,7 @@ var init_agy = __esm({
8090
8206
  for (const rawId of sessionDirs) {
8091
8207
  const sessionPath = join7(brainDir, rawId);
8092
8208
  try {
8093
- if (!statSync5(sessionPath).isDirectory())
8209
+ if (!statSync6(sessionPath).isDirectory())
8094
8210
  continue;
8095
8211
  } catch {
8096
8212
  continue;
@@ -8100,13 +8216,13 @@ var init_agy = __esm({
8100
8216
  continue;
8101
8217
  let stat;
8102
8218
  try {
8103
- stat = statSync5(filePath);
8219
+ stat = statSync6(filePath);
8104
8220
  } catch {
8105
8221
  continue;
8106
8222
  }
8107
8223
  if (stat.mtimeMs < cutoff)
8108
8224
  continue;
8109
- const projectPath = resolveAgyProject(dirname8(filePath), this.homeDir());
8225
+ const projectPath = resolveAgyProject(dirname7(filePath), this.homeDir());
8110
8226
  if (filter && (!projectPath || !projectPath.toLowerCase().includes(filter)))
8111
8227
  continue;
8112
8228
  const projectDir = projectPath ? basename5(projectPath) : "";
@@ -8114,7 +8230,7 @@ var init_agy = __esm({
8114
8230
  let messageCount = 0;
8115
8231
  if (opts.previews !== false)
8116
8232
  try {
8117
- const lines = readFileSync3(filePath, "utf-8").split("\n").filter(Boolean);
8233
+ const lines = readFileSync4(filePath, "utf-8").split("\n").filter(Boolean);
8118
8234
  messageCount = lines.length;
8119
8235
  for (const line of lines) {
8120
8236
  const obj = JSON.parse(line);
@@ -8204,7 +8320,7 @@ var init_agy = __esm({
8204
8320
  return [];
8205
8321
  let rawText;
8206
8322
  try {
8207
- rawText = readFileSync3(located.path, "utf-8");
8323
+ rawText = readFileSync4(located.path, "utf-8");
8208
8324
  } catch {
8209
8325
  return [];
8210
8326
  }
@@ -8366,7 +8482,7 @@ var init_agy = __esm({
8366
8482
  for (const rawId of sessionDirs) {
8367
8483
  const sessionPath = join7(brainDir, rawId);
8368
8484
  try {
8369
- if (!statSync5(sessionPath).isDirectory())
8485
+ if (!statSync6(sessionPath).isDirectory())
8370
8486
  continue;
8371
8487
  } catch {
8372
8488
  continue;
@@ -8375,7 +8491,7 @@ var init_agy = __esm({
8375
8491
  if (!filePath)
8376
8492
  continue;
8377
8493
  try {
8378
- const st = statSync5(filePath);
8494
+ const st = statSync6(filePath);
8379
8495
  if (st.mtimeMs < opts.sinceMs)
8380
8496
  continue;
8381
8497
  candidates.push({ rawId, mtime: st.mtimeMs });
@@ -8403,8 +8519,8 @@ var init_agy = __esm({
8403
8519
  try {
8404
8520
  return {
8405
8521
  tool: "agy",
8406
- mtime: statSync5(loc.path).mtimeMs,
8407
- files: [{ name: basename5(loc.path), bytes: readFileSync3(loc.path) }]
8522
+ mtime: statSync6(loc.path).mtimeMs,
8523
+ files: [{ name: basename5(loc.path), bytes: readFileSync4(loc.path) }]
8408
8524
  };
8409
8525
  } catch {
8410
8526
  return null;
@@ -8418,7 +8534,7 @@ var init_agy = __esm({
8418
8534
  if (!loc)
8419
8535
  return 0;
8420
8536
  try {
8421
- return statSync5(loc.path).size;
8537
+ return statSync6(loc.path).size;
8422
8538
  } catch {
8423
8539
  return 0;
8424
8540
  }
@@ -8435,7 +8551,7 @@ var init_agy = __esm({
8435
8551
  });
8436
8552
 
8437
8553
  // ../engine/dist/core/backends/cursor-store.js
8438
- import { existsSync as existsSync7, readdirSync as readdirSync5, readFileSync as readFileSync4, statSync as statSync6 } from "fs";
8554
+ import { existsSync as existsSync7, readdirSync as readdirSync5, readFileSync as readFileSync5, statSync as statSync7 } from "fs";
8439
8555
  import { join as join8 } from "path";
8440
8556
  function cursorProjectSlug(absPath) {
8441
8557
  return absPath.replace(/[^a-zA-Z0-9]/g, "-").replace(/-+/g, "-").replace(/^-+|-+$/g, "");
@@ -8452,7 +8568,7 @@ function listChatsIn(chatsRoot) {
8452
8568
  const hashPath = join8(chatsRoot, workspaceHash);
8453
8569
  let chatIds;
8454
8570
  try {
8455
- if (!statSync6(hashPath).isDirectory())
8571
+ if (!statSync7(hashPath).isDirectory())
8456
8572
  continue;
8457
8573
  chatIds = readdirSync5(hashPath);
8458
8574
  } catch {
@@ -8465,7 +8581,7 @@ function listChatsIn(chatsRoot) {
8465
8581
  continue;
8466
8582
  let meta = {};
8467
8583
  try {
8468
- meta = JSON.parse(readFileSync4(join8(dir, "meta.json"), "utf-8"));
8584
+ meta = JSON.parse(readFileSync5(join8(dir, "meta.json"), "utf-8"));
8469
8585
  } catch {
8470
8586
  }
8471
8587
  if (meta.hasConversation === false)
@@ -8474,7 +8590,7 @@ function listChatsIn(chatsRoot) {
8474
8590
  let created = meta.createdAtMs ?? 0;
8475
8591
  if (!mtime || !created) {
8476
8592
  try {
8477
- const st = statSync6(dbPath);
8593
+ const st = statSync7(dbPath);
8478
8594
  mtime = mtime || st.mtimeMs;
8479
8595
  created = created || st.birthtimeMs || st.mtimeMs;
8480
8596
  } catch {
@@ -8510,14 +8626,14 @@ function findChat(chatsRoots, chatId) {
8510
8626
  continue;
8511
8627
  let meta = {};
8512
8628
  try {
8513
- meta = JSON.parse(readFileSync4(join8(dir, "meta.json"), "utf-8"));
8629
+ meta = JSON.parse(readFileSync5(join8(dir, "meta.json"), "utf-8"));
8514
8630
  } catch {
8515
8631
  }
8516
8632
  let mtime = meta.updatedAtMs ?? 0;
8517
8633
  let created = meta.createdAtMs ?? 0;
8518
8634
  if (!mtime || !created) {
8519
8635
  try {
8520
- const st = statSync6(dbPath);
8636
+ const st = statSync7(dbPath);
8521
8637
  mtime = mtime || st.mtimeMs;
8522
8638
  created = created || st.birthtimeMs || st.mtimeMs;
8523
8639
  } catch {
@@ -8820,8 +8936,8 @@ var init_cursor_store = __esm({
8820
8936
  });
8821
8937
 
8822
8938
  // ../engine/dist/core/backends/cursor-ide.js
8823
- import { existsSync as existsSync8, readFileSync as readFileSync5, readdirSync as readdirSync6, statSync as statSync7 } from "fs";
8824
- import { dirname as dirname9, join as join9 } from "path";
8939
+ import { existsSync as existsSync8, readFileSync as readFileSync6, readdirSync as readdirSync6, statSync as statSync8 } from "fs";
8940
+ import { dirname as dirname8, join as join9 } from "path";
8825
8941
  function jsonOf(value) {
8826
8942
  if (value == null)
8827
8943
  return null;
@@ -8873,7 +8989,7 @@ function projectPathForWorkspace(workspaceDir) {
8873
8989
  }
8874
8990
  function safeRead(path) {
8875
8991
  try {
8876
- return readFileSync5(path, "utf-8");
8992
+ return readFileSync6(path, "utf-8");
8877
8993
  } catch {
8878
8994
  return null;
8879
8995
  }
@@ -8890,7 +9006,7 @@ function workspaceIndex(workspaceRoots) {
8890
9006
  for (const id of entries) {
8891
9007
  const dir = join9(root, id);
8892
9008
  try {
8893
- if (!statSync7(dir).isDirectory())
9009
+ if (!statSync8(dir).isDirectory())
8894
9010
  continue;
8895
9011
  } catch {
8896
9012
  continue;
@@ -9236,7 +9352,7 @@ var init_cursor_ide = __esm({
9236
9352
  });
9237
9353
 
9238
9354
  // ../engine/dist/core/backends/cursor.js
9239
- import { existsSync as existsSync9, readFileSync as readFileSync6, statSync as statSync8 } from "fs";
9355
+ import { existsSync as existsSync9, readFileSync as readFileSync7, statSync as statSync9 } from "fs";
9240
9356
  import { join as join10 } from "path";
9241
9357
  var PREFIX4, CursorBackend, cursorBackend;
9242
9358
  var init_cursor = __esm({
@@ -9289,7 +9405,7 @@ var init_cursor = __esm({
9289
9405
  if (r.surface === "cli") {
9290
9406
  let mtime2 = r.chat.updatedAtMs;
9291
9407
  try {
9292
- mtime2 = statSync8(r.chat.dbPath).mtimeMs || mtime2;
9408
+ mtime2 = statSync9(r.chat.dbPath).mtimeMs || mtime2;
9293
9409
  } catch {
9294
9410
  }
9295
9411
  return {
@@ -9302,7 +9418,7 @@ var init_cursor = __esm({
9302
9418
  }
9303
9419
  let mtime = r.composer.updatedAtMs;
9304
9420
  try {
9305
- mtime = statSync8(r.composer.globalDbPath).mtimeMs || mtime;
9421
+ mtime = statSync9(r.composer.globalDbPath).mtimeMs || mtime;
9306
9422
  } catch {
9307
9423
  }
9308
9424
  return {
@@ -9460,7 +9576,7 @@ var init_cursor = __esm({
9460
9576
  if (!jsonl)
9461
9577
  return [];
9462
9578
  try {
9463
- return readTranscriptEvents(readFileSync6(jsonl, "utf-8"), chat.updatedAtMs);
9579
+ return readTranscriptEvents(readFileSync7(jsonl, "utf-8"), chat.updatedAtMs);
9464
9580
  } catch {
9465
9581
  return [];
9466
9582
  }
@@ -9546,9 +9662,9 @@ var init_cursor = __esm({
9546
9662
  const files = [{ name: `${r.chat.chatId}.jsonl`, bytes: Buffer.from(lines, "utf8") }];
9547
9663
  const metaPath = join10(r.chat.dir, "meta.json");
9548
9664
  if (existsSync9(metaPath)) {
9549
- files.push({ name: "meta.json", bytes: readFileSync6(metaPath) });
9665
+ files.push({ name: "meta.json", bytes: readFileSync7(metaPath) });
9550
9666
  }
9551
- return { tool: "cursor", mtime: statSync8(r.chat.dbPath).mtimeMs, files };
9667
+ return { tool: "cursor", mtime: statSync9(r.chat.dbPath).mtimeMs, files };
9552
9668
  }
9553
9669
  const events = readComposerEvents(r.composer);
9554
9670
  if (events.length === 0)
@@ -9556,7 +9672,7 @@ var init_cursor = __esm({
9556
9672
  const body = events.map((e) => JSON.stringify(e)).join("\n") + "\n";
9557
9673
  return {
9558
9674
  tool: "cursor",
9559
- mtime: statSync8(r.composer.globalDbPath).mtimeMs,
9675
+ mtime: statSync9(r.composer.globalDbPath).mtimeMs,
9560
9676
  files: [{ name: `${r.composer.composerId}.jsonl`, bytes: Buffer.from(body, "utf8") }]
9561
9677
  };
9562
9678
  } catch {
@@ -9568,7 +9684,7 @@ var init_cursor = __esm({
9568
9684
  if (!p)
9569
9685
  return "";
9570
9686
  try {
9571
- return readFileSync6(p, "utf-8");
9687
+ return readFileSync7(p, "utf-8");
9572
9688
  } catch {
9573
9689
  return "";
9574
9690
  }
@@ -10045,6 +10161,623 @@ var init_hermes = __esm({
10045
10161
  }
10046
10162
  });
10047
10163
 
10164
+ // ../engine/dist/core/backends/pi.js
10165
+ import { readdirSync as readdirSync7, readFileSync as readFileSync8, statSync as statSync10, openSync as openSync3, readSync as readSync3, closeSync as closeSync3 } from "fs";
10166
+ import { createHash } from "crypto";
10167
+ import { basename as basename6, join as join11 } from "path";
10168
+ function parsePiFile(path) {
10169
+ let raw;
10170
+ try {
10171
+ raw = readFileSync8(path, "utf-8");
10172
+ } catch {
10173
+ return { header: null, entries: [] };
10174
+ }
10175
+ const out = { header: null, entries: [] };
10176
+ for (const line of raw.split("\n")) {
10177
+ if (!line.trim())
10178
+ continue;
10179
+ let obj;
10180
+ try {
10181
+ obj = JSON.parse(line);
10182
+ } catch {
10183
+ continue;
10184
+ }
10185
+ if (!obj || typeof obj !== "object")
10186
+ continue;
10187
+ if (obj.type === "session" && !out.header) {
10188
+ out.header = obj;
10189
+ continue;
10190
+ }
10191
+ out.entries.push(obj);
10192
+ }
10193
+ return out;
10194
+ }
10195
+ function idFromFilename(file) {
10196
+ if (!file.endsWith(".jsonl"))
10197
+ return null;
10198
+ const stem = file.slice(0, -".jsonl".length);
10199
+ const at = stem.indexOf("_");
10200
+ const id = at === -1 ? stem : stem.slice(at + 1);
10201
+ return id || null;
10202
+ }
10203
+ function* walkSessionFiles(root, depth = 2) {
10204
+ if (depth < 0)
10205
+ return;
10206
+ let entries;
10207
+ try {
10208
+ entries = readdirSync7(root, { withFileTypes: true });
10209
+ } catch {
10210
+ return;
10211
+ }
10212
+ for (const entry of entries) {
10213
+ if (entry.name.startsWith("."))
10214
+ continue;
10215
+ const path = join11(root, entry.name);
10216
+ if (entry.isDirectory()) {
10217
+ yield* walkSessionFiles(path, depth - 1);
10218
+ continue;
10219
+ }
10220
+ if (entry.isFile() && entry.name.endsWith(".jsonl"))
10221
+ yield path;
10222
+ }
10223
+ }
10224
+ function readPiHeader(path) {
10225
+ let fd = null;
10226
+ try {
10227
+ fd = openSync3(path, "r");
10228
+ const buf = Buffer.alloc(8192);
10229
+ const n = readSync3(fd, buf, 0, buf.length, 0);
10230
+ const firstLine = buf.toString("utf-8", 0, n).split("\n", 1)[0];
10231
+ if (!firstLine.trim())
10232
+ return null;
10233
+ const obj = JSON.parse(firstLine);
10234
+ if (!obj || typeof obj !== "object" || obj.type !== "session")
10235
+ return null;
10236
+ return obj;
10237
+ } catch {
10238
+ return null;
10239
+ } finally {
10240
+ if (fd !== null) {
10241
+ try {
10242
+ closeSync3(fd);
10243
+ } catch {
10244
+ }
10245
+ }
10246
+ }
10247
+ }
10248
+ function dirSignature(root) {
10249
+ const parts = [];
10250
+ try {
10251
+ parts.push(String(statSync10(root).mtimeMs));
10252
+ } catch {
10253
+ return "missing";
10254
+ }
10255
+ let entries = [];
10256
+ try {
10257
+ entries = readdirSync7(root, { withFileTypes: true });
10258
+ } catch {
10259
+ return parts.join(",");
10260
+ }
10261
+ for (const entry of entries) {
10262
+ if (!entry.isDirectory())
10263
+ continue;
10264
+ try {
10265
+ parts.push(`${entry.name}:${statSync10(join11(root, entry.name)).mtimeMs}`);
10266
+ } catch {
10267
+ }
10268
+ }
10269
+ parts.sort();
10270
+ return parts.join(",");
10271
+ }
10272
+ function piSessionKey(file) {
10273
+ return `${file.id}~${projectSuffix(file.projectPath || file.projectDir)}`;
10274
+ }
10275
+ function projectSuffix(projectDir) {
10276
+ return createHash("sha256").update(projectDir).digest("hex").slice(0, 8);
10277
+ }
10278
+ function mtimeOf(path, fallback) {
10279
+ try {
10280
+ return statSync10(path).mtimeMs;
10281
+ } catch {
10282
+ return fallback;
10283
+ }
10284
+ }
10285
+ function piText(content) {
10286
+ if (typeof content === "string")
10287
+ return content;
10288
+ if (!Array.isArray(content))
10289
+ return "";
10290
+ const parts = [];
10291
+ for (const block of content) {
10292
+ if (!block || typeof block !== "object")
10293
+ continue;
10294
+ const b = block;
10295
+ if (b.type === "text" && typeof b.text === "string")
10296
+ parts.push(b.text);
10297
+ }
10298
+ return parts.join("\n");
10299
+ }
10300
+ function piToolInput(args) {
10301
+ return args && typeof args === "object" && !Array.isArray(args) ? { ...args } : {};
10302
+ }
10303
+ var PREFIX6, PiBackend, piBackend;
10304
+ var init_pi = __esm({
10305
+ "../engine/dist/core/backends/pi.js"() {
10306
+ "use strict";
10307
+ init_tail_read();
10308
+ init_tool_paths();
10309
+ init_session_outcome();
10310
+ init_session_git();
10311
+ init_generic_engine();
10312
+ init_flat_string();
10313
+ PREFIX6 = "pi_";
10314
+ PiBackend = class {
10315
+ id = "pi";
10316
+ idPrefix = PREFIX6;
10317
+ displayName = "Pi";
10318
+ homeDir() {
10319
+ return piHomeDir();
10320
+ }
10321
+ /** Session root(s) — Pi has a single agent dir, so this is one entry. */
10322
+ sessionDirs() {
10323
+ return piSessionDirs();
10324
+ }
10325
+ skillsDir() {
10326
+ return piSkillsDir();
10327
+ }
10328
+ promptsDir() {
10329
+ return piPromptsDir();
10330
+ }
10331
+ mcpConfigPath() {
10332
+ return piMcpConfigPath();
10333
+ }
10334
+ isAvailable() {
10335
+ return this.sessionDirs().length > 0;
10336
+ }
10337
+ // ── ID handling ────────────────────────────────────────────────
10338
+ matchesId(id) {
10339
+ return id.startsWith(PREFIX6);
10340
+ }
10341
+ /**
10342
+ * A Pi id can itself start with `<prefix>` (`--session-id` allows `_`), so the
10343
+ * bare prefix does not identify a stored id. The index does.
10344
+ */
10345
+ toRawId(id) {
10346
+ if (!id.startsWith(PREFIX6))
10347
+ return id;
10348
+ if (this.fileIndex().has(id))
10349
+ return id;
10350
+ return id.slice(PREFIX6.length);
10351
+ }
10352
+ toPrefixedId(rawId) {
10353
+ if (!rawId.startsWith(PREFIX6))
10354
+ return PREFIX6 + rawId;
10355
+ return this.fileIndex().has(rawId) ? PREFIX6 + rawId : rawId;
10356
+ }
10357
+ // ── Location ───────────────────────────────────────────────────
10358
+ /**
10359
+ * Session key → file path for every session on this machine.
10360
+ *
10361
+ * The entry list is cached on the project dirs. When two files carry one key
10362
+ * — a copy of a session — this stats them on every call, because an append to
10363
+ * the live file changes its mtime and not its folder.
10364
+ */
10365
+ fileIndex() {
10366
+ const roots = this.sessionDirs();
10367
+ const signature = roots.map(dirSignature).join("|");
10368
+ if (this._index?.signature !== signature) {
10369
+ const entries2 = [];
10370
+ for (const root of roots) {
10371
+ for (const path of walkSessionFiles(root)) {
10372
+ let mtime = 0;
10373
+ try {
10374
+ mtime = statSync10(path).mtimeMs;
10375
+ } catch {
10376
+ continue;
10377
+ }
10378
+ const header = readPiHeader(path);
10379
+ const id = header ? header.id || idFromFilename(basename6(path)) : "";
10380
+ entries2.push({
10381
+ id: id || "",
10382
+ projectPath: header?.cwd || "",
10383
+ projectDir: basename6(join11(path, "..")),
10384
+ mtime,
10385
+ path
10386
+ });
10387
+ }
10388
+ }
10389
+ this._index = { signature, entries: entries2 };
10390
+ }
10391
+ const entries = this._index.entries;
10392
+ const seen = /* @__PURE__ */ new Map();
10393
+ for (const entry of entries) {
10394
+ if (!entry.id) {
10395
+ const header = readPiHeader(entry.path);
10396
+ if (!header)
10397
+ continue;
10398
+ entry.id = header.id || idFromFilename(basename6(entry.path)) || "";
10399
+ entry.projectPath = header.cwd || "";
10400
+ if (!entry.id)
10401
+ continue;
10402
+ }
10403
+ const key = piSessionKey(entry);
10404
+ const prior = seen.get(key);
10405
+ if (!prior) {
10406
+ seen.set(key, entry);
10407
+ continue;
10408
+ }
10409
+ const priorMtime = mtimeOf(prior.path, prior.mtime);
10410
+ const entryMtime = mtimeOf(entry.path, entry.mtime);
10411
+ if (entryMtime > priorMtime)
10412
+ seen.set(key, entry);
10413
+ }
10414
+ const files = /* @__PURE__ */ new Map();
10415
+ for (const [key, file] of seen)
10416
+ files.set(key, file.path);
10417
+ return files;
10418
+ }
10419
+ _index = null;
10420
+ findSession(id) {
10421
+ const rawId = this.toRawId(id);
10422
+ const path = this.fileIndex().get(rawId);
10423
+ if (!path)
10424
+ return null;
10425
+ const header = readPiHeader(path);
10426
+ if (!header)
10427
+ return null;
10428
+ let mtime = 0;
10429
+ try {
10430
+ mtime = statSync10(path).mtimeMs;
10431
+ } catch {
10432
+ }
10433
+ return {
10434
+ path,
10435
+ format: "jsonl",
10436
+ projectDir: basename6(join11(path, "..")),
10437
+ projectPath: header.cwd || "",
10438
+ mtime
10439
+ };
10440
+ }
10441
+ listSessions(opts = {}) {
10442
+ const cutoff = opts.sinceMs ?? 0;
10443
+ const filter = opts.projectFilter?.toLowerCase();
10444
+ const out = [];
10445
+ for (const [rawId, path] of this.fileIndex()) {
10446
+ let stat;
10447
+ try {
10448
+ stat = statSync10(path);
10449
+ } catch {
10450
+ continue;
10451
+ }
10452
+ if (stat.mtimeMs < cutoff)
10453
+ continue;
10454
+ const header = readPiHeader(path);
10455
+ if (!header)
10456
+ continue;
10457
+ const projectPath = header.cwd || "";
10458
+ if (filter && !projectPath.toLowerCase().includes(filter))
10459
+ continue;
10460
+ let firstPrompt = "";
10461
+ let messageCount = 0;
10462
+ if (opts.previews !== false) {
10463
+ const parsed = parsePiFile(path);
10464
+ for (const entry of parsed.entries) {
10465
+ if (entry.type !== "message")
10466
+ continue;
10467
+ const role = entry.message?.role;
10468
+ if (role !== "user" && role !== "assistant")
10469
+ continue;
10470
+ messageCount++;
10471
+ if (!firstPrompt && role === "user") {
10472
+ const text = piText(entry.message?.content).trim();
10473
+ if (text)
10474
+ firstPrompt = flatString(text.slice(0, 200));
10475
+ }
10476
+ }
10477
+ }
10478
+ out.push({
10479
+ toolId: "pi",
10480
+ rawId,
10481
+ prefixedId: this.toPrefixedId(rawId),
10482
+ projectPath,
10483
+ projectDir: basename6(join11(path, "..")),
10484
+ fullPath: path,
10485
+ created: header.timestamp || stat.birthtime.toISOString(),
10486
+ modified: stat.mtime.toISOString(),
10487
+ mtime: stat.mtimeMs,
10488
+ firstPrompt,
10489
+ messageCount
10490
+ });
10491
+ }
10492
+ out.sort((a, b) => b.mtime - a.mtime);
10493
+ return opts.limit ? out.slice(0, opts.limit) : out;
10494
+ }
10495
+ // ── Generic-engine inputs ───────────────────────────────────────
10496
+ /**
10497
+ * The file tools and their EditOp. A shell command carries no path, so it
10498
+ * produces no file entry.
10499
+ */
10500
+ fileToolMap = {
10501
+ write: "write",
10502
+ edit: "edit",
10503
+ read: "read"
10504
+ };
10505
+ /**
10506
+ * The inline diff of a file tool.
10507
+ * - write: { path, content }.
10508
+ * - edit: { path, edits: [{ oldText, newText }] }.
10509
+ *
10510
+ * An edit holds several disjoint replacements. Join them into one pair.
10511
+ */
10512
+ extractEditDelta(toolName, input) {
10513
+ if (input == null || typeof input !== "object")
10514
+ return null;
10515
+ const inp = input;
10516
+ if (toolName === "write") {
10517
+ const after = typeof inp.content === "string" ? inp.content : null;
10518
+ if (after === null)
10519
+ return null;
10520
+ return { before: "", after };
10521
+ }
10522
+ if (toolName === "edit") {
10523
+ const edits = Array.isArray(inp.edits) ? inp.edits : [];
10524
+ let before = "";
10525
+ let after = "";
10526
+ for (const raw of edits) {
10527
+ if (!raw || typeof raw !== "object")
10528
+ continue;
10529
+ const e = raw;
10530
+ if (typeof e.oldText === "string")
10531
+ before += (before ? "\n" : "") + e.oldText;
10532
+ if (typeof e.newText === "string")
10533
+ after += (after ? "\n" : "") + e.newText;
10534
+ }
10535
+ if (!before && !after)
10536
+ return null;
10537
+ return { before: before || null, after: after || null };
10538
+ }
10539
+ return null;
10540
+ }
10541
+ readEvents(rawId) {
10542
+ const located = this.findSession(rawId);
10543
+ if (!located)
10544
+ return [];
10545
+ let rawText;
10546
+ try {
10547
+ rawText = readFileSync8(located.path, "utf-8");
10548
+ } catch {
10549
+ return [];
10550
+ }
10551
+ return this.readEventsFromText(rawText, located.mtime);
10552
+ }
10553
+ /**
10554
+ * Parse Pi session text into canonical events. Split out from readEvents so
10555
+ * the same parser runs on archived/shadow container bytes.
10556
+ */
10557
+ readEventsFromText(rawText, mtimeFallback = 0) {
10558
+ const events = [];
10559
+ let lineNum = 0;
10560
+ for (const line of rawText.split("\n")) {
10561
+ lineNum++;
10562
+ if (!line.trim())
10563
+ continue;
10564
+ let obj;
10565
+ try {
10566
+ obj = JSON.parse(line);
10567
+ } catch {
10568
+ continue;
10569
+ }
10570
+ const tsIso = typeof obj.timestamp === "string" ? obj.timestamp : void 0;
10571
+ const msgTs = typeof obj.message?.timestamp === "number" ? obj.message.timestamp : void 0;
10572
+ const ts = tsIso ? Date.parse(tsIso) || mtimeFallback : msgTs ?? mtimeFallback;
10573
+ if (obj.type === "message") {
10574
+ const msg = obj.message || {};
10575
+ const role = msg.role;
10576
+ if (role === "user") {
10577
+ const text = piText(msg.content).trim();
10578
+ if (text)
10579
+ events.push({ kind: "user", ts, tsIso, line: lineNum, text });
10580
+ continue;
10581
+ }
10582
+ if (role === "assistant") {
10583
+ const text = piText(msg.content).trim();
10584
+ if (text)
10585
+ events.push({ kind: "assistant_text", ts, tsIso, line: lineNum, text });
10586
+ const blocks = Array.isArray(msg.content) ? msg.content : [];
10587
+ for (const block of blocks) {
10588
+ if (!block || typeof block !== "object" || block.type !== "toolCall")
10589
+ continue;
10590
+ const toolName = String(block.name || "");
10591
+ if (!toolName)
10592
+ continue;
10593
+ const input = piToolInput(block.arguments);
10594
+ const command = toolName === "bash" || toolName === "powershell" ? typeof input.command === "string" ? input.command : void 0 : void 0;
10595
+ events.push({
10596
+ kind: "tool_use",
10597
+ ts,
10598
+ tsIso,
10599
+ line: lineNum,
10600
+ toolName,
10601
+ toolUseId: typeof block.id === "string" ? block.id : "",
10602
+ toolInput: input,
10603
+ command
10604
+ });
10605
+ }
10606
+ continue;
10607
+ }
10608
+ if (role === "toolResult") {
10609
+ const body = piText(msg.content);
10610
+ events.push({
10611
+ kind: "tool_result",
10612
+ ts,
10613
+ tsIso,
10614
+ line: lineNum,
10615
+ toolName: typeof msg.toolName === "string" ? msg.toolName : void 0,
10616
+ toolUseId: typeof msg.toolCallId === "string" ? msg.toolCallId : "",
10617
+ resultBody: body,
10618
+ resultIsError: msg.isError === true,
10619
+ resultBytes: body.length
10620
+ });
10621
+ continue;
10622
+ }
10623
+ if (role === "bashExecution") {
10624
+ const command = typeof msg.command === "string" ? msg.command : "";
10625
+ const output = typeof msg.output === "string" ? msg.output : "";
10626
+ const toolUseId = `pi_bash_${lineNum}`;
10627
+ events.push({
10628
+ kind: "tool_use",
10629
+ ts,
10630
+ tsIso,
10631
+ line: lineNum,
10632
+ toolName: "bash",
10633
+ toolUseId,
10634
+ toolInput: { command },
10635
+ command
10636
+ });
10637
+ events.push({
10638
+ kind: "tool_result",
10639
+ ts,
10640
+ tsIso,
10641
+ line: lineNum,
10642
+ toolUseId,
10643
+ toolName: "bash",
10644
+ resultBody: output,
10645
+ resultIsError: typeof msg.exitCode === "number" && msg.exitCode !== 0,
10646
+ resultExitCode: typeof msg.exitCode === "number" ? msg.exitCode : void 0,
10647
+ resultBytes: output.length
10648
+ });
10649
+ continue;
10650
+ }
10651
+ continue;
10652
+ }
10653
+ if (obj.type === "compaction" && typeof obj.summary === "string" && obj.summary.trim()) {
10654
+ events.push({ kind: "summary", ts, tsIso, line: lineNum, text: obj.summary.trim() });
10655
+ continue;
10656
+ }
10657
+ if (obj.type === "branch_summary" && typeof obj.summary === "string" && obj.summary.trim()) {
10658
+ events.push({ kind: "summary", ts, tsIso, line: lineNum, text: obj.summary.trim() });
10659
+ }
10660
+ }
10661
+ return events;
10662
+ }
10663
+ // ── Per-session operations — all delegate to the generic engine ─
10664
+ extractTurns(id, opts = {}) {
10665
+ const events = this.readEvents(this.toRawId(id));
10666
+ return extractTurnsFromEvents(this.toPrefixedId(id), events, opts);
10667
+ }
10668
+ liveScanEdits(id) {
10669
+ const located = this.findSession(this.toRawId(id));
10670
+ if (!located) {
10671
+ return { found: false, projectPath: "", projectDir: "", edits: [], fileMtime: 0, tool: "pi" };
10672
+ }
10673
+ const events = this.readEvents(this.toRawId(id));
10674
+ return liveScanEditsFromEvents(events, this.fileToolMap, {
10675
+ sessionId: this.toPrefixedId(id),
10676
+ tool: "pi",
10677
+ projectPath: located.projectPath,
10678
+ projectDir: located.projectDir,
10679
+ fileMtime: located.mtime,
10680
+ found: true
10681
+ }, this.extractEditDelta.bind(this));
10682
+ }
10683
+ replay(id) {
10684
+ const located = this.findSession(this.toRawId(id));
10685
+ if (!located) {
10686
+ return { sessionId: this.toPrefixedId(id), found: false, projectPath: "", files: [], totalLinesAdded: 0, totalLinesRemoved: 0 };
10687
+ }
10688
+ const events = this.readEvents(this.toRawId(id));
10689
+ return replayFromEvents(this.toPrefixedId(id), events, this.fileToolMap, this.extractEditDelta.bind(this), { projectPath: located.projectPath, found: true });
10690
+ }
10691
+ computeOutcome(id, opts) {
10692
+ return computeOutcome(this.toPrefixedId(id), opts);
10693
+ }
10694
+ collectRecentEdits(opts) {
10695
+ const candidates = [];
10696
+ for (const [rawId, path] of this.fileIndex()) {
10697
+ let stat;
10698
+ try {
10699
+ stat = statSync10(path);
10700
+ } catch {
10701
+ continue;
10702
+ }
10703
+ if (stat.mtimeMs < opts.sinceMs)
10704
+ continue;
10705
+ if (opts.projectFilter) {
10706
+ const header = readPiHeader(path);
10707
+ const projectPath = header?.cwd || "";
10708
+ if (!projectPath.toLowerCase().includes(opts.projectFilter.toLowerCase()))
10709
+ continue;
10710
+ }
10711
+ candidates.push({ rawId, mtime: stat.mtimeMs });
10712
+ }
10713
+ candidates.sort((a, b) => b.mtime - a.mtime);
10714
+ const limited = opts.limitSessions ? candidates.slice(0, opts.limitSessions) : candidates;
10715
+ const edits = [];
10716
+ for (const c of limited)
10717
+ edits.push(...this.liveScanEdits(c.rawId).edits);
10718
+ return edits;
10719
+ }
10720
+ getCommits(id, files, startMs, endMs, bufferMinutes) {
10721
+ return getSessionCommits(this.toPrefixedId(id), files, startMs, endMs, bufferMinutes);
10722
+ }
10723
+ /**
10724
+ * Pi's user-assigned session name (`/name`, `--name`), from the newest
10725
+ * `session_info` entry. Null when the session was never named.
10726
+ */
10727
+ getNativeTitle(rawId) {
10728
+ const located = this.findSession(rawId);
10729
+ if (!located)
10730
+ return null;
10731
+ const parsed = parsePiFile(located.path);
10732
+ for (let i = parsed.entries.length - 1; i >= 0; i--) {
10733
+ const entry = parsed.entries[i];
10734
+ if (entry.type !== "session_info")
10735
+ continue;
10736
+ const name = typeof entry.name === "string" ? entry.name.trim() : "";
10737
+ if (name)
10738
+ return name;
10739
+ }
10740
+ return null;
10741
+ }
10742
+ exportRawSession(id) {
10743
+ const located = this.findSession(id);
10744
+ if (!located)
10745
+ return null;
10746
+ try {
10747
+ const st = statSync10(located.path);
10748
+ return {
10749
+ tool: "pi",
10750
+ mtime: st.mtimeMs,
10751
+ files: [{ name: basename6(located.path), bytes: readFileSync8(located.path) }]
10752
+ };
10753
+ } catch {
10754
+ return null;
10755
+ }
10756
+ }
10757
+ isAppendOnly() {
10758
+ return true;
10759
+ }
10760
+ fileSize(prefixedId) {
10761
+ const located = this.findSession(prefixedId);
10762
+ if (!located)
10763
+ return 0;
10764
+ try {
10765
+ return statSync10(located.path).size;
10766
+ } catch {
10767
+ return 0;
10768
+ }
10769
+ }
10770
+ async readFromOffset(prefixedId, offset, maxBytes) {
10771
+ const located = this.findSession(prefixedId);
10772
+ if (!located)
10773
+ return { text: "", newOffset: offset };
10774
+ return readTailFromOffset(located.path, offset, maxBytes);
10775
+ }
10776
+ };
10777
+ piBackend = new PiBackend();
10778
+ }
10779
+ });
10780
+
10048
10781
  // ../engine/dist/core/backends/index.js
10049
10782
  function bootstrapBackends() {
10050
10783
  registerBackend(claudeBackend);
@@ -10053,6 +10786,7 @@ function bootstrapBackends() {
10053
10786
  registerBackend(agyBackend);
10054
10787
  registerBackend(cursorBackend);
10055
10788
  registerBackend(hermesBackend);
10789
+ registerBackend(piBackend);
10056
10790
  }
10057
10791
  var init_backends = __esm({
10058
10792
  "../engine/dist/core/backends/index.js"() {
@@ -10064,6 +10798,7 @@ var init_backends = __esm({
10064
10798
  init_agy();
10065
10799
  init_cursor();
10066
10800
  init_hermes();
10801
+ init_pi();
10067
10802
  init_tool_backend();
10068
10803
  _setRegistryBootstrapper(bootstrapBackends);
10069
10804
  }
@@ -10276,7 +11011,7 @@ var init_session_outcome = __esm({
10276
11011
  });
10277
11012
 
10278
11013
  // ../engine/dist/core/first-prompt.js
10279
- import { createReadStream, existsSync as existsSync11, openSync as openSync3, readSync as readSync3, closeSync as closeSync3 } from "fs";
11014
+ import { createReadStream, existsSync as existsSync11, openSync as openSync4, readSync as readSync4, closeSync as closeSync4 } from "fs";
10280
11015
  import { StringDecoder } from "string_decoder";
10281
11016
  function stripBanners(s) {
10282
11017
  let out = s;
@@ -10330,7 +11065,7 @@ function extractFirstUserPromptSync(filePath, options = {}) {
10330
11065
  const maxBytes = options.maxBytes ?? 4 * 1024 * 1024;
10331
11066
  let fd;
10332
11067
  try {
10333
- fd = openSync3(filePath, "r");
11068
+ fd = openSync4(filePath, "r");
10334
11069
  } catch {
10335
11070
  return "";
10336
11071
  }
@@ -10342,7 +11077,7 @@ function extractFirstUserPromptSync(filePath, options = {}) {
10342
11077
  let pos = 0;
10343
11078
  let lineNo = 0;
10344
11079
  for (; ; ) {
10345
- const n = readSync3(fd, buf, 0, CHUNK, pos);
11080
+ const n = readSync4(fd, buf, 0, CHUNK, pos);
10346
11081
  if (n <= 0)
10347
11082
  break;
10348
11083
  pos += n;
@@ -10368,7 +11103,7 @@ function extractFirstUserPromptSync(filePath, options = {}) {
10368
11103
  return "";
10369
11104
  } finally {
10370
11105
  try {
10371
- closeSync3(fd);
11106
+ closeSync4(fd);
10372
11107
  } catch {
10373
11108
  }
10374
11109
  }
@@ -10387,7 +11122,7 @@ var init_first_prompt = __esm({
10387
11122
  });
10388
11123
 
10389
11124
  // ../engine/dist/core/project-dir-name.js
10390
- import { readdirSync as readdirSync7 } from "node:fs";
11125
+ import { readdirSync as readdirSync8 } from "node:fs";
10391
11126
  function looksWindowsEncoded(dirName) {
10392
11127
  return /^[A-Za-z]--/.test(dirName);
10393
11128
  }
@@ -10407,7 +11142,7 @@ function resolveProjectDirName(dirName, deps = {}) {
10407
11142
  return structural;
10408
11143
  if (looksWindowsEncoded(dirName))
10409
11144
  return structural;
10410
- const readdir = deps.readdir ?? ((p) => readdirSync7(p, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name));
11145
+ const readdir = deps.readdir ?? ((p) => readdirSync8(p, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name));
10411
11146
  const encodeName = (name) => name.replace(/[-_.]/g, "-");
10412
11147
  let remaining = dirName.replace(/^-/, "");
10413
11148
  let current = "/";
@@ -10445,8 +11180,8 @@ var init_project_dir_name = __esm({
10445
11180
  });
10446
11181
 
10447
11182
  // ../engine/dist/core/backends/claude.js
10448
- import { existsSync as existsSync12, readdirSync as readdirSync8, readFileSync as readFileSync7, statSync as statSync9, openSync as openSync4, readSync as readSync4, closeSync as closeSync4 } from "fs";
10449
- import { join as join11, basename as basename6 } from "path";
11183
+ import { existsSync as existsSync12, readdirSync as readdirSync9, readFileSync as readFileSync9, statSync as statSync11, openSync as openSync5, readSync as readSync5, closeSync as closeSync5 } from "fs";
11184
+ import { join as join12, basename as basename7 } from "path";
10450
11185
  function stripReminders(text) {
10451
11186
  return text.replace(/<system-reminder>[\s\S]*?<\/system-reminder>/g, "").trim();
10452
11187
  }
@@ -10478,41 +11213,41 @@ var init_claude2 = __esm({
10478
11213
  }
10479
11214
  // ── Subpath helpers used by the parser/source layer ─────────────
10480
11215
  projectsDir() {
10481
- return join11(this.homeDir(), "projects");
11216
+ return join12(this.homeDir(), "projects");
10482
11217
  }
10483
11218
  plansDir() {
10484
- return join11(this.homeDir(), "plans");
11219
+ return join12(this.homeDir(), "plans");
10485
11220
  }
10486
11221
  todosDir() {
10487
- return join11(this.homeDir(), "todos");
11222
+ return join12(this.homeDir(), "todos");
10488
11223
  }
10489
11224
  /** Legacy task-list directory still used by older Claude Code releases. */
10490
11225
  tasksDir() {
10491
- return join11(this.homeDir(), "tasks");
11226
+ return join12(this.homeDir(), "tasks");
10492
11227
  }
10493
11228
  pasteCacheDir() {
10494
- return join11(this.homeDir(), "paste-cache");
11229
+ return join12(this.homeDir(), "paste-cache");
10495
11230
  }
10496
11231
  skillsDir() {
10497
- return join11(this.homeDir(), "skills");
11232
+ return join12(this.homeDir(), "skills");
10498
11233
  }
10499
11234
  agentsDir() {
10500
- return join11(this.homeDir(), "agents");
11235
+ return join12(this.homeDir(), "agents");
10501
11236
  }
10502
11237
  commandsDir() {
10503
- return join11(this.homeDir(), "commands");
11238
+ return join12(this.homeDir(), "commands");
10504
11239
  }
10505
11240
  pluginsManifestPath() {
10506
- return join11(this.homeDir(), "plugins", "installed_plugins.json");
11241
+ return join12(this.homeDir(), "plugins", "installed_plugins.json");
10507
11242
  }
10508
11243
  hooksFile() {
10509
- return join11(this.homeDir(), "hooks.json");
11244
+ return join12(this.homeDir(), "hooks.json");
10510
11245
  }
10511
11246
  settingsFile() {
10512
- return join11(this.homeDir(), "settings.json");
11247
+ return join12(this.homeDir(), "settings.json");
10513
11248
  }
10514
11249
  historyFile() {
10515
- return join11(this.homeDir(), "history.jsonl");
11250
+ return join12(this.homeDir(), "history.jsonl");
10516
11251
  }
10517
11252
  isAvailable() {
10518
11253
  return existsSync12(this.projectsDir());
@@ -10543,13 +11278,13 @@ var init_claude2 = __esm({
10543
11278
  return null;
10544
11279
  let head;
10545
11280
  try {
10546
- const fd = openSync4(located.path, "r");
11281
+ const fd = openSync5(located.path, "r");
10547
11282
  try {
10548
11283
  const buf = Buffer.alloc(65536);
10549
- const n = readSync4(fd, buf, 0, buf.length, 0);
11284
+ const n = readSync5(fd, buf, 0, buf.length, 0);
10550
11285
  head = buf.toString("utf-8", 0, n);
10551
11286
  } finally {
10552
- closeSync4(fd);
11287
+ closeSync5(fd);
10553
11288
  }
10554
11289
  } catch {
10555
11290
  return null;
@@ -10576,7 +11311,7 @@ var init_claude2 = __esm({
10576
11311
  let mtime = 0;
10577
11312
  for (const c of copies) {
10578
11313
  try {
10579
- mtime = Math.max(mtime, statSync9(c.path).mtimeMs);
11314
+ mtime = Math.max(mtime, statSync11(c.path).mtimeMs);
10580
11315
  } catch {
10581
11316
  }
10582
11317
  }
@@ -10623,18 +11358,18 @@ var init_claude2 = __esm({
10623
11358
  };
10624
11359
  if (!existsSync12(root))
10625
11360
  return;
10626
- for (const proj of readdirSync8(root, { withFileTypes: true })) {
11361
+ for (const proj of readdirSync9(root, { withFileTypes: true })) {
10627
11362
  if (!proj.isDirectory())
10628
11363
  continue;
10629
11364
  if (filter && !proj.name.toLowerCase().includes(filter))
10630
11365
  continue;
10631
- const projPath = join11(root, proj.name);
11366
+ const projPath = join12(root, proj.name);
10632
11367
  const projectPath = resolveProjectDirName(proj.name);
10633
- const indexPath = join11(projPath, "sessions-index.json");
11368
+ const indexPath = join12(projPath, "sessions-index.json");
10634
11369
  const indexed = /* @__PURE__ */ new Set();
10635
11370
  if (existsSync12(indexPath)) {
10636
11371
  try {
10637
- const indexData = JSON.parse(readFileSync7(indexPath, "utf-8"));
11372
+ const indexData = JSON.parse(readFileSync9(indexPath, "utf-8"));
10638
11373
  const entries = indexData.entries || [];
10639
11374
  for (const entry of entries) {
10640
11375
  if (!entry.fullPath || !existsSync12(entry.fullPath))
@@ -10659,20 +11394,20 @@ var init_claude2 = __esm({
10659
11394
  }
10660
11395
  let files;
10661
11396
  try {
10662
- files = readdirSync8(projPath);
11397
+ files = readdirSync9(projPath);
10663
11398
  } catch {
10664
11399
  continue;
10665
11400
  }
10666
11401
  for (const f of files) {
10667
11402
  if (!f.endsWith(".jsonl") || f === "sessions-index.json")
10668
11403
  continue;
10669
- const sessionId = basename6(f, ".jsonl");
11404
+ const sessionId = basename7(f, ".jsonl");
10670
11405
  if (indexed.has(sessionId))
10671
11406
  continue;
10672
- const fullPath = join11(projPath, f);
11407
+ const fullPath = join12(projPath, f);
10673
11408
  let stat;
10674
11409
  try {
10675
- stat = statSync9(fullPath);
11410
+ stat = statSync11(fullPath);
10676
11411
  } catch {
10677
11412
  continue;
10678
11413
  }
@@ -10926,7 +11661,7 @@ var init_claude2 = __esm({
10926
11661
  const events = this.readEvents(rawId);
10927
11662
  let fileMtime = 0;
10928
11663
  try {
10929
- fileMtime = statSync9(located.path).mtimeMs;
11664
+ fileMtime = statSync11(located.path).mtimeMs;
10930
11665
  } catch {
10931
11666
  }
10932
11667
  return liveScanEditsFromEvents(events, this.fileToolMap, {
@@ -10964,30 +11699,30 @@ var init_claude2 = __esm({
10964
11699
  for (const root of claudeProjectDirs()) {
10965
11700
  if (!existsSync12(root))
10966
11701
  continue;
10967
- for (const projEntry of readdirSync8(root, { withFileTypes: true })) {
11702
+ for (const projEntry of readdirSync9(root, { withFileTypes: true })) {
10968
11703
  if (!projEntry.isDirectory())
10969
11704
  continue;
10970
11705
  if (opts.projectFilter && !projEntry.name.toLowerCase().includes(opts.projectFilter.toLowerCase()))
10971
11706
  continue;
10972
- const projPath = join11(root, projEntry.name);
11707
+ const projPath = join12(root, projEntry.name);
10973
11708
  let files;
10974
11709
  try {
10975
- files = readdirSync8(projPath);
11710
+ files = readdirSync9(projPath);
10976
11711
  } catch {
10977
11712
  continue;
10978
11713
  }
10979
11714
  for (const f of files) {
10980
11715
  if (!f.endsWith(".jsonl") || f === "sessions-index.json")
10981
11716
  continue;
10982
- const fp = join11(projPath, f);
11717
+ const fp = join12(projPath, f);
10983
11718
  try {
10984
- const st = statSync9(fp);
11719
+ const st = statSync11(fp);
10985
11720
  let mtime = st.mtimeMs;
10986
- const subDir = join11(projPath, f.slice(0, -6), "subagents");
11721
+ const subDir = join12(projPath, f.slice(0, -6), "subagents");
10987
11722
  if (existsSync12(subDir)) {
10988
- for (const sub of readdirSync8(subDir)) {
11723
+ for (const sub of readdirSync9(subDir)) {
10989
11724
  try {
10990
- const subSt = statSync9(join11(subDir, sub));
11725
+ const subSt = statSync11(join12(subDir, sub));
10991
11726
  if (subSt.mtimeMs > mtime)
10992
11727
  mtime = subSt.mtimeMs;
10993
11728
  } catch {
@@ -10996,7 +11731,7 @@ var init_claude2 = __esm({
10996
11731
  }
10997
11732
  if (mtime < opts.sinceMs)
10998
11733
  continue;
10999
- candidates.push({ rawId: basename6(f, ".jsonl"), mtime });
11734
+ candidates.push({ rawId: basename7(f, ".jsonl"), mtime });
11000
11735
  } catch {
11001
11736
  }
11002
11737
  }
@@ -11052,7 +11787,7 @@ var init_claude2 = __esm({
11052
11787
  let total = 0;
11053
11788
  for (const located of findSessionFiles(this.toRawId(prefixedId))) {
11054
11789
  try {
11055
- total += statSync9(located.path).size;
11790
+ total += statSync11(located.path).size;
11056
11791
  } catch {
11057
11792
  }
11058
11793
  }
@@ -11081,7 +11816,7 @@ var init_claude2 = __esm({
11081
11816
  return copies.slice(0, -1).map((c) => {
11082
11817
  let size = -1;
11083
11818
  try {
11084
- size = statSync9(c.path).size;
11819
+ size = statSync11(c.path).size;
11085
11820
  } catch {
11086
11821
  }
11087
11822
  return `${c.path}:${size}`;
@@ -11114,11 +11849,11 @@ var init_model_pricing = __esm({
11114
11849
  });
11115
11850
 
11116
11851
  // ../engine/dist/parsers/session.js
11117
- import { createReadStream as createReadStream2, existsSync as existsSync13, readdirSync as readdirSync9, readFileSync as readFileSync8, statSync as statSync10, openSync as openSync5, readSync as readSync5, closeSync as closeSync5 } from "fs";
11118
- import { join as join12, basename as basename7 } from "path";
11852
+ import { createReadStream as createReadStream2, existsSync as existsSync13, readdirSync as readdirSync10, readFileSync as readFileSync10, statSync as statSync12, openSync as openSync6, readSync as readSync6, closeSync as closeSync6 } from "fs";
11853
+ import { join as join13, basename as basename8 } from "path";
11119
11854
  function hasSubagentsDir(sessionPath) {
11120
11855
  const dir = sessionPath.slice(0, -6);
11121
- return existsSync13(join12(dir, "subagents"));
11856
+ return existsSync13(join13(dir, "subagents"));
11122
11857
  }
11123
11858
  var init_session = __esm({
11124
11859
  "../engine/dist/parsers/session.js"() {
@@ -11133,9 +11868,9 @@ var init_session = __esm({
11133
11868
  });
11134
11869
 
11135
11870
  // ../engine/dist/transcript/shadow.js
11136
- import { createHash } from "crypto";
11871
+ import { createHash as createHash2 } from "crypto";
11137
11872
  function sha1(s) {
11138
- return createHash("sha1").update(s).digest("hex");
11873
+ return createHash2("sha1").update(s).digest("hex");
11139
11874
  }
11140
11875
  function lineKey(line) {
11141
11876
  try {
@@ -11217,11 +11952,11 @@ __export(live_session_scan_exports, {
11217
11952
  withSessionReadCache: () => withSessionReadCache,
11218
11953
  withSessionScanScope: () => withSessionScanScope
11219
11954
  });
11220
- import { existsSync as existsSync14, readdirSync as readdirSync10, readFileSync as readFileSync9, statSync as statSync11, openSync as openSync6, readSync as readSync6, closeSync as closeSync6 } from "fs";
11221
- import { join as join13, basename as basename8 } from "path";
11222
- import { createHash as createHash2 } from "crypto";
11955
+ import { existsSync as existsSync14, readdirSync as readdirSync11, readFileSync as readFileSync11, statSync as statSync13, openSync as openSync7, readSync as readSync7, closeSync as closeSync7 } from "fs";
11956
+ import { join as join14, basename as basename9 } from "path";
11957
+ import { createHash as createHash3 } from "crypto";
11223
11958
  function lazyGeminiProjectsJson() {
11224
- return join13(geminiHomeDir(), "projects.json");
11959
+ return join14(geminiHomeDir(), "projects.json");
11225
11960
  }
11226
11961
  function detectTool(sessionId) {
11227
11962
  return getBackendForId(sessionId)?.id ?? "claude";
@@ -11284,18 +12019,18 @@ function sessionFileIndex() {
11284
12019
  dirs.set(root, dirMtime(root));
11285
12020
  let entries;
11286
12021
  try {
11287
- entries = readdirSync10(root, { withFileTypes: true });
12022
+ entries = readdirSync11(root, { withFileTypes: true });
11288
12023
  } catch {
11289
12024
  continue;
11290
12025
  }
11291
12026
  for (const entry of entries) {
11292
12027
  if (!entry.isDirectory())
11293
12028
  continue;
11294
- const dir = join13(root, entry.name);
12029
+ const dir = join14(root, entry.name);
11295
12030
  dirs.set(dir, dirMtime(dir));
11296
12031
  let names;
11297
12032
  try {
11298
- names = readdirSync10(dir);
12033
+ names = readdirSync11(dir);
11299
12034
  } catch {
11300
12035
  continue;
11301
12036
  }
@@ -11304,7 +12039,7 @@ function sessionFileIndex() {
11304
12039
  continue;
11305
12040
  const id = name.slice(0, -".jsonl".length);
11306
12041
  const located = {
11307
- path: join13(dir, name),
12042
+ path: join14(dir, name),
11308
12043
  projectDir: entry.name,
11309
12044
  projectPath: projectPathOf(entry.name)
11310
12045
  };
@@ -11336,7 +12071,7 @@ function resolveSessionContentGroups(sessionId) {
11336
12071
  };
11337
12072
  for (const located of findSessionFiles(sessionId)) {
11338
12073
  for (const p of resolveSessionContentPaths(located.path)) {
11339
- add(p === located.path ? "main" : `subagents/${basename8(p)}`, p);
12074
+ add(p === located.path ? "main" : `subagents/${basename9(p)}`, p);
11340
12075
  }
11341
12076
  }
11342
12077
  const names = [...groups.keys()].sort((a, b) => a === "main" ? -1 : b === "main" ? 1 : a.localeCompare(b));
@@ -11370,7 +12105,7 @@ function readSessionGroupText(group) {
11370
12105
  const parts = [];
11371
12106
  for (const p of group.paths) {
11372
12107
  try {
11373
- const st = statSync11(p);
12108
+ const st = statSync13(p);
11374
12109
  parts.push(`${p}:${st.mtimeMs}:${st.size}`);
11375
12110
  } catch {
11376
12111
  parts.push(`${p}:missing`);
@@ -11385,12 +12120,12 @@ function readSessionGroupText(group) {
11385
12120
  for (const p of group.paths) {
11386
12121
  let raw;
11387
12122
  try {
11388
- raw = readFileSync9(p, "utf-8");
12123
+ raw = readFileSync11(p, "utf-8");
11389
12124
  } catch {
11390
12125
  continue;
11391
12126
  }
11392
12127
  try {
11393
- mtime = Math.max(mtime, statSync11(p).mtimeMs);
12128
+ mtime = Math.max(mtime, statSync13(p).mtimeMs);
11394
12129
  } catch {
11395
12130
  }
11396
12131
  text = text ? mergeLineText(text, raw).text : raw;
@@ -11403,10 +12138,10 @@ function readSessionGroupText(group) {
11403
12138
  function resolveSessionContentPaths(sessionFile) {
11404
12139
  if (!hasSubagentsDir(sessionFile))
11405
12140
  return [sessionFile];
11406
- const subDir = join13(sessionFile.slice(0, -6), "subagents");
12141
+ const subDir = join14(sessionFile.slice(0, -6), "subagents");
11407
12142
  if (!existsSync14(subDir))
11408
12143
  return [sessionFile];
11409
- const subPaths = readdirSync10(subDir).filter((f) => f.endsWith(".jsonl")).sort().map((f) => join13(subDir, f));
12144
+ const subPaths = readdirSync11(subDir).filter((f) => f.endsWith(".jsonl")).sort().map((f) => join14(subDir, f));
11410
12145
  return [sessionFile, ...subPaths];
11411
12146
  }
11412
12147
  function liveScanSessionEdits(sessionId) {
@@ -11423,9 +12158,9 @@ function loadGeminiProjectMap() {
11423
12158
  const projectsPath = lazyGeminiProjectsJson();
11424
12159
  if (existsSync14(projectsPath)) {
11425
12160
  try {
11426
- const data = JSON.parse(readFileSync9(projectsPath, "utf-8"));
12161
+ const data = JSON.parse(readFileSync11(projectsPath, "utf-8"));
11427
12162
  for (const path of Object.keys(data.projects || {})) {
11428
- map.set(createHash2("sha256").update(path).digest("hex"), path);
12163
+ map.set(createHash3("sha256").update(path).digest("hex"), path);
11429
12164
  }
11430
12165
  } catch {
11431
12166
  }
@@ -11461,19 +12196,19 @@ function geminiIndex() {
11461
12196
  continue;
11462
12197
  let projs;
11463
12198
  try {
11464
- projs = readdirSync10(tmpRoot, { withFileTypes: true });
12199
+ projs = readdirSync11(tmpRoot, { withFileTypes: true });
11465
12200
  } catch {
11466
12201
  continue;
11467
12202
  }
11468
12203
  for (const proj of projs) {
11469
12204
  if (!proj.isDirectory())
11470
12205
  continue;
11471
- const chats = join13(tmpRoot, proj.name, "chats");
12206
+ const chats = join14(tmpRoot, proj.name, "chats");
11472
12207
  if (!existsSync14(chats))
11473
12208
  continue;
11474
12209
  let files;
11475
12210
  try {
11476
- files = readdirSync10(chats);
12211
+ files = readdirSync11(chats);
11477
12212
  } catch {
11478
12213
  continue;
11479
12214
  }
@@ -11482,7 +12217,7 @@ function geminiIndex() {
11482
12217
  continue;
11483
12218
  const base = f.replace(/\.jsonl?$/, "");
11484
12219
  const located = {
11485
- path: join13(chats, f),
12220
+ path: join14(chats, f),
11486
12221
  projectDir: proj.name,
11487
12222
  projectPath: projMap.get(proj.name) || "",
11488
12223
  format: f.endsWith(".jsonl") ? "jsonl" : "json"
@@ -11517,19 +12252,19 @@ function geminiInnerIdIndex(idx) {
11517
12252
  return byInnerId;
11518
12253
  }
11519
12254
  function readHeadSync(path, bytes = 65536) {
11520
- const fd = openSync6(path, "r");
12255
+ const fd = openSync7(path, "r");
11521
12256
  try {
11522
12257
  const buf = Buffer.alloc(bytes);
11523
- const n = readSync6(fd, buf, 0, buf.length, 0);
12258
+ const n = readSync7(fd, buf, 0, buf.length, 0);
11524
12259
  return buf.toString("utf-8", 0, n);
11525
12260
  } finally {
11526
- closeSync6(fd);
12261
+ closeSync7(fd);
11527
12262
  }
11528
12263
  }
11529
12264
  function readGeminiSessionIdFromFile(path, format) {
11530
12265
  if (format === "json") {
11531
12266
  try {
11532
- return JSON.parse(readFileSync9(path, "utf-8"))?.sessionId ?? null;
12267
+ return JSON.parse(readFileSync11(path, "utf-8"))?.sessionId ?? null;
11533
12268
  } catch {
11534
12269
  return null;
11535
12270
  }
@@ -11544,7 +12279,7 @@ function readGeminiSessionIdFromFile(path, format) {
11544
12279
  function readGeminiMessages(path, format) {
11545
12280
  if (format === "json") {
11546
12281
  try {
11547
- const json = JSON.parse(readFileSync9(path, "utf-8"));
12282
+ const json = JSON.parse(readFileSync11(path, "utf-8"));
11548
12283
  return Array.isArray(json.messages) ? json.messages : [];
11549
12284
  } catch {
11550
12285
  return [];
@@ -11553,7 +12288,7 @@ function readGeminiMessages(path, format) {
11553
12288
  const out = [];
11554
12289
  let raw;
11555
12290
  try {
11556
- raw = readFileSync9(path, "utf-8");
12291
+ raw = readFileSync11(path, "utf-8");
11557
12292
  } catch {
11558
12293
  return out;
11559
12294
  }
@@ -11592,21 +12327,21 @@ function findCodexSessionFile(sessionId) {
11592
12327
  function findCodexSessionFileIn(root, sessionId) {
11593
12328
  if (!existsSync14(root))
11594
12329
  return null;
11595
- for (const year of readdirSync10(root, { withFileTypes: true })) {
12330
+ for (const year of readdirSync11(root, { withFileTypes: true })) {
11596
12331
  if (!year.isDirectory())
11597
12332
  continue;
11598
- const yearPath = join13(root, year.name);
11599
- for (const month of readdirSync10(yearPath, { withFileTypes: true })) {
12333
+ const yearPath = join14(root, year.name);
12334
+ for (const month of readdirSync11(yearPath, { withFileTypes: true })) {
11600
12335
  if (!month.isDirectory())
11601
12336
  continue;
11602
- const monthPath = join13(yearPath, month.name);
11603
- for (const day of readdirSync10(monthPath, { withFileTypes: true })) {
12337
+ const monthPath = join14(yearPath, month.name);
12338
+ for (const day of readdirSync11(monthPath, { withFileTypes: true })) {
11604
12339
  if (!day.isDirectory())
11605
12340
  continue;
11606
- const dayPath = join13(monthPath, day.name);
12341
+ const dayPath = join14(monthPath, day.name);
11607
12342
  let files;
11608
12343
  try {
11609
- files = readdirSync10(dayPath);
12344
+ files = readdirSync11(dayPath);
11610
12345
  } catch {
11611
12346
  continue;
11612
12347
  }
@@ -11614,22 +12349,22 @@ function findCodexSessionFileIn(root, sessionId) {
11614
12349
  if (!f.endsWith(".jsonl"))
11615
12350
  continue;
11616
12351
  if (f.includes(sessionId)) {
11617
- return { path: join13(dayPath, f), projectPath: "" };
12352
+ return { path: join14(dayPath, f), projectPath: "" };
11618
12353
  }
11619
12354
  }
11620
12355
  }
11621
12356
  }
11622
12357
  }
11623
12358
  function scanDir(dir) {
11624
- for (const entry of readdirSync10(dir, { withFileTypes: true })) {
12359
+ for (const entry of readdirSync11(dir, { withFileTypes: true })) {
11625
12360
  if (entry.isDirectory()) {
11626
- const found = scanDir(join13(dir, entry.name));
12361
+ const found = scanDir(join14(dir, entry.name));
11627
12362
  if (found)
11628
12363
  return found;
11629
12364
  } else if (entry.name.endsWith(".jsonl")) {
11630
- const p = join13(dir, entry.name);
12365
+ const p = join14(dir, entry.name);
11631
12366
  try {
11632
- const first = readFileSync9(p, "utf-8").split("\n")[0];
12367
+ const first = readFileSync11(p, "utf-8").split("\n")[0];
11633
12368
  if (!first)
11634
12369
  continue;
11635
12370
  const meta = JSON.parse(first);
@@ -11705,7 +12440,7 @@ var init_live_session_scan = __esm({
11705
12440
  INDEX_RECHECK_MS = 1e3;
11706
12441
  dirMtime = (p) => {
11707
12442
  try {
11708
- return statSync11(p).mtimeMs;
12443
+ return statSync13(p).mtimeMs;
11709
12444
  } catch {
11710
12445
  return -1;
11711
12446
  }