cli-remote-agent 1.0.6 → 1.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -251,20 +251,58 @@ function startLocalControl(port, onHook) {
251
251
  return server;
252
252
  }
253
253
 
254
+ // src/pty-helper-fix.ts
255
+ var import_node_module = require("module");
256
+ var import_node_child_process = require("child_process");
257
+ var import_fs3 = __toESM(require("fs"));
258
+ var import_path3 = __toESM(require("path"));
259
+ function ensurePtyHelperExecutable() {
260
+ if (process.platform === "win32") return;
261
+ try {
262
+ const nodeRequire = (0, import_node_module.createRequire)(__filename);
263
+ const ptyMain = nodeRequire.resolve("node-pty");
264
+ const ptyDir = import_path3.default.dirname(import_path3.default.dirname(ptyMain));
265
+ const candidates = [import_path3.default.join(ptyDir, "build", "Release", "spawn-helper")];
266
+ const prebuilds = import_path3.default.join(ptyDir, "prebuilds");
267
+ try {
268
+ for (const d of import_fs3.default.readdirSync(prebuilds)) {
269
+ candidates.push(import_path3.default.join(prebuilds, d, "spawn-helper"));
270
+ }
271
+ } catch {
272
+ }
273
+ for (const file of candidates) {
274
+ try {
275
+ const mode = import_fs3.default.statSync(file).mode;
276
+ if (!(mode & 73)) {
277
+ import_fs3.default.chmodSync(file, mode | 493);
278
+ logger.info({ file }, "Restored execute bit on node-pty spawn-helper");
279
+ }
280
+ } catch {
281
+ }
282
+ }
283
+ if (process.platform === "darwin") {
284
+ (0, import_node_child_process.execFile)("xattr", ["-dr", "com.apple.quarantine", ptyDir], () => {
285
+ });
286
+ }
287
+ } catch (err) {
288
+ logger.warn({ error: err?.message }, "Could not verify node-pty spawn-helper permissions");
289
+ }
290
+ }
291
+
254
292
  // src/tmux.ts
255
293
  var import_child_process2 = require("child_process");
256
294
  var import_util2 = require("util");
257
- var import_fs4 = __toESM(require("fs"));
258
- var import_path4 = __toESM(require("path"));
295
+ var import_fs5 = __toESM(require("fs"));
296
+ var import_path5 = __toESM(require("path"));
259
297
 
260
298
  // src/claude-live.ts
261
- var import_fs3 = __toESM(require("fs"));
262
- var import_path3 = __toESM(require("path"));
299
+ var import_fs4 = __toESM(require("fs"));
300
+ var import_path4 = __toESM(require("path"));
263
301
  var import_os2 = __toESM(require("os"));
264
302
  var import_child_process = require("child_process");
265
303
  var import_util = require("util");
266
304
  var execFileAsync = (0, import_util.promisify)(import_child_process.execFile);
267
- var LIVE_SESSIONS_DIR = import_path3.default.join(import_os2.default.homedir(), ".claude", "sessions");
305
+ var LIVE_SESSIONS_DIR = import_path4.default.join(import_os2.default.homedir(), ".claude", "sessions");
268
306
  function isAlive(pid) {
269
307
  try {
270
308
  process.kill(pid, 0);
@@ -276,14 +314,14 @@ function isAlive(pid) {
276
314
  function getLiveClaudeSessions() {
277
315
  let files;
278
316
  try {
279
- files = import_fs3.default.readdirSync(LIVE_SESSIONS_DIR).filter((f) => f.endsWith(".json"));
317
+ files = import_fs4.default.readdirSync(LIVE_SESSIONS_DIR).filter((f) => f.endsWith(".json"));
280
318
  } catch {
281
319
  return [];
282
320
  }
283
321
  const out = [];
284
322
  for (const f of files) {
285
323
  try {
286
- const obj = JSON.parse(import_fs3.default.readFileSync(import_path3.default.join(LIVE_SESSIONS_DIR, f), "utf-8"));
324
+ const obj = JSON.parse(import_fs4.default.readFileSync(import_path4.default.join(LIVE_SESSIONS_DIR, f), "utf-8"));
287
325
  if (typeof obj?.pid !== "number" || !isAlive(obj.pid)) continue;
288
326
  out.push({
289
327
  pid: obj.pid,
@@ -325,14 +363,14 @@ var IS_WIN = process.platform === "win32";
325
363
  var cachedTmuxPath;
326
364
  function resolveTmuxPath() {
327
365
  if (cachedTmuxPath !== void 0) return cachedTmuxPath;
328
- const dirs = (process.env.PATH || "").split(import_path4.default.delimiter).filter(Boolean);
366
+ const dirs = (process.env.PATH || "").split(import_path5.default.delimiter).filter(Boolean);
329
367
  for (const extra of ["/opt/homebrew/bin", "/usr/local/bin", "/usr/bin", "/bin", "/opt/local/bin"]) {
330
368
  if (!dirs.includes(extra)) dirs.push(extra);
331
369
  }
332
370
  for (const dir of dirs) {
333
- const candidate = import_path4.default.join(dir, "tmux");
371
+ const candidate = import_path5.default.join(dir, "tmux");
334
372
  try {
335
- import_fs4.default.accessSync(candidate, import_fs4.default.constants.X_OK);
373
+ import_fs5.default.accessSync(candidate, import_fs5.default.constants.X_OK);
336
374
  cachedTmuxPath = candidate;
337
375
  return candidate;
338
376
  } catch {
@@ -382,8 +420,8 @@ async function enrichWithPanesAndClaude(sessions2) {
382
420
  const { file, args } = tmuxCmd(["list-panes", "-a", "-F", paneFmt]);
383
421
  const { stdout } = await execFileAsync2(file, args, { timeout: 6e3 });
384
422
  const panes = stdout.split("\n").map((line) => line.replace(/\r$/, "").trim()).filter(Boolean).map((line) => {
385
- const [session, pid, path9, activeFlags] = line.split(" ");
386
- return { session, pid: parseInt(pid, 10) || 0, path: path9 || "", active: activeFlags === "11" };
423
+ const [session, pid, path10, activeFlags] = line.split(" ");
424
+ return { session, pid: parseInt(pid, 10) || 0, path: path10 || "", active: activeFlags === "11" };
387
425
  });
388
426
  const byName = new Map(sessions2.map((s) => [s.name, s]));
389
427
  for (const pane of panes) {
@@ -425,13 +463,13 @@ function buildTmuxLaunch(name, launch) {
425
463
 
426
464
  // src/heartbeat.ts
427
465
  var import_os4 = __toESM(require("os"));
428
- var import_path6 = __toESM(require("path"));
466
+ var import_path7 = __toESM(require("path"));
429
467
  var import_child_process4 = require("child_process");
430
468
 
431
469
  // src/pty-session.ts
432
470
  var pty = __toESM(require("node-pty"));
433
- var import_fs5 = require("fs");
434
- var import_path5 = require("path");
471
+ var import_fs6 = require("fs");
472
+ var import_path6 = require("path");
435
473
  var import_os3 = require("os");
436
474
 
437
475
  // src/shell.ts
@@ -451,22 +489,22 @@ function detectShell(preference) {
451
489
 
452
490
  // src/pty-session.ts
453
491
  var THRESHOLD = 3;
454
- var INIT_DIR = (0, import_path5.join)((0, import_os3.tmpdir)(), "crc-shell-init");
455
- var BASH_INIT = (0, import_path5.join)(INIT_DIR, "bashrc");
456
- var ZSH_DIR = (0, import_path5.join)(INIT_DIR, "zsh");
457
- var ZSH_RC = (0, import_path5.join)(ZSH_DIR, ".zshrc");
458
- var ZSH_ENV = (0, import_path5.join)(ZSH_DIR, ".zshenv");
492
+ var INIT_DIR = (0, import_path6.join)((0, import_os3.tmpdir)(), "crc-shell-init");
493
+ var BASH_INIT = (0, import_path6.join)(INIT_DIR, "bashrc");
494
+ var ZSH_DIR = (0, import_path6.join)(INIT_DIR, "zsh");
495
+ var ZSH_RC = (0, import_path6.join)(ZSH_DIR, ".zshrc");
496
+ var ZSH_ENV = (0, import_path6.join)(ZSH_DIR, ".zshenv");
459
497
  var INIT_VERSION = "2";
460
498
  function ensureInitFiles() {
461
- const versionFile = (0, import_path5.join)(INIT_DIR, ".version");
462
- if ((0, import_fs5.existsSync)(versionFile)) {
499
+ const versionFile = (0, import_path6.join)(INIT_DIR, ".version");
500
+ if ((0, import_fs6.existsSync)(versionFile)) {
463
501
  try {
464
- if ((0, import_fs5.readFileSync)(versionFile, "utf-8").trim() === INIT_VERSION) return;
502
+ if ((0, import_fs6.readFileSync)(versionFile, "utf-8").trim() === INIT_VERSION) return;
465
503
  } catch {
466
504
  }
467
505
  }
468
- (0, import_fs5.mkdirSync)(ZSH_DIR, { recursive: true });
469
- (0, import_fs5.writeFileSync)(BASH_INIT, [
506
+ (0, import_fs6.mkdirSync)(ZSH_DIR, { recursive: true });
507
+ (0, import_fs6.writeFileSync)(BASH_INIT, [
470
508
  "[ -f ~/.bash_profile ] && source ~/.bash_profile",
471
509
  "[ -f ~/.bashrc ] && source ~/.bashrc",
472
510
  "__crc_s=$SECONDS",
@@ -477,11 +515,11 @@ function ensureInitFiles() {
477
515
  `PROMPT_COMMAND='[ "$__crc_armed" = 1 ] && [ \${__crc_elapsed:-0} -ge ${THRESHOLD} ] && printf "\\a"; __crc_armed=1; eval "$__crc_orig_pc"'`,
478
516
  ""
479
517
  ].join("\n"), "utf-8");
480
- (0, import_fs5.writeFileSync)(ZSH_ENV, [
518
+ (0, import_fs6.writeFileSync)(ZSH_ENV, [
481
519
  '[ -f "${ZDOTDIR_ORIG:-$HOME}/.zshenv" ] && source "${ZDOTDIR_ORIG:-$HOME}/.zshenv"',
482
520
  ""
483
521
  ].join("\n"), "utf-8");
484
- (0, import_fs5.writeFileSync)(ZSH_RC, [
522
+ (0, import_fs6.writeFileSync)(ZSH_RC, [
485
523
  '[ -f "${ZDOTDIR_ORIG:-$HOME}/.zshrc" ] && source "${ZDOTDIR_ORIG:-$HOME}/.zshrc"',
486
524
  "__crc_s=$SECONDS",
487
525
  "__crc_armed=0",
@@ -494,14 +532,14 @@ function ensureInitFiles() {
494
532
  "fi",
495
533
  ""
496
534
  ].join("\n"), "utf-8");
497
- (0, import_fs5.writeFileSync)(versionFile, INIT_VERSION, "utf-8");
535
+ (0, import_fs6.writeFileSync)(versionFile, INIT_VERSION, "utf-8");
498
536
  }
499
537
  function resolveCwd(cwd) {
500
538
  const candidates = process.platform === "win32" ? [cwd, (0, import_os3.homedir)(), process.env.USERPROFILE, process.env.HOME] : [cwd, (0, import_os3.homedir)(), process.env.HOME, process.env.USERPROFILE];
501
539
  for (const c of candidates) {
502
540
  if (c) {
503
541
  try {
504
- if ((0, import_fs5.existsSync)(c)) return c;
542
+ if ((0, import_fs6.existsSync)(c)) return c;
505
543
  } catch {
506
544
  }
507
545
  }
@@ -727,7 +765,7 @@ function buildHeartbeat(homeDir) {
727
765
  memoryUsage: Math.round((totalMem - freeMem) / totalMem * 100),
728
766
  uptime: Math.round(import_os4.default.uptime()),
729
767
  activeSessions: getActiveSessionCount(),
730
- pathSeparator: import_path6.default.sep,
768
+ pathSeparator: import_path7.default.sep,
731
769
  homeDirectory: homeDir || import_os4.default.homedir(),
732
770
  rootPaths: getRootPaths(),
733
771
  capabilities: { terminal: true, fileTransfer: false }
@@ -735,33 +773,33 @@ function buildHeartbeat(homeDir) {
735
773
  }
736
774
 
737
775
  // src/file-explorer.ts
738
- var import_fs6 = __toESM(require("fs"));
739
- var import_path7 = __toESM(require("path"));
776
+ var import_fs7 = __toESM(require("fs"));
777
+ var import_path8 = __toESM(require("path"));
740
778
  var import_os5 = __toESM(require("os"));
741
- var SECRET_DIR = import_path7.default.join(import_os5.default.homedir(), ".crc-agent");
779
+ var SECRET_DIR = import_path8.default.join(import_os5.default.homedir(), ".crc-agent");
742
780
  function isInSecretDir(resolved) {
743
- const rel = import_path7.default.relative(SECRET_DIR, resolved);
744
- return rel === "" || !rel.startsWith(".." + import_path7.default.sep) && rel !== ".." && !import_path7.default.isAbsolute(rel);
781
+ const rel = import_path8.default.relative(SECRET_DIR, resolved);
782
+ return rel === "" || !rel.startsWith(".." + import_path8.default.sep) && rel !== ".." && !import_path8.default.isAbsolute(rel);
745
783
  }
746
784
  function listDirectory(dirPath) {
747
785
  try {
748
- const resolved = import_path7.default.resolve(dirPath);
786
+ const resolved = import_path8.default.resolve(dirPath);
749
787
  if (isInSecretDir(resolved)) {
750
788
  return { entries: [], error: "Access denied" };
751
789
  }
752
- if (!import_fs6.default.existsSync(resolved)) {
790
+ if (!import_fs7.default.existsSync(resolved)) {
753
791
  return { entries: [], error: "Path does not exist" };
754
792
  }
755
- const stat = import_fs6.default.statSync(resolved);
793
+ const stat = import_fs7.default.statSync(resolved);
756
794
  if (!stat.isDirectory()) {
757
795
  return { entries: [], error: "Not a directory" };
758
796
  }
759
- const dirents = import_fs6.default.readdirSync(resolved, { withFileTypes: true });
797
+ const dirents = import_fs7.default.readdirSync(resolved, { withFileTypes: true });
760
798
  const entries = [];
761
799
  for (const dirent of dirents) {
762
800
  try {
763
- const fullPath = import_path7.default.join(resolved, dirent.name);
764
- const s = import_fs6.default.statSync(fullPath);
801
+ const fullPath = import_path8.default.join(resolved, dirent.name);
802
+ const s = import_fs7.default.statSync(fullPath);
765
803
  entries.push({
766
804
  name: dirent.name,
767
805
  isDirectory: dirent.isDirectory(),
@@ -783,22 +821,22 @@ function listDirectory(dirPath) {
783
821
  }
784
822
  async function downloadFile(filePath, serverUrl, secret, agentId) {
785
823
  try {
786
- const resolved = import_path7.default.resolve(filePath);
824
+ const resolved = import_path8.default.resolve(filePath);
787
825
  if (isInSecretDir(resolved)) {
788
826
  return { error: "Access denied" };
789
827
  }
790
- if (!import_fs6.default.existsSync(resolved)) {
828
+ if (!import_fs7.default.existsSync(resolved)) {
791
829
  return { error: "File does not exist" };
792
830
  }
793
- const stat = import_fs6.default.statSync(resolved);
831
+ const stat = import_fs7.default.statSync(resolved);
794
832
  if (stat.isDirectory()) {
795
833
  return { error: "Cannot download a directory" };
796
834
  }
797
835
  if (stat.size > FILE_MAX_SIZE) {
798
836
  return { error: `File too large (max ${FILE_MAX_SIZE} bytes)` };
799
837
  }
800
- const fileName = import_path7.default.basename(resolved);
801
- const fileStream = import_fs6.default.createReadStream(resolved);
838
+ const fileName = import_path8.default.basename(resolved);
839
+ const fileStream = import_fs7.default.createReadStream(resolved);
802
840
  const baseUrl = serverUrl.replace("wss://", "https://").replace("ws://", "http://");
803
841
  const url = `${baseUrl}/api/files/receive`;
804
842
  const res = await fetch(url, {
@@ -831,12 +869,12 @@ async function downloadFile(filePath, serverUrl, secret, agentId) {
831
869
  // src/vpn-manager.ts
832
870
  var import_child_process5 = require("child_process");
833
871
  var import_util3 = require("util");
834
- var import_fs7 = __toESM(require("fs"));
835
- var import_path8 = __toESM(require("path"));
872
+ var import_fs8 = __toESM(require("fs"));
873
+ var import_path9 = __toESM(require("path"));
836
874
  var import_os6 = __toESM(require("os"));
837
875
  var execAsync = (0, import_util3.promisify)(import_child_process5.exec);
838
876
  var isWindows = process.platform === "win32";
839
- var VPN_DIR = import_path8.default.join(import_os6.default.homedir(), ".crc-agent", "vpn");
877
+ var VPN_DIR = import_path9.default.join(import_os6.default.homedir(), ".crc-agent", "vpn");
840
878
  function shq(value) {
841
879
  return value.replace(/'/g, "'\\''");
842
880
  }
@@ -855,8 +893,8 @@ async function runCmd(cmd, shell) {
855
893
  }
856
894
  function getConfigPath(profile) {
857
895
  const file = profile.configFile || `${profile.id}.conf`;
858
- if (import_path8.default.isAbsolute(file)) return file;
859
- return import_path8.default.join(VPN_DIR, file);
896
+ if (import_path9.default.isAbsolute(file)) return file;
897
+ return import_path9.default.join(VPN_DIR, file);
860
898
  }
861
899
  async function getScutilStatus(serviceName) {
862
900
  const { stdout } = await runCmd(`scutil --nc status '${shq(serviceName)}'`);
@@ -972,7 +1010,7 @@ async function connectWireGuard(profile) {
972
1010
  const tunnelName = profile.tunnelName || profile.id;
973
1011
  if (isWindows) {
974
1012
  const confPath2 = getConfigPath(profile);
975
- if (!import_fs7.default.existsSync(confPath2)) {
1013
+ if (!import_fs8.default.existsSync(confPath2)) {
976
1014
  return `Config file not found: ${confPath2}`;
977
1015
  }
978
1016
  const script = `
@@ -998,7 +1036,7 @@ async function connectWireGuard(profile) {
998
1036
  async function connectOpenVpn(profile) {
999
1037
  if (isWindows) {
1000
1038
  const confPath2 = getConfigPath(profile);
1001
- if (!import_fs7.default.existsSync(confPath2)) {
1039
+ if (!import_fs8.default.existsSync(confPath2)) {
1002
1040
  return `Config file not found: ${confPath2}`;
1003
1041
  }
1004
1042
  const connector = "C:\\Program Files\\OpenVPN Connect\\ovpnconnector.exe";
@@ -1025,7 +1063,7 @@ async function connectOpenVpn(profile) {
1025
1063
  return scutilStart(profile.serviceName);
1026
1064
  }
1027
1065
  const confPath = getConfigPath(profile);
1028
- if (!import_fs7.default.existsSync(confPath)) {
1066
+ if (!import_fs8.default.existsSync(confPath)) {
1029
1067
  return `Config file not found: ${confPath}`;
1030
1068
  }
1031
1069
  const { stderr } = await runCmd(`sudo openvpn --config '${shq(confPath)}' --daemon`);
@@ -1034,7 +1072,7 @@ async function connectOpenVpn(profile) {
1034
1072
  async function connectAzure(profile) {
1035
1073
  if (isWindows) {
1036
1074
  const confPath = getConfigPath(profile);
1037
- if (!import_fs7.default.existsSync(confPath)) {
1075
+ if (!import_fs8.default.existsSync(confPath)) {
1038
1076
  return `Config file not found: ${confPath}`;
1039
1077
  }
1040
1078
  await runCmd(`& 'AzureVpn.exe' -i '${psq(confPath)}' 2>&1`);
@@ -1156,8 +1194,8 @@ async function disconnectVpn(configs, profileId) {
1156
1194
  }
1157
1195
 
1158
1196
  // src/claude-sessions.ts
1159
- var import_fs8 = __toESM(require("fs"));
1160
- var import_path9 = __toESM(require("path"));
1197
+ var import_fs9 = __toESM(require("fs"));
1198
+ var import_path10 = __toESM(require("path"));
1161
1199
  var import_os7 = __toESM(require("os"));
1162
1200
  var import_readline = __toESM(require("readline"));
1163
1201
 
@@ -1185,10 +1223,10 @@ function findProjectDirs(allDirs, filterProjectPath) {
1185
1223
  }
1186
1224
 
1187
1225
  // src/claude-sessions.ts
1188
- var CLAUDE_PROJECTS_DIR = import_path9.default.join(import_os7.default.homedir(), ".claude", "projects");
1226
+ var CLAUDE_PROJECTS_DIR = import_path10.default.join(import_os7.default.homedir(), ".claude", "projects");
1189
1227
  async function parseSessionFile(filePath) {
1190
1228
  try {
1191
- const stream = import_fs8.default.createReadStream(filePath, { encoding: "utf-8" });
1229
+ const stream = import_fs9.default.createReadStream(filePath, { encoding: "utf-8" });
1192
1230
  const rl = import_readline.default.createInterface({ input: stream, crlfDelay: Infinity });
1193
1231
  let firstMessage = "";
1194
1232
  let lastTimestamp = "";
@@ -1236,17 +1274,17 @@ async function parseSessionFile(filePath) {
1236
1274
  }
1237
1275
  async function listClaudeSessions(filterProjectPath) {
1238
1276
  const sessions2 = [];
1239
- if (!import_fs8.default.existsSync(CLAUDE_PROJECTS_DIR)) return sessions2;
1277
+ if (!import_fs9.default.existsSync(CLAUDE_PROJECTS_DIR)) return sessions2;
1240
1278
  const isDirSafe = (d) => {
1241
1279
  try {
1242
- return import_fs8.default.statSync(import_path9.default.join(CLAUDE_PROJECTS_DIR, d)).isDirectory();
1280
+ return import_fs9.default.statSync(import_path10.default.join(CLAUDE_PROJECTS_DIR, d)).isDirectory();
1243
1281
  } catch {
1244
1282
  return false;
1245
1283
  }
1246
1284
  };
1247
1285
  let allEntries;
1248
1286
  try {
1249
- allEntries = import_fs8.default.readdirSync(CLAUDE_PROJECTS_DIR);
1287
+ allEntries = import_fs9.default.readdirSync(CLAUDE_PROJECTS_DIR);
1250
1288
  } catch {
1251
1289
  return sessions2;
1252
1290
  }
@@ -1259,16 +1297,16 @@ async function listClaudeSessions(filterProjectPath) {
1259
1297
  projectDirs = allEntries.filter((d) => isDirSafe(d) && !d.startsWith("-private-"));
1260
1298
  }
1261
1299
  for (const dirName of projectDirs) {
1262
- const dirPath = import_path9.default.join(CLAUDE_PROJECTS_DIR, dirName);
1300
+ const dirPath = import_path10.default.join(CLAUDE_PROJECTS_DIR, dirName);
1263
1301
  let files;
1264
1302
  try {
1265
- files = import_fs8.default.readdirSync(dirPath).filter((f) => f.endsWith(".jsonl"));
1303
+ files = import_fs9.default.readdirSync(dirPath).filter((f) => f.endsWith(".jsonl"));
1266
1304
  } catch {
1267
1305
  continue;
1268
1306
  }
1269
1307
  for (const file of files) {
1270
1308
  const sessionId = file.replace(".jsonl", "");
1271
- const parsed = await parseSessionFile(import_path9.default.join(dirPath, file));
1309
+ const parsed = await parseSessionFile(import_path10.default.join(dirPath, file));
1272
1310
  if (!parsed) continue;
1273
1311
  const projectPath = parsed.cwd || dirName.replace(/^-/, "/").replace(/-/g, "/");
1274
1312
  sessions2.push({
@@ -1288,21 +1326,21 @@ async function listClaudeSessions(filterProjectPath) {
1288
1326
  }
1289
1327
 
1290
1328
  // src/claude-conversation.ts
1291
- var import_fs9 = __toESM(require("fs"));
1292
- var import_path10 = __toESM(require("path"));
1329
+ var import_fs10 = __toESM(require("fs"));
1330
+ var import_path11 = __toESM(require("path"));
1293
1331
  var import_os8 = __toESM(require("os"));
1294
1332
  var import_readline2 = __toESM(require("readline"));
1295
- var CLAUDE_PROJECTS_DIR2 = import_path10.default.join(import_os8.default.homedir(), ".claude", "projects");
1333
+ var CLAUDE_PROJECTS_DIR2 = import_path11.default.join(import_os8.default.homedir(), ".claude", "projects");
1296
1334
  function findProjectDir(projectPath) {
1297
1335
  const encoded = encodeProjectPath(projectPath);
1298
- const dirPath = import_path10.default.join(CLAUDE_PROJECTS_DIR2, encoded);
1299
- if (import_fs9.default.existsSync(dirPath)) return dirPath;
1300
- if (!import_fs9.default.existsSync(CLAUDE_PROJECTS_DIR2)) return null;
1336
+ const dirPath = import_path11.default.join(CLAUDE_PROJECTS_DIR2, encoded);
1337
+ if (import_fs10.default.existsSync(dirPath)) return dirPath;
1338
+ if (!import_fs10.default.existsSync(CLAUDE_PROJECTS_DIR2)) return null;
1301
1339
  let allDirs;
1302
1340
  try {
1303
- allDirs = import_fs9.default.readdirSync(CLAUDE_PROJECTS_DIR2).filter((d) => {
1341
+ allDirs = import_fs10.default.readdirSync(CLAUDE_PROJECTS_DIR2).filter((d) => {
1304
1342
  try {
1305
- return import_fs9.default.statSync(import_path10.default.join(CLAUDE_PROJECTS_DIR2, d)).isDirectory();
1343
+ return import_fs10.default.statSync(import_path11.default.join(CLAUDE_PROJECTS_DIR2, d)).isDirectory();
1306
1344
  } catch {
1307
1345
  return false;
1308
1346
  }
@@ -1312,23 +1350,23 @@ function findProjectDir(projectPath) {
1312
1350
  }
1313
1351
  const matches = findProjectDirs(allDirs, projectPath);
1314
1352
  if (matches.length > 0) {
1315
- return import_path10.default.join(CLAUDE_PROJECTS_DIR2, matches[0]);
1353
+ return import_path11.default.join(CLAUDE_PROJECTS_DIR2, matches[0]);
1316
1354
  }
1317
1355
  return null;
1318
1356
  }
1319
1357
  function findSessionFileById(sessionId) {
1320
1358
  if (!/^[A-Za-z0-9._-]+$/.test(sessionId)) return null;
1321
- if (!import_fs9.default.existsSync(CLAUDE_PROJECTS_DIR2)) return null;
1359
+ if (!import_fs10.default.existsSync(CLAUDE_PROJECTS_DIR2)) return null;
1322
1360
  let dirs;
1323
1361
  try {
1324
- dirs = import_fs9.default.readdirSync(CLAUDE_PROJECTS_DIR2);
1362
+ dirs = import_fs10.default.readdirSync(CLAUDE_PROJECTS_DIR2);
1325
1363
  } catch {
1326
1364
  return null;
1327
1365
  }
1328
1366
  for (const dir of dirs) {
1329
- const candidate = import_path10.default.join(CLAUDE_PROJECTS_DIR2, dir, `${sessionId}.jsonl`);
1367
+ const candidate = import_path11.default.join(CLAUDE_PROJECTS_DIR2, dir, `${sessionId}.jsonl`);
1330
1368
  try {
1331
- if (import_fs9.default.statSync(candidate).isFile()) return candidate;
1369
+ if (import_fs10.default.statSync(candidate).isFile()) return candidate;
1332
1370
  } catch {
1333
1371
  }
1334
1372
  }
@@ -1339,20 +1377,20 @@ function findLatestSessionFile(projectPath) {
1339
1377
  if (!dirPath) return null;
1340
1378
  let entries;
1341
1379
  try {
1342
- entries = import_fs9.default.readdirSync(dirPath);
1380
+ entries = import_fs10.default.readdirSync(dirPath);
1343
1381
  } catch {
1344
1382
  return null;
1345
1383
  }
1346
1384
  const files = entries.filter((f) => f.endsWith(".jsonl") && !f.includes("/")).map((f) => {
1347
1385
  try {
1348
- return { name: f, mtime: import_fs9.default.statSync(import_path10.default.join(dirPath, f)).mtimeMs };
1386
+ return { name: f, mtime: import_fs10.default.statSync(import_path11.default.join(dirPath, f)).mtimeMs };
1349
1387
  } catch {
1350
1388
  return null;
1351
1389
  }
1352
1390
  }).filter((f) => f !== null).sort((a, b) => b.mtime - a.mtime);
1353
1391
  if (files.length === 0) return null;
1354
1392
  return {
1355
- filePath: import_path10.default.join(dirPath, files[0].name),
1393
+ filePath: import_path11.default.join(dirPath, files[0].name),
1356
1394
  sessionId: files[0].name.replace(".jsonl", "")
1357
1395
  };
1358
1396
  }
@@ -1362,8 +1400,8 @@ async function readConversation(projectPath, afterLine = 0, specificSessionId) {
1362
1400
  if (specificSessionId) {
1363
1401
  sessionId = specificSessionId;
1364
1402
  const dirPath = findProjectDir(projectPath);
1365
- const direct = dirPath ? import_path10.default.join(dirPath, `${specificSessionId}.jsonl`) : null;
1366
- if (direct && import_fs9.default.existsSync(direct)) {
1403
+ const direct = dirPath ? import_path11.default.join(dirPath, `${specificSessionId}.jsonl`) : null;
1404
+ if (direct && import_fs10.default.existsSync(direct)) {
1367
1405
  filePath = direct;
1368
1406
  } else {
1369
1407
  const byId = findSessionFileById(specificSessionId);
@@ -1377,7 +1415,7 @@ async function readConversation(projectPath, afterLine = 0, specificSessionId) {
1377
1415
  sessionId = found.sessionId;
1378
1416
  }
1379
1417
  try {
1380
- const stream = import_fs9.default.createReadStream(filePath, { encoding: "utf-8" });
1418
+ const stream = import_fs10.default.createReadStream(filePath, { encoding: "utf-8" });
1381
1419
  const rl = import_readline2.default.createInterface({ input: stream, crlfDelay: Infinity });
1382
1420
  const messages = [];
1383
1421
  let lineNum = 0;
@@ -1466,6 +1504,7 @@ if (!isConfigured()) {
1466
1504
  }
1467
1505
  var config = loadConfig();
1468
1506
  logger.info({ agentId: config.agentId, serverUrl: config.serverUrl }, "Starting agent");
1507
+ ensurePtyHelperExecutable();
1469
1508
  process.on("unhandledRejection", (reason) => {
1470
1509
  logger.error({ reason }, "Unhandled promise rejection (agent kept alive)");
1471
1510
  });