@ai-matrx/coding-sessions 0.1.81 → 0.1.83

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/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # @ai-matrx/coding-sessions
2
2
 
3
+ ## 0.1.83
4
+
5
+ Automatic changed-only republish (docs/metadata drift since the last tag — see
6
+ `git diff npm/coding-sessions/v0.1.81..npm/coding-sessions/v0.1.83 -- apps/shared/coding-sessions`).
7
+ No source changes intended and no consumer action required.
8
+
9
+ ## 0.1.82
10
+
11
+ Automatic changed-only republish (docs/metadata drift since the last tag — see
12
+ `git diff npm/coding-sessions/v0.1.81..npm/coding-sessions/v0.1.82 -- apps/shared/coding-sessions`).
13
+ No source changes intended and no consumer action required.
14
+
3
15
  ## 0.1.81
4
16
 
5
17
  Automatic changed-only republish (docs/metadata drift since the last tag — see
@@ -60,9 +60,9 @@ var getImportMetaUrl = () => typeof document === "undefined" ? new URL(`file:${_
60
60
  var importMetaUrl = /* @__PURE__ */ getImportMetaUrl();
61
61
 
62
62
  // src/engine/index.ts
63
- var import_node_child_process2 = require("child_process");
63
+ var import_node_child_process3 = require("child_process");
64
64
  var import_node_crypto4 = require("crypto");
65
- var import_node_fs3 = require("fs");
65
+ var import_node_fs4 = require("fs");
66
66
  var import_format = require("@ai-matrx/kit/format");
67
67
 
68
68
  // src/engine/raw-backup.ts
@@ -161,8 +161,8 @@ function createAiMatrxRawBackupSink(options) {
161
161
 
162
162
  // src/engine/index.ts
163
163
  var import_promises6 = __toESM(require("fs/promises"), 1);
164
- var import_node_os4 = __toESM(require("os"), 1);
165
- var import_node_path6 = __toESM(require("path"), 1);
164
+ var import_node_os5 = __toESM(require("os"), 1);
165
+ var import_node_path7 = __toESM(require("path"), 1);
166
166
  var import_node_url = require("url");
167
167
 
168
168
  // src/normalize/claude.ts
@@ -828,9 +828,177 @@ function describeProblem(provider, problem) {
828
828
  };
829
829
  }
830
830
 
831
- // src/engine/clean-env.ts
831
+ // src/engine/binaries.ts
832
+ var import_node_child_process = require("child_process");
833
+ var import_node_fs = require("fs");
832
834
  var import_node_os = __toESM(require("os"), 1);
833
835
  var import_node_path = __toESM(require("path"), 1);
836
+ var SOURCE_LABEL = {
837
+ codex: { "desktop-app": "from ChatGPT app", path: "from PATH", "npm-global": "from npm", configured: "set by host" },
838
+ claude: { "desktop-app": "from Claude app", path: "from PATH", "npm-global": "from npm", configured: "set by host" }
839
+ };
840
+ function sourceLabel(provider, source) {
841
+ return SOURCE_LABEL[provider][source];
842
+ }
843
+ function parseVersion(text) {
844
+ const match = /(\d+)\.(\d+)\.(\d+)(?:[-.][0-9A-Za-z.]+)?/.exec(text ?? "");
845
+ return match ? match[0] : null;
846
+ }
847
+ function compareVersions(a, b) {
848
+ const [aCore = "", aPre] = a.split("-", 2);
849
+ const [bCore = "", bPre] = b.split("-", 2);
850
+ const pa = aCore.split(".").map((n) => Number.parseInt(n, 10) || 0);
851
+ const pb = bCore.split(".").map((n) => Number.parseInt(n, 10) || 0);
852
+ for (let i = 0; i < Math.max(pa.length, pb.length); i++) {
853
+ const d = (pa[i] ?? 0) - (pb[i] ?? 0);
854
+ if (d !== 0) return d < 0 ? -1 : 1;
855
+ }
856
+ if (aPre && !bPre) return -1;
857
+ if (!aPre && bPre) return 1;
858
+ return 0;
859
+ }
860
+ function pickBinary(candidates) {
861
+ let best = null;
862
+ for (const c of candidates) {
863
+ if (!best) {
864
+ best = c;
865
+ continue;
866
+ }
867
+ if (c.version && (!best.version || compareVersions(c.version, best.version) > 0)) best = c;
868
+ }
869
+ return best;
870
+ }
871
+ function executable(file) {
872
+ try {
873
+ (0, import_node_fs.accessSync)(file, import_node_fs.constants.X_OK);
874
+ return true;
875
+ } catch {
876
+ return false;
877
+ }
878
+ }
879
+ function exeName(name, platform) {
880
+ return platform === "win32" ? [`${name}.exe`, `${name}.cmd`, name] : [name];
881
+ }
882
+ function allOnPath(name, pathValue, platform = process.platform) {
883
+ const found = [];
884
+ for (const dir of pathValue.split(import_node_path.default.delimiter)) {
885
+ if (!dir) continue;
886
+ for (const file of exeName(name, platform)) {
887
+ const candidate = import_node_path.default.join(dir, file);
888
+ if (executable(candidate)) {
889
+ found.push(candidate);
890
+ break;
891
+ }
892
+ }
893
+ }
894
+ return found;
895
+ }
896
+ function desktopAppCandidates(provider, platform, home, applications) {
897
+ if (platform !== "darwin") return [];
898
+ if (provider === "codex") {
899
+ return applications.map(
900
+ (apps) => import_node_path.default.join(apps, "ChatGPT.app", "Contents", "Resources", "codex-cli", "bin", "codex")
901
+ );
902
+ }
903
+ const root = import_node_path.default.join(home, "Library", "Application Support", "Claude", "claude-code");
904
+ let versions = [];
905
+ try {
906
+ versions = (0, import_node_fs.readdirSync)(root);
907
+ } catch {
908
+ return [];
909
+ }
910
+ return versions.map((v) => import_node_path.default.join(root, v, "claude.app", "Contents", "MacOS", "claude"));
911
+ }
912
+ function npmGlobalPrefix(env) {
913
+ const fromEnv = env.npm_config_prefix ?? env.NPM_CONFIG_PREFIX;
914
+ if (fromEnv) return Promise.resolve(fromEnv);
915
+ const npm = allOnPath("npm", env.PATH ?? "")[0];
916
+ if (!npm) return Promise.resolve(null);
917
+ return new Promise((resolve) => {
918
+ const child = (0, import_node_child_process.execFile)(npm, ["prefix", "-g"], { timeout: 5e3, env }, (error, stdout) => {
919
+ resolve(error ? null : String(stdout).trim() || null);
920
+ });
921
+ child.stdin?.end();
922
+ });
923
+ }
924
+ function declaredVersion(provider, source, file) {
925
+ if (source !== "desktop-app") return null;
926
+ if (provider === "codex") {
927
+ try {
928
+ const pkg = JSON.parse((0, import_node_fs.readFileSync)(import_node_path.default.join(import_node_path.default.dirname(import_node_path.default.dirname(file)), "codex-package.json"), "utf8"));
929
+ return typeof pkg.version === "string" ? parseVersion(pkg.version) : null;
930
+ } catch {
931
+ return null;
932
+ }
933
+ }
934
+ return parseVersion(import_node_path.default.basename(import_node_path.default.resolve(file, "..", "..", "..", "..")));
935
+ }
936
+ function runVersion(file, env) {
937
+ return new Promise((resolve) => {
938
+ const child = (0, import_node_child_process.execFile)(file, ["--version"], { timeout: 8e3, env }, (error, stdout) => {
939
+ resolve(error ? null : parseVersion(String(stdout)));
940
+ });
941
+ child.stdin?.end();
942
+ });
943
+ }
944
+ async function discoverBinaries(provider, options) {
945
+ const platform = options.platform ?? process.platform;
946
+ const home = options.home ?? options.env.HOME ?? import_node_os.default.homedir();
947
+ const listed2 = [
948
+ ...desktopAppCandidates(provider, platform, home, options.applications ?? ["/Applications", import_node_path.default.join(home, "Applications")]).filter(executable).map((p) => ({ path: p, source: "desktop-app" })),
949
+ ...allOnPath(provider, options.env.PATH ?? "", platform).map((p) => ({ path: p, source: "path" }))
950
+ ];
951
+ const prefix = await npmGlobalPrefix(options.env);
952
+ if (prefix) {
953
+ const dir = platform === "win32" ? prefix : import_node_path.default.join(prefix, "bin");
954
+ for (const file of exeName(provider, platform)) {
955
+ const candidate = import_node_path.default.join(dir, file);
956
+ if (executable(candidate)) {
957
+ listed2.push({ path: candidate, source: "npm-global" });
958
+ break;
959
+ }
960
+ }
961
+ }
962
+ const seen = /* @__PURE__ */ new Set();
963
+ const unique = listed2.filter((c) => {
964
+ let real = c.path;
965
+ try {
966
+ real = (0, import_node_fs.realpathSync)(c.path);
967
+ } catch {
968
+ }
969
+ if (seen.has(real)) return false;
970
+ seen.add(real);
971
+ return true;
972
+ });
973
+ return Promise.all(
974
+ unique.map(async (c) => ({
975
+ ...c,
976
+ version: declaredVersion(provider, c.source, c.path) ?? await runVersion(c.path, options.env)
977
+ }))
978
+ );
979
+ }
980
+ async function resolveBinary(provider, options) {
981
+ const candidates = options.discover === false ? [] : await discoverBinaries(provider, options);
982
+ const best = pickBinary(candidates);
983
+ const inUse = options.forced ? {
984
+ path: options.forced,
985
+ source: "configured",
986
+ version: candidates.find((c) => c.path === options.forced)?.version ?? (options.discover === false ? null : await runVersion(options.forced, options.env))
987
+ } : best;
988
+ if (!inUse) return null;
989
+ const newer = best && best.path !== inUse.path && best.version && (!inUse.version || compareVersions(best.version, inUse.version) > 0) ? { path: best.path, version: best.version, sourceLabel: sourceLabel(provider, best.source) } : null;
990
+ return {
991
+ path: inUse.path,
992
+ version: inUse.version,
993
+ source: inUse.source,
994
+ sourceLabel: sourceLabel(provider, inUse.source),
995
+ newer
996
+ };
997
+ }
998
+
999
+ // src/engine/clean-env.ts
1000
+ var import_node_os2 = __toESM(require("os"), 1);
1001
+ var import_node_path2 = __toESM(require("path"), 1);
834
1002
  var ALLOWED_NAMES = /* @__PURE__ */ new Set([
835
1003
  "HOME",
836
1004
  "USER",
@@ -852,11 +1020,11 @@ var ALLOWED_NAMES = /* @__PURE__ */ new Set([
852
1020
  var ALLOWED_PREFIXES = ["LC_"];
853
1021
  function wellKnownBinDirs(home) {
854
1022
  return [
855
- import_node_path.default.join(home, ".local", "bin"),
856
- import_node_path.default.join(home, ".claude", "local"),
857
- import_node_path.default.join(home, ".npm-global", "bin"),
858
- import_node_path.default.join(home, ".bun", "bin"),
859
- import_node_path.default.join(home, ".volta", "bin"),
1023
+ import_node_path2.default.join(home, ".local", "bin"),
1024
+ import_node_path2.default.join(home, ".claude", "local"),
1025
+ import_node_path2.default.join(home, ".npm-global", "bin"),
1026
+ import_node_path2.default.join(home, ".bun", "bin"),
1027
+ import_node_path2.default.join(home, ".volta", "bin"),
860
1028
  "/opt/homebrew/bin",
861
1029
  "/usr/local/bin",
862
1030
  "/usr/bin",
@@ -874,31 +1042,31 @@ function buildCleanEnv(hostEnv, extra = {}) {
874
1042
  if (typeof value !== "string") continue;
875
1043
  if (isAllowedEnvName(name)) out[name] = value;
876
1044
  }
877
- const home = out.HOME ?? import_node_os.default.homedir();
1045
+ const home = out.HOME ?? import_node_os2.default.homedir();
878
1046
  out.HOME = home;
879
- const hostPath = (hostEnv.PATH ?? "").split(import_node_path.default.delimiter).filter(Boolean);
1047
+ const hostPath = (hostEnv.PATH ?? "").split(import_node_path2.default.delimiter).filter(Boolean);
880
1048
  const merged = [];
881
1049
  for (const dir of [...hostPath, ...wellKnownBinDirs(home)]) {
882
1050
  if (!merged.includes(dir)) merged.push(dir);
883
1051
  }
884
- out.PATH = merged.join(import_node_path.default.delimiter);
1052
+ out.PATH = merged.join(import_node_path2.default.delimiter);
885
1053
  for (const [name, value] of Object.entries(extra)) out[name] = value;
886
1054
  return out;
887
1055
  }
888
1056
 
889
1057
  // src/engine/files.ts
890
- var import_node_fs = require("fs");
1058
+ var import_node_fs2 = require("fs");
891
1059
  var import_promises2 = __toESM(require("fs/promises"), 1);
892
- var import_node_os2 = __toESM(require("os"), 1);
893
- var import_node_path2 = __toESM(require("path"), 1);
1060
+ var import_node_os3 = __toESM(require("os"), 1);
1061
+ var import_node_path3 = __toESM(require("path"), 1);
894
1062
 
895
1063
  // src/engine/activity.ts
896
- var import_node_child_process = require("child_process");
1064
+ var import_node_child_process2 = require("child_process");
897
1065
  var RECENT_WRITE_MS = 2 * 60 * 1e3;
898
1066
  var OPEN_TOOL_WINDOW_MS = 15 * 60 * 1e3;
899
1067
  function listProcesses() {
900
1068
  return new Promise((resolve) => {
901
- (0, import_node_child_process.execFile)("ps", ["-axww", "-o", "pid=,args="], { maxBuffer: 64 * 1024 * 1024, timeout: 5e3 }, (error, stdout) => {
1069
+ (0, import_node_child_process2.execFile)("ps", ["-axww", "-o", "pid=,args="], { maxBuffer: 64 * 1024 * 1024, timeout: 5e3 }, (error, stdout) => {
902
1070
  if (error) {
903
1071
  resolve([]);
904
1072
  return;
@@ -957,11 +1125,11 @@ function describeActivity(input) {
957
1125
  }
958
1126
 
959
1127
  // src/engine/files.ts
960
- function defaultProviderHomes(home = import_node_os2.default.homedir()) {
1128
+ function defaultProviderHomes(home = import_node_os3.default.homedir()) {
961
1129
  return {
962
- claudeProjects: import_node_path2.default.join(home, ".claude", "projects"),
963
- codexSessions: import_node_path2.default.join(home, ".codex", "sessions"),
964
- codexIndex: import_node_path2.default.join(home, ".codex", "session_index.jsonl")
1130
+ claudeProjects: import_node_path3.default.join(home, ".claude", "projects"),
1131
+ codexSessions: import_node_path3.default.join(home, ".codex", "sessions"),
1132
+ codexIndex: import_node_path3.default.join(home, ".codex", "session_index.jsonl")
965
1133
  };
966
1134
  }
967
1135
  var UUIDISH = /([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})\.jsonl$/i;
@@ -986,10 +1154,10 @@ async function claudeCandidates(root) {
986
1154
  const out = [];
987
1155
  for (const project of await safeReaddir(root)) {
988
1156
  if (!project.isDirectory()) continue;
989
- const dir = import_node_path2.default.join(root, project.name);
1157
+ const dir = import_node_path3.default.join(root, project.name);
990
1158
  const entries = await safeReaddir(dir);
991
1159
  const stats = await Promise.all(
992
- entries.filter((e) => e.isFile() && e.name.endsWith(".jsonl")).map((e) => statCandidate("claude", import_node_path2.default.join(dir, e.name)))
1160
+ entries.filter((e) => e.isFile() && e.name.endsWith(".jsonl")).map((e) => statCandidate("claude", import_node_path3.default.join(dir, e.name)))
993
1161
  );
994
1162
  for (const s of stats) if (s) out.push(s);
995
1163
  }
@@ -999,14 +1167,14 @@ async function codexCandidates(root) {
999
1167
  const out = [];
1000
1168
  for (const year of await safeReaddir(root)) {
1001
1169
  if (!year.isDirectory()) continue;
1002
- for (const month of await safeReaddir(import_node_path2.default.join(root, year.name))) {
1170
+ for (const month of await safeReaddir(import_node_path3.default.join(root, year.name))) {
1003
1171
  if (!month.isDirectory()) continue;
1004
- for (const day of await safeReaddir(import_node_path2.default.join(root, year.name, month.name))) {
1172
+ for (const day of await safeReaddir(import_node_path3.default.join(root, year.name, month.name))) {
1005
1173
  if (!day.isDirectory()) continue;
1006
- const dir = import_node_path2.default.join(root, year.name, month.name, day.name);
1174
+ const dir = import_node_path3.default.join(root, year.name, month.name, day.name);
1007
1175
  const entries = await safeReaddir(dir);
1008
1176
  const stats = await Promise.all(
1009
- entries.filter((e) => e.isFile() && e.name.startsWith("rollout-") && e.name.endsWith(".jsonl")).map((e) => statCandidate("codex", import_node_path2.default.join(dir, e.name)))
1177
+ entries.filter((e) => e.isFile() && e.name.startsWith("rollout-") && e.name.endsWith(".jsonl")).map((e) => statCandidate("codex", import_node_path3.default.join(dir, e.name)))
1010
1178
  );
1011
1179
  for (const s of stats) if (s) out.push(s);
1012
1180
  }
@@ -1227,7 +1395,7 @@ async function readSessionFile(provider, file, endOffset, maxBytes = HISTORY_BUD
1227
1395
  let droppedFirst = start > 0;
1228
1396
  let carry = "";
1229
1397
  await new Promise((resolve, reject) => {
1230
- const stream = (0, import_node_fs.createReadStream)(file, { start, end: Math.max(start, end - 1), encoding: "utf8" });
1398
+ const stream = (0, import_node_fs2.createReadStream)(file, { start, end: Math.max(start, end - 1), encoding: "utf8" });
1231
1399
  stream.on("data", (chunk) => {
1232
1400
  const text = carry + String(chunk);
1233
1401
  const lines = text.split("\n");
@@ -1267,7 +1435,7 @@ async function describeSessionFile(candidate, codexNames) {
1267
1435
  // src/engine/preferences.ts
1268
1436
  var import_node_crypto2 = require("crypto");
1269
1437
  var import_promises3 = __toESM(require("fs/promises"), 1);
1270
- var import_node_path3 = __toESM(require("path"), 1);
1438
+ var import_node_path4 = __toESM(require("path"), 1);
1271
1439
  var PreferenceStore = class {
1272
1440
  constructor(dir) {
1273
1441
  this.dir = dir;
@@ -1276,7 +1444,7 @@ var PreferenceStore = class {
1276
1444
  data = {};
1277
1445
  writing = Promise.resolve();
1278
1446
  get file() {
1279
- return import_node_path3.default.join(this.dir, "preferences.json");
1447
+ return import_node_path4.default.join(this.dir, "preferences.json");
1280
1448
  }
1281
1449
  async load() {
1282
1450
  try {
@@ -1331,7 +1499,7 @@ var PreferenceStore = class {
1331
1499
  };
1332
1500
 
1333
1501
  // src/engine/search.ts
1334
- var import_node_fs2 = require("fs");
1502
+ var import_node_fs3 = require("fs");
1335
1503
  function findInLine(provider, value, needle) {
1336
1504
  const items = provider === "claude" ? createClaudeNormalizer().push(value) : createCodexRolloutNormalizer().push(value);
1337
1505
  for (const item of items) {
@@ -1372,7 +1540,7 @@ async function scanFile(provider, file, needle, raw, deadline) {
1372
1540
  return new Promise((resolve) => {
1373
1541
  let carry = Buffer.alloc(0);
1374
1542
  let done = false;
1375
- const stream = (0, import_node_fs2.createReadStream)(file, { highWaterMark: 4 * 1024 * 1024 });
1543
+ const stream = (0, import_node_fs3.createReadStream)(file, { highWaterMark: 4 * 1024 * 1024 });
1376
1544
  const finish = (value) => {
1377
1545
  if (done) return;
1378
1546
  done = true;
@@ -1480,7 +1648,7 @@ async function searchLocalChats(query, options = {}) {
1480
1648
  // src/engine/store.ts
1481
1649
  var import_node_crypto3 = require("crypto");
1482
1650
  var import_promises4 = __toESM(require("fs/promises"), 1);
1483
- var import_node_path4 = __toESM(require("path"), 1);
1651
+ var import_node_path5 = __toESM(require("path"), 1);
1484
1652
  var MAX_RUNS = 2e3;
1485
1653
  var RunIndex = class {
1486
1654
  constructor(dir) {
@@ -1490,7 +1658,7 @@ var RunIndex = class {
1490
1658
  data = { version: 1, sessions: [], runs: [] };
1491
1659
  writing = Promise.resolve();
1492
1660
  get file() {
1493
- return import_node_path4.default.join(this.dir, "index.json");
1661
+ return import_node_path5.default.join(this.dir, "index.json");
1494
1662
  }
1495
1663
  async load() {
1496
1664
  await import_promises4.default.mkdir(this.dir, { recursive: true });
@@ -1549,7 +1717,7 @@ var RunIndex = class {
1549
1717
  /** A stable Paperclip agent/company identity for this install, so the
1550
1718
  * driver's scratch state is reused rather than growing per run. */
1551
1719
  async identity() {
1552
- const file = import_node_path4.default.join(this.dir, "identity.json");
1720
+ const file = import_node_path5.default.join(this.dir, "identity.json");
1553
1721
  try {
1554
1722
  const parsed = JSON.parse(await import_promises4.default.readFile(file, "utf8"));
1555
1723
  if (typeof parsed.companyId === "string" && typeof parsed.agentId === "string") {
@@ -1565,8 +1733,8 @@ var RunIndex = class {
1565
1733
 
1566
1734
  // src/engine/user-defaults.ts
1567
1735
  var import_promises5 = __toESM(require("fs/promises"), 1);
1568
- var import_node_os3 = __toESM(require("os"), 1);
1569
- var import_node_path5 = __toESM(require("path"), 1);
1736
+ var import_node_os4 = __toESM(require("os"), 1);
1737
+ var import_node_path6 = __toESM(require("path"), 1);
1570
1738
  async function readJson(file) {
1571
1739
  try {
1572
1740
  const parsed = JSON.parse(await import_promises5.default.readFile(file, "utf8"));
@@ -1578,10 +1746,10 @@ async function readJson(file) {
1578
1746
  function str3(value) {
1579
1747
  return typeof value === "string" && value.trim() ? value.trim() : null;
1580
1748
  }
1581
- async function claudeDefaults(cwd, home = import_node_os3.default.homedir()) {
1749
+ async function claudeDefaults(cwd, home = import_node_os4.default.homedir()) {
1582
1750
  const files = [
1583
- ...cwd ? [import_node_path5.default.join(cwd, ".claude", "settings.local.json"), import_node_path5.default.join(cwd, ".claude", "settings.json")] : [],
1584
- import_node_path5.default.join(home, ".claude", "settings.json")
1751
+ ...cwd ? [import_node_path6.default.join(cwd, ".claude", "settings.local.json"), import_node_path6.default.join(cwd, ".claude", "settings.json")] : [],
1752
+ import_node_path6.default.join(home, ".claude", "settings.json")
1585
1753
  ];
1586
1754
  let model = null;
1587
1755
  let effort = null;
@@ -1594,10 +1762,10 @@ async function claudeDefaults(cwd, home = import_node_os3.default.homedir()) {
1594
1762
  }
1595
1763
  return { model, effort };
1596
1764
  }
1597
- async function codexDefaults(home = import_node_os3.default.homedir()) {
1765
+ async function codexDefaults(home = import_node_os4.default.homedir()) {
1598
1766
  let text;
1599
1767
  try {
1600
- text = await import_promises5.default.readFile(import_node_path5.default.join(home, ".codex", "config.toml"), "utf8");
1768
+ text = await import_promises5.default.readFile(import_node_path6.default.join(home, ".codex", "config.toml"), "utf8");
1601
1769
  } catch {
1602
1770
  return { model: null, effort: null };
1603
1771
  }
@@ -1621,45 +1789,33 @@ var EFFORT_LEVELS = {
1621
1789
  // src/engine/index.ts
1622
1790
  var RAW_TRANSCRIPT_MAX_BYTES = 200 * 1048576;
1623
1791
  function moduleDir() {
1624
- return import_node_path6.default.dirname((0, import_node_url.fileURLToPath)(importMetaUrl));
1792
+ return import_node_path7.default.dirname((0, import_node_url.fileURLToPath)(importMetaUrl));
1625
1793
  }
1626
1794
  function resolveWorkerPath() {
1627
1795
  const dir = moduleDir();
1628
1796
  for (const candidate of [
1629
- import_node_path6.default.join(dir, "worker.js"),
1630
- import_node_path6.default.join(dir, "worker.ts"),
1631
- import_node_path6.default.join(dir, "..", "engine", "worker.js"),
1632
- import_node_path6.default.join(dir, "..", "engine", "worker.ts")
1797
+ import_node_path7.default.join(dir, "worker.js"),
1798
+ import_node_path7.default.join(dir, "worker.ts"),
1799
+ import_node_path7.default.join(dir, "..", "engine", "worker.js"),
1800
+ import_node_path7.default.join(dir, "..", "engine", "worker.ts")
1633
1801
  ]) {
1634
- if ((0, import_node_fs3.existsSync)(candidate)) return candidate;
1802
+ if ((0, import_node_fs4.existsSync)(candidate)) return candidate;
1635
1803
  }
1636
1804
  throw new Error(`[coding-sessions] The driver worker is missing next to ${dir}.`);
1637
1805
  }
1638
1806
  async function installShim(dataDir) {
1639
- const source = import_node_path6.default.resolve(moduleDir(), "..", "..", "bin", "cli-shim.sh");
1640
- if (!(0, import_node_fs3.existsSync)(source)) throw new Error(`[coding-sessions] The CLI shim is missing at ${source}.`);
1807
+ const source = import_node_path7.default.resolve(moduleDir(), "..", "..", "bin", "cli-shim.sh");
1808
+ if (!(0, import_node_fs4.existsSync)(source)) throw new Error(`[coding-sessions] The CLI shim is missing at ${source}.`);
1641
1809
  const body = await import_promises6.default.readFile(source, "utf8");
1642
- const target = import_node_path6.default.join(dataDir, "bin", "cli-shim.sh");
1810
+ const target = import_node_path7.default.join(dataDir, "bin", "cli-shim.sh");
1643
1811
  const current = await import_promises6.default.readFile(target, "utf8").catch(() => null);
1644
1812
  if (current !== body) {
1645
- await import_promises6.default.mkdir(import_node_path6.default.dirname(target), { recursive: true });
1813
+ await import_promises6.default.mkdir(import_node_path7.default.dirname(target), { recursive: true });
1646
1814
  await import_promises6.default.writeFile(target, body, { mode: 493 });
1647
1815
  }
1648
1816
  await import_promises6.default.chmod(target, 493);
1649
1817
  return target;
1650
1818
  }
1651
- function whichOnPath(name, pathValue) {
1652
- for (const dir of pathValue.split(import_node_path6.default.delimiter)) {
1653
- if (!dir) continue;
1654
- const candidate = import_node_path6.default.join(dir, name);
1655
- try {
1656
- (0, import_node_fs3.accessSync)(candidate, import_node_fs3.constants.X_OK);
1657
- return candidate;
1658
- } catch {
1659
- }
1660
- }
1661
- return null;
1662
- }
1663
1819
  function nowIso() {
1664
1820
  return (/* @__PURE__ */ new Date()).toISOString();
1665
1821
  }
@@ -1698,12 +1854,14 @@ function describeProviderStatus(provider, probe, lastProblem = null, quota = [])
1698
1854
  function describeAuthStatus(provider, probe) {
1699
1855
  const label = PROVIDER_LABEL[provider];
1700
1856
  const installed = probe?.installed === true;
1701
- const version = typeof probe?.version === "string" ? probe.version : null;
1857
+ const binary = probe?.binary ?? null;
1858
+ const version = binary?.version ?? (typeof probe?.version === "string" ? probe.version : null);
1702
1859
  const base = {
1703
1860
  provider,
1704
1861
  label,
1705
1862
  installed,
1706
1863
  version,
1864
+ binary,
1707
1865
  loggedIn: false,
1708
1866
  billing: "unknown",
1709
1867
  plan: null,
@@ -1755,8 +1913,8 @@ function describeAuthStatus(provider, probe) {
1755
1913
  };
1756
1914
  }
1757
1915
  async function createCodingSessionsEngine(options = {}) {
1758
- const dataDir = options.dataDir ?? import_node_path6.default.join(import_node_os4.default.homedir(), ".matrx", "coding-sessions");
1759
- const stateDir = import_node_path6.default.join(dataDir, "paperclip-state");
1916
+ const dataDir = options.dataDir ?? import_node_path7.default.join(import_node_os5.default.homedir(), ".matrx", "coding-sessions");
1917
+ const stateDir = import_node_path7.default.join(dataDir, "paperclip-state");
1760
1918
  const homes = options.homes ?? defaultProviderHomes();
1761
1919
  const index = new RunIndex(dataDir);
1762
1920
  await index.load();
@@ -1770,7 +1928,7 @@ async function createCodingSessionsEngine(options = {}) {
1770
1928
  onError: (error) => console.warn("[coding-sessions] raw transcript backup failed:", error)
1771
1929
  }) : null;
1772
1930
  const discoveredSeen = /* @__PURE__ */ new Map();
1773
- const healthFile = import_node_path6.default.join(dataDir, "provider-health.json");
1931
+ const healthFile = import_node_path7.default.join(dataDir, "provider-health.json");
1774
1932
  let health = {};
1775
1933
  try {
1776
1934
  health = JSON.parse(await import_promises6.default.readFile(healthFile, "utf8"));
@@ -1805,7 +1963,24 @@ async function createCodingSessionsEngine(options = {}) {
1805
1963
  // Marks the forked process as a driver worker (see worker.ts).
1806
1964
  MATRX_CODING_SESSIONS_WORKER: "1"
1807
1965
  });
1808
- const commandFor = (provider) => options.commands?.[provider] ?? whichOnPath(provider, workerEnv.PATH ?? "");
1966
+ const binaryHome = options.hostEnv?.HOME ?? import_node_os5.default.homedir();
1967
+ const binaryCache = /* @__PURE__ */ new Map();
1968
+ function binaryFor(provider, fresh = false) {
1969
+ const cached = binaryCache.get(provider);
1970
+ if (cached && !fresh && Date.now() - cached.at < 5 * 6e4) return cached.value;
1971
+ const forced = options.commands?.[provider];
1972
+ const value = resolveBinary(provider, {
1973
+ env: workerEnv,
1974
+ home: binaryHome,
1975
+ forced,
1976
+ // A forced command needs no discovery to run; the status check still
1977
+ // looks, so it can say when a newer copy exists.
1978
+ discover: !forced || fresh
1979
+ }).catch(() => forced ? { path: forced, version: null, source: "configured", sourceLabel: "set by host", newer: null } : null);
1980
+ if (!forced || !fresh) binaryCache.set(provider, { at: Date.now(), value });
1981
+ return value;
1982
+ }
1983
+ const commandFor = async (provider) => (await binaryFor(provider))?.path ?? null;
1809
1984
  const workerPath = resolveWorkerPath();
1810
1985
  const shimPath = await installShim(dataDir);
1811
1986
  const listeners = /* @__PURE__ */ new Set();
@@ -1855,7 +2030,7 @@ async function createCodingSessionsEngine(options = {}) {
1855
2030
  }
1856
2031
  }
1857
2032
  function forkWorker() {
1858
- return (0, import_node_child_process2.fork)(workerPath, [], {
2033
+ return (0, import_node_child_process3.fork)(workerPath, [], {
1859
2034
  env: workerEnv,
1860
2035
  cwd: dataDir,
1861
2036
  stdio: ["ignore", "pipe", "pipe", "ipc"],
@@ -1876,7 +2051,7 @@ async function createCodingSessionsEngine(options = {}) {
1876
2051
  }
1877
2052
  async function startRun(session, prompt) {
1878
2053
  const provider = session.provider;
1879
- const realCommand = commandFor(provider);
2054
+ const realCommand = await commandFor(provider);
1880
2055
  const runId = (0, import_node_crypto4.randomUUID)();
1881
2056
  const model = session.model ?? (provider === "claude" ? (await userDefaults(provider, session.cwd)).model ?? null : null);
1882
2057
  const run = {
@@ -2108,7 +2283,7 @@ async function createCodingSessionsEngine(options = {}) {
2108
2283
  }, 3e3);
2109
2284
  }
2110
2285
  async function pruneDriverScratch() {
2111
- const runsDir = import_node_path6.default.join(
2286
+ const runsDir = import_node_path7.default.join(
2112
2287
  stateDir,
2113
2288
  "instances",
2114
2289
  "default",
@@ -2121,10 +2296,11 @@ async function createCodingSessionsEngine(options = {}) {
2121
2296
  );
2122
2297
  const entries = await import_promises6.default.readdir(runsDir).catch(() => []);
2123
2298
  await Promise.all(
2124
- entries.filter((name) => !live.has(name)).map((name) => import_promises6.default.rm(import_node_path6.default.join(runsDir, name), { recursive: true, force: true }).catch(() => void 0))
2299
+ entries.filter((name) => !live.has(name)).map((name) => import_promises6.default.rm(import_node_path7.default.join(runsDir, name), { recursive: true, force: true }).catch(() => void 0))
2125
2300
  );
2126
2301
  }
2127
2302
  async function probe() {
2303
+ const [claudeBinary, codexBinary] = await Promise.all([binaryFor("claude", true), binaryFor("codex", true)]);
2128
2304
  return new Promise((resolve) => {
2129
2305
  const child = forkWorker();
2130
2306
  let answered = false;
@@ -2140,8 +2316,8 @@ async function createCodingSessionsEngine(options = {}) {
2140
2316
  answered = true;
2141
2317
  clearTimeout(timer);
2142
2318
  resolve({
2143
- claude: message.claude ?? {},
2144
- codex: message.codex ?? {}
2319
+ claude: { ...message.claude ?? {}, binary: claudeBinary },
2320
+ codex: { ...message.codex ?? {}, binary: codexBinary }
2145
2321
  });
2146
2322
  }
2147
2323
  });
@@ -2153,7 +2329,7 @@ async function createCodingSessionsEngine(options = {}) {
2153
2329
  });
2154
2330
  child.send({
2155
2331
  kind: "probe",
2156
- commands: { claude: commandFor("claude"), codex: commandFor("codex") },
2332
+ commands: { claude: claudeBinary?.path ?? null, codex: codexBinary?.path ?? null },
2157
2333
  quota: options.quota !== false
2158
2334
  });
2159
2335
  });
@@ -2179,7 +2355,7 @@ async function createCodingSessionsEngine(options = {}) {
2179
2355
  function resolveFolder(raw) {
2180
2356
  const trimmed = raw.trim();
2181
2357
  if (!trimmed) return null;
2182
- return import_node_path6.default.resolve(trimmed.replace(/^~(?=$|\/)/, import_node_os4.default.homedir()));
2358
+ return import_node_path7.default.resolve(trimmed.replace(/^~(?=$|\/)/, import_node_os5.default.homedir()));
2183
2359
  }
2184
2360
  async function checkFolder(raw) {
2185
2361
  const target = resolveFolder(raw);
@@ -2188,7 +2364,7 @@ async function createCodingSessionsEngine(options = {}) {
2188
2364
  return { path: target, exists: stat !== null, isDirectory: stat?.isDirectory() === true };
2189
2365
  }
2190
2366
  async function assertFolder(cwd) {
2191
- const resolved = import_node_path6.default.resolve(cwd.replace(/^~(?=$|\/)/, import_node_os4.default.homedir()));
2367
+ const resolved = import_node_path7.default.resolve(cwd.replace(/^~(?=$|\/)/, import_node_os5.default.homedir()));
2192
2368
  const stat = await import_promises6.default.stat(resolved).catch(() => null);
2193
2369
  if (!stat?.isDirectory()) {
2194
2370
  throw new Error(`The folder ${resolved} doesn't exist on this computer.`);
@@ -2342,7 +2518,7 @@ async function createCodingSessionsEngine(options = {}) {
2342
2518
  };
2343
2519
  }
2344
2520
  const content = await import_promises6.default.readFile(file, "utf8");
2345
- return { available: true, fileName: import_node_path6.default.basename(file), bytes: stat.size, content };
2521
+ return { available: true, fileName: import_node_path7.default.basename(file), bytes: stat.size, content };
2346
2522
  },
2347
2523
  async start(input) {
2348
2524
  const prompt = input.prompt.trim();
@@ -2463,7 +2639,7 @@ function openFolderIn(folder, target) {
2463
2639
  args = ["-a", app.app, folder];
2464
2640
  }
2465
2641
  return new Promise((resolve, reject) => {
2466
- (0, import_node_child_process2.execFile)(command, args, { timeout: 1e4 }, (error) => {
2642
+ (0, import_node_child_process3.execFile)(command, args, { timeout: 1e4 }, (error) => {
2467
2643
  if (!error) return resolve();
2468
2644
  const label = target === "finder" ? "the folder" : OPEN_APP[target]?.label ?? target;
2469
2645
  reject(