cli-remote-agent 1.0.1 → 1.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -250,9 +250,73 @@ function startLocalControl(port, onHook) {
250
250
  }
251
251
 
252
252
  // src/tmux.ts
253
+ var import_child_process2 = require("child_process");
254
+ var import_util2 = require("util");
255
+
256
+ // src/claude-live.ts
257
+ var import_fs3 = __toESM(require("fs"));
258
+ var import_path3 = __toESM(require("path"));
259
+ var import_os2 = __toESM(require("os"));
253
260
  var import_child_process = require("child_process");
254
261
  var import_util = require("util");
255
262
  var execFileAsync = (0, import_util.promisify)(import_child_process.execFile);
263
+ var LIVE_SESSIONS_DIR = import_path3.default.join(import_os2.default.homedir(), ".claude", "sessions");
264
+ function isAlive(pid) {
265
+ try {
266
+ process.kill(pid, 0);
267
+ return true;
268
+ } catch {
269
+ return false;
270
+ }
271
+ }
272
+ function getLiveClaudeSessions() {
273
+ let files;
274
+ try {
275
+ files = import_fs3.default.readdirSync(LIVE_SESSIONS_DIR).filter((f) => f.endsWith(".json"));
276
+ } catch {
277
+ return [];
278
+ }
279
+ const out = [];
280
+ for (const f of files) {
281
+ try {
282
+ const obj = JSON.parse(import_fs3.default.readFileSync(import_path3.default.join(LIVE_SESSIONS_DIR, f), "utf-8"));
283
+ if (typeof obj?.pid !== "number" || !isAlive(obj.pid)) continue;
284
+ out.push({
285
+ pid: obj.pid,
286
+ cwd: typeof obj.cwd === "string" ? obj.cwd : "",
287
+ name: typeof obj.name === "string" ? obj.name : void 0,
288
+ status: typeof obj.status === "string" ? obj.status : void 0,
289
+ updatedAt: typeof obj.updatedAt === "number" ? obj.updatedAt : void 0
290
+ });
291
+ } catch {
292
+ }
293
+ }
294
+ out.sort((a, b) => (a.updatedAt || 0) - (b.updatedAt || 0));
295
+ return out;
296
+ }
297
+ async function getPidParents() {
298
+ const map = /* @__PURE__ */ new Map();
299
+ try {
300
+ const { stdout } = await execFileAsync("ps", ["-axo", "pid=,ppid="], { timeout: 5e3 });
301
+ for (const line of stdout.split("\n")) {
302
+ const m = line.trim().match(/^(\d+)\s+(\d+)$/);
303
+ if (m) map.set(parseInt(m[1], 10), parseInt(m[2], 10));
304
+ }
305
+ } catch {
306
+ }
307
+ return map;
308
+ }
309
+ function isDescendantOf(pid, ancestor, parents) {
310
+ let cur = pid;
311
+ for (let i = 0; i < 25 && cur !== void 0 && cur > 1; i++) {
312
+ if (cur === ancestor) return true;
313
+ cur = parents.get(cur);
314
+ }
315
+ return false;
316
+ }
317
+
318
+ // src/tmux.ts
319
+ var execFileAsync2 = (0, import_util2.promisify)(import_child_process2.execFile);
256
320
  var IS_WIN = process.platform === "win32";
257
321
  function tmuxCmd(args) {
258
322
  return IS_WIN ? { file: "wsl.exe", args: ["tmux", ...args] } : { file: "tmux", args };
@@ -261,8 +325,8 @@ async function listTmuxSessions() {
261
325
  const fmt = "#{session_name} #{session_windows} #{session_attached} #{session_activity}";
262
326
  const { file, args } = tmuxCmd(["list-sessions", "-F", fmt]);
263
327
  try {
264
- const { stdout } = await execFileAsync(file, args, { timeout: 6e3 });
265
- return stdout.split("\n").map((line) => line.replace(/\r$/, "").trim()).filter(Boolean).map((line) => {
328
+ const { stdout } = await execFileAsync2(file, args, { timeout: 6e3 });
329
+ const sessions2 = stdout.split("\n").map((line) => line.replace(/\r$/, "").trim()).filter(Boolean).map((line) => {
266
330
  const [name, windows, attached, activity] = line.split(" ");
267
331
  return {
268
332
  name,
@@ -271,10 +335,42 @@ async function listTmuxSessions() {
271
335
  activity: parseInt(activity, 10) || void 0
272
336
  };
273
337
  });
338
+ await enrichWithPanesAndClaude(sessions2);
339
+ return sessions2;
274
340
  } catch {
275
341
  return [];
276
342
  }
277
343
  }
344
+ async function enrichWithPanesAndClaude(sessions2) {
345
+ if (IS_WIN || sessions2.length === 0) return;
346
+ try {
347
+ const paneFmt = "#{session_name} #{pane_pid} #{pane_current_path} #{window_active}#{pane_active}";
348
+ const { file, args } = tmuxCmd(["list-panes", "-a", "-F", paneFmt]);
349
+ const { stdout } = await execFileAsync2(file, args, { timeout: 6e3 });
350
+ const panes = stdout.split("\n").map((line) => line.replace(/\r$/, "").trim()).filter(Boolean).map((line) => {
351
+ const [session, pid, path8, activeFlags] = line.split(" ");
352
+ return { session, pid: parseInt(pid, 10) || 0, path: path8 || "", active: activeFlags === "11" };
353
+ });
354
+ const byName = new Map(sessions2.map((s) => [s.name, s]));
355
+ for (const pane of panes) {
356
+ const s = byName.get(pane.session);
357
+ if (s && (!s.path || pane.active)) s.path = pane.path || s.path;
358
+ }
359
+ const live = getLiveClaudeSessions();
360
+ if (live.length === 0) return;
361
+ const parents = await getPidParents();
362
+ for (const cs of live) {
363
+ const target = parents.size > 0 ? panes.find((p) => p.pid > 0 && isDescendantOf(cs.pid, p.pid, parents)) : panes.find((p) => cs.cwd && p.path === cs.cwd);
364
+ if (!target) continue;
365
+ const s = byName.get(target.session);
366
+ if (!s) continue;
367
+ s.claudeTitle = cs.name;
368
+ s.claudeStatus = cs.status;
369
+ if (cs.cwd) s.path = cs.cwd;
370
+ }
371
+ } catch {
372
+ }
373
+ }
278
374
  function shq(v) {
279
375
  return `'${v.replace(/'/g, `'\\''`)}'`;
280
376
  }
@@ -291,12 +387,12 @@ function buildTmuxLaunch(name, launch, shell) {
291
387
  }
292
388
 
293
389
  // src/shell.ts
294
- var import_child_process2 = require("child_process");
390
+ var import_child_process3 = require("child_process");
295
391
  function detectShell(preference) {
296
392
  if (preference !== "auto") return preference;
297
393
  if (process.platform === "win32") {
298
394
  try {
299
- (0, import_child_process2.execSync)("where pwsh", { stdio: "ignore" });
395
+ (0, import_child_process3.execSync)("where pwsh", { stdio: "ignore" });
300
396
  return "pwsh.exe";
301
397
  } catch {
302
398
  return "powershell.exe";
@@ -306,32 +402,32 @@ function detectShell(preference) {
306
402
  }
307
403
 
308
404
  // src/heartbeat.ts
309
- var import_os3 = __toESM(require("os"));
310
- var import_path4 = __toESM(require("path"));
311
- var import_child_process3 = require("child_process");
405
+ var import_os4 = __toESM(require("os"));
406
+ var import_path5 = __toESM(require("path"));
407
+ var import_child_process4 = require("child_process");
312
408
 
313
409
  // src/pty-session.ts
314
410
  var pty = __toESM(require("node-pty"));
315
- var import_fs3 = require("fs");
316
- var import_path3 = require("path");
317
- var import_os2 = require("os");
411
+ var import_fs4 = require("fs");
412
+ var import_path4 = require("path");
413
+ var import_os3 = require("os");
318
414
  var THRESHOLD = 3;
319
- var INIT_DIR = (0, import_path3.join)((0, import_os2.tmpdir)(), "crc-shell-init");
320
- var BASH_INIT = (0, import_path3.join)(INIT_DIR, "bashrc");
321
- var ZSH_DIR = (0, import_path3.join)(INIT_DIR, "zsh");
322
- var ZSH_RC = (0, import_path3.join)(ZSH_DIR, ".zshrc");
323
- var ZSH_ENV = (0, import_path3.join)(ZSH_DIR, ".zshenv");
415
+ var INIT_DIR = (0, import_path4.join)((0, import_os3.tmpdir)(), "crc-shell-init");
416
+ var BASH_INIT = (0, import_path4.join)(INIT_DIR, "bashrc");
417
+ var ZSH_DIR = (0, import_path4.join)(INIT_DIR, "zsh");
418
+ var ZSH_RC = (0, import_path4.join)(ZSH_DIR, ".zshrc");
419
+ var ZSH_ENV = (0, import_path4.join)(ZSH_DIR, ".zshenv");
324
420
  var INIT_VERSION = "2";
325
421
  function ensureInitFiles() {
326
- const versionFile = (0, import_path3.join)(INIT_DIR, ".version");
327
- if ((0, import_fs3.existsSync)(versionFile)) {
422
+ const versionFile = (0, import_path4.join)(INIT_DIR, ".version");
423
+ if ((0, import_fs4.existsSync)(versionFile)) {
328
424
  try {
329
- if ((0, import_fs3.readFileSync)(versionFile, "utf-8").trim() === INIT_VERSION) return;
425
+ if ((0, import_fs4.readFileSync)(versionFile, "utf-8").trim() === INIT_VERSION) return;
330
426
  } catch {
331
427
  }
332
428
  }
333
- (0, import_fs3.mkdirSync)(ZSH_DIR, { recursive: true });
334
- (0, import_fs3.writeFileSync)(BASH_INIT, [
429
+ (0, import_fs4.mkdirSync)(ZSH_DIR, { recursive: true });
430
+ (0, import_fs4.writeFileSync)(BASH_INIT, [
335
431
  "[ -f ~/.bash_profile ] && source ~/.bash_profile",
336
432
  "[ -f ~/.bashrc ] && source ~/.bashrc",
337
433
  "__crc_s=$SECONDS",
@@ -342,11 +438,11 @@ function ensureInitFiles() {
342
438
  `PROMPT_COMMAND='[ "$__crc_armed" = 1 ] && [ \${__crc_elapsed:-0} -ge ${THRESHOLD} ] && printf "\\a"; __crc_armed=1; eval "$__crc_orig_pc"'`,
343
439
  ""
344
440
  ].join("\n"), "utf-8");
345
- (0, import_fs3.writeFileSync)(ZSH_ENV, [
441
+ (0, import_fs4.writeFileSync)(ZSH_ENV, [
346
442
  '[ -f "${ZDOTDIR_ORIG:-$HOME}/.zshenv" ] && source "${ZDOTDIR_ORIG:-$HOME}/.zshenv"',
347
443
  ""
348
444
  ].join("\n"), "utf-8");
349
- (0, import_fs3.writeFileSync)(ZSH_RC, [
445
+ (0, import_fs4.writeFileSync)(ZSH_RC, [
350
446
  '[ -f "${ZDOTDIR_ORIG:-$HOME}/.zshrc" ] && source "${ZDOTDIR_ORIG:-$HOME}/.zshrc"',
351
447
  "__crc_s=$SECONDS",
352
448
  "__crc_armed=0",
@@ -359,19 +455,19 @@ function ensureInitFiles() {
359
455
  "fi",
360
456
  ""
361
457
  ].join("\n"), "utf-8");
362
- (0, import_fs3.writeFileSync)(versionFile, INIT_VERSION, "utf-8");
458
+ (0, import_fs4.writeFileSync)(versionFile, INIT_VERSION, "utf-8");
363
459
  }
364
460
  function resolveCwd(cwd) {
365
- const candidates = process.platform === "win32" ? [cwd, (0, import_os2.homedir)(), process.env.USERPROFILE, process.env.HOME] : [cwd, (0, import_os2.homedir)(), process.env.HOME, process.env.USERPROFILE];
461
+ 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];
366
462
  for (const c of candidates) {
367
463
  if (c) {
368
464
  try {
369
- if ((0, import_fs3.existsSync)(c)) return c;
465
+ if ((0, import_fs4.existsSync)(c)) return c;
370
466
  } catch {
371
467
  }
372
468
  }
373
469
  }
374
- return (0, import_os2.homedir)();
470
+ return (0, import_os3.homedir)();
375
471
  }
376
472
  var PtySession = class {
377
473
  id;
@@ -415,7 +511,7 @@ var PtySession = class {
415
511
  name: "xterm-256color",
416
512
  cols,
417
513
  rows,
418
- cwd: (0, import_os2.homedir)(),
514
+ cwd: (0, import_os3.homedir)(),
419
515
  env
420
516
  });
421
517
  }
@@ -553,7 +649,7 @@ function reapDetachedSessions(maxIdleMs) {
553
649
  // src/heartbeat.ts
554
650
  var prevCpu = null;
555
651
  function getCpuUsage() {
556
- const cpus = import_os3.default.cpus();
652
+ const cpus = import_os4.default.cpus();
557
653
  let idle = 0;
558
654
  let total = 0;
559
655
  for (const cpu of cpus) {
@@ -573,7 +669,7 @@ function getCpuUsage() {
573
669
  function getRootPaths() {
574
670
  if (process.platform === "win32") {
575
671
  try {
576
- const output = (0, import_child_process3.execSync)("wmic logicaldisk get name", { encoding: "utf-8" });
672
+ const output = (0, import_child_process4.execSync)("wmic logicaldisk get name", { encoding: "utf-8" });
577
673
  return output.split("\n").map((l) => l.trim()).filter((l) => /^[A-Z]:$/.test(l)).map((l) => l + "\\");
578
674
  } catch {
579
675
  return ["C:\\"];
@@ -582,51 +678,51 @@ function getRootPaths() {
582
678
  return ["/"];
583
679
  }
584
680
  function buildHeartbeat(homeDir) {
585
- const totalMem = import_os3.default.totalmem();
586
- const freeMem = import_os3.default.freemem();
681
+ const totalMem = import_os4.default.totalmem();
682
+ const freeMem = import_os4.default.freemem();
587
683
  return {
588
- hostname: import_os3.default.hostname(),
684
+ hostname: import_os4.default.hostname(),
589
685
  platform: process.platform,
590
- arch: import_os3.default.arch(),
686
+ arch: import_os4.default.arch(),
591
687
  cpuUsage: getCpuUsage(),
592
688
  memoryUsage: Math.round((totalMem - freeMem) / totalMem * 100),
593
- uptime: Math.round(import_os3.default.uptime()),
689
+ uptime: Math.round(import_os4.default.uptime()),
594
690
  activeSessions: getActiveSessionCount(),
595
- pathSeparator: import_path4.default.sep,
596
- homeDirectory: homeDir || import_os3.default.homedir(),
691
+ pathSeparator: import_path5.default.sep,
692
+ homeDirectory: homeDir || import_os4.default.homedir(),
597
693
  rootPaths: getRootPaths(),
598
694
  capabilities: { terminal: true, fileTransfer: false }
599
695
  };
600
696
  }
601
697
 
602
698
  // src/file-explorer.ts
603
- var import_fs4 = __toESM(require("fs"));
604
- var import_path5 = __toESM(require("path"));
605
- var import_os4 = __toESM(require("os"));
606
- var SECRET_DIR = import_path5.default.join(import_os4.default.homedir(), ".crc-agent");
699
+ var import_fs5 = __toESM(require("fs"));
700
+ var import_path6 = __toESM(require("path"));
701
+ var import_os5 = __toESM(require("os"));
702
+ var SECRET_DIR = import_path6.default.join(import_os5.default.homedir(), ".crc-agent");
607
703
  function isInSecretDir(resolved) {
608
- const rel = import_path5.default.relative(SECRET_DIR, resolved);
609
- return rel === "" || !rel.startsWith(".." + import_path5.default.sep) && rel !== ".." && !import_path5.default.isAbsolute(rel);
704
+ const rel = import_path6.default.relative(SECRET_DIR, resolved);
705
+ return rel === "" || !rel.startsWith(".." + import_path6.default.sep) && rel !== ".." && !import_path6.default.isAbsolute(rel);
610
706
  }
611
707
  function listDirectory(dirPath) {
612
708
  try {
613
- const resolved = import_path5.default.resolve(dirPath);
709
+ const resolved = import_path6.default.resolve(dirPath);
614
710
  if (isInSecretDir(resolved)) {
615
711
  return { entries: [], error: "Access denied" };
616
712
  }
617
- if (!import_fs4.default.existsSync(resolved)) {
713
+ if (!import_fs5.default.existsSync(resolved)) {
618
714
  return { entries: [], error: "Path does not exist" };
619
715
  }
620
- const stat = import_fs4.default.statSync(resolved);
716
+ const stat = import_fs5.default.statSync(resolved);
621
717
  if (!stat.isDirectory()) {
622
718
  return { entries: [], error: "Not a directory" };
623
719
  }
624
- const dirents = import_fs4.default.readdirSync(resolved, { withFileTypes: true });
720
+ const dirents = import_fs5.default.readdirSync(resolved, { withFileTypes: true });
625
721
  const entries = [];
626
722
  for (const dirent of dirents) {
627
723
  try {
628
- const fullPath = import_path5.default.join(resolved, dirent.name);
629
- const s = import_fs4.default.statSync(fullPath);
724
+ const fullPath = import_path6.default.join(resolved, dirent.name);
725
+ const s = import_fs5.default.statSync(fullPath);
630
726
  entries.push({
631
727
  name: dirent.name,
632
728
  isDirectory: dirent.isDirectory(),
@@ -648,22 +744,22 @@ function listDirectory(dirPath) {
648
744
  }
649
745
  async function downloadFile(filePath, serverUrl, secret, agentId) {
650
746
  try {
651
- const resolved = import_path5.default.resolve(filePath);
747
+ const resolved = import_path6.default.resolve(filePath);
652
748
  if (isInSecretDir(resolved)) {
653
749
  return { error: "Access denied" };
654
750
  }
655
- if (!import_fs4.default.existsSync(resolved)) {
751
+ if (!import_fs5.default.existsSync(resolved)) {
656
752
  return { error: "File does not exist" };
657
753
  }
658
- const stat = import_fs4.default.statSync(resolved);
754
+ const stat = import_fs5.default.statSync(resolved);
659
755
  if (stat.isDirectory()) {
660
756
  return { error: "Cannot download a directory" };
661
757
  }
662
758
  if (stat.size > FILE_MAX_SIZE) {
663
759
  return { error: `File too large (max ${FILE_MAX_SIZE} bytes)` };
664
760
  }
665
- const fileName = import_path5.default.basename(resolved);
666
- const fileStream = import_fs4.default.createReadStream(resolved);
761
+ const fileName = import_path6.default.basename(resolved);
762
+ const fileStream = import_fs5.default.createReadStream(resolved);
667
763
  const baseUrl = serverUrl.replace("wss://", "https://").replace("ws://", "http://");
668
764
  const url = `${baseUrl}/api/files/receive`;
669
765
  const res = await fetch(url, {
@@ -694,14 +790,14 @@ async function downloadFile(filePath, serverUrl, secret, agentId) {
694
790
  }
695
791
 
696
792
  // src/vpn-manager.ts
697
- var import_child_process4 = require("child_process");
698
- var import_util2 = require("util");
699
- var import_fs5 = __toESM(require("fs"));
700
- var import_path6 = __toESM(require("path"));
701
- var import_os5 = __toESM(require("os"));
702
- var execAsync = (0, import_util2.promisify)(import_child_process4.exec);
793
+ var import_child_process5 = require("child_process");
794
+ var import_util3 = require("util");
795
+ var import_fs6 = __toESM(require("fs"));
796
+ var import_path7 = __toESM(require("path"));
797
+ var import_os6 = __toESM(require("os"));
798
+ var execAsync = (0, import_util3.promisify)(import_child_process5.exec);
703
799
  var isWindows = process.platform === "win32";
704
- var VPN_DIR = import_path6.default.join(import_os5.default.homedir(), ".crc-agent", "vpn");
800
+ var VPN_DIR = import_path7.default.join(import_os6.default.homedir(), ".crc-agent", "vpn");
705
801
  function shq2(value) {
706
802
  return value.replace(/'/g, "'\\''");
707
803
  }
@@ -720,8 +816,8 @@ async function runCmd(cmd, shell) {
720
816
  }
721
817
  function getConfigPath(profile) {
722
818
  const file = profile.configFile || `${profile.id}.conf`;
723
- if (import_path6.default.isAbsolute(file)) return file;
724
- return import_path6.default.join(VPN_DIR, file);
819
+ if (import_path7.default.isAbsolute(file)) return file;
820
+ return import_path7.default.join(VPN_DIR, file);
725
821
  }
726
822
  async function getScutilStatus(serviceName) {
727
823
  const { stdout } = await runCmd(`scutil --nc status '${shq2(serviceName)}'`);
@@ -837,7 +933,7 @@ async function connectWireGuard(profile) {
837
933
  const tunnelName = profile.tunnelName || profile.id;
838
934
  if (isWindows) {
839
935
  const confPath2 = getConfigPath(profile);
840
- if (!import_fs5.default.existsSync(confPath2)) {
936
+ if (!import_fs6.default.existsSync(confPath2)) {
841
937
  return `Config file not found: ${confPath2}`;
842
938
  }
843
939
  const script = `
@@ -863,7 +959,7 @@ async function connectWireGuard(profile) {
863
959
  async function connectOpenVpn(profile) {
864
960
  if (isWindows) {
865
961
  const confPath2 = getConfigPath(profile);
866
- if (!import_fs5.default.existsSync(confPath2)) {
962
+ if (!import_fs6.default.existsSync(confPath2)) {
867
963
  return `Config file not found: ${confPath2}`;
868
964
  }
869
965
  const connector = "C:\\Program Files\\OpenVPN Connect\\ovpnconnector.exe";
@@ -890,7 +986,7 @@ async function connectOpenVpn(profile) {
890
986
  return scutilStart(profile.serviceName);
891
987
  }
892
988
  const confPath = getConfigPath(profile);
893
- if (!import_fs5.default.existsSync(confPath)) {
989
+ if (!import_fs6.default.existsSync(confPath)) {
894
990
  return `Config file not found: ${confPath}`;
895
991
  }
896
992
  const { stderr } = await runCmd(`sudo openvpn --config '${shq2(confPath)}' --daemon`);
@@ -899,7 +995,7 @@ async function connectOpenVpn(profile) {
899
995
  async function connectAzure(profile) {
900
996
  if (isWindows) {
901
997
  const confPath = getConfigPath(profile);
902
- if (!import_fs5.default.existsSync(confPath)) {
998
+ if (!import_fs6.default.existsSync(confPath)) {
903
999
  return `Config file not found: ${confPath}`;
904
1000
  }
905
1001
  await runCmd(`& 'AzureVpn.exe' -i '${psq(confPath)}' 2>&1`);
@@ -1021,9 +1117,9 @@ async function disconnectVpn(configs, profileId) {
1021
1117
  }
1022
1118
 
1023
1119
  // src/claude-sessions.ts
1024
- var import_fs6 = __toESM(require("fs"));
1025
- var import_path7 = __toESM(require("path"));
1026
- var import_os6 = __toESM(require("os"));
1120
+ var import_fs7 = __toESM(require("fs"));
1121
+ var import_path8 = __toESM(require("path"));
1122
+ var import_os7 = __toESM(require("os"));
1027
1123
  var import_readline = __toESM(require("readline"));
1028
1124
 
1029
1125
  // src/claude-path.ts
@@ -1050,10 +1146,10 @@ function findProjectDirs(allDirs, filterProjectPath) {
1050
1146
  }
1051
1147
 
1052
1148
  // src/claude-sessions.ts
1053
- var CLAUDE_PROJECTS_DIR = import_path7.default.join(import_os6.default.homedir(), ".claude", "projects");
1149
+ var CLAUDE_PROJECTS_DIR = import_path8.default.join(import_os7.default.homedir(), ".claude", "projects");
1054
1150
  async function parseSessionFile(filePath) {
1055
1151
  try {
1056
- const stream = import_fs6.default.createReadStream(filePath, { encoding: "utf-8" });
1152
+ const stream = import_fs7.default.createReadStream(filePath, { encoding: "utf-8" });
1057
1153
  const rl = import_readline.default.createInterface({ input: stream, crlfDelay: Infinity });
1058
1154
  let firstMessage = "";
1059
1155
  let lastTimestamp = "";
@@ -1101,17 +1197,17 @@ async function parseSessionFile(filePath) {
1101
1197
  }
1102
1198
  async function listClaudeSessions(filterProjectPath) {
1103
1199
  const sessions2 = [];
1104
- if (!import_fs6.default.existsSync(CLAUDE_PROJECTS_DIR)) return sessions2;
1200
+ if (!import_fs7.default.existsSync(CLAUDE_PROJECTS_DIR)) return sessions2;
1105
1201
  const isDirSafe = (d) => {
1106
1202
  try {
1107
- return import_fs6.default.statSync(import_path7.default.join(CLAUDE_PROJECTS_DIR, d)).isDirectory();
1203
+ return import_fs7.default.statSync(import_path8.default.join(CLAUDE_PROJECTS_DIR, d)).isDirectory();
1108
1204
  } catch {
1109
1205
  return false;
1110
1206
  }
1111
1207
  };
1112
1208
  let allEntries;
1113
1209
  try {
1114
- allEntries = import_fs6.default.readdirSync(CLAUDE_PROJECTS_DIR);
1210
+ allEntries = import_fs7.default.readdirSync(CLAUDE_PROJECTS_DIR);
1115
1211
  } catch {
1116
1212
  return sessions2;
1117
1213
  }
@@ -1124,16 +1220,16 @@ async function listClaudeSessions(filterProjectPath) {
1124
1220
  projectDirs = allEntries.filter((d) => isDirSafe(d) && !d.startsWith("-private-"));
1125
1221
  }
1126
1222
  for (const dirName of projectDirs) {
1127
- const dirPath = import_path7.default.join(CLAUDE_PROJECTS_DIR, dirName);
1223
+ const dirPath = import_path8.default.join(CLAUDE_PROJECTS_DIR, dirName);
1128
1224
  let files;
1129
1225
  try {
1130
- files = import_fs6.default.readdirSync(dirPath).filter((f) => f.endsWith(".jsonl"));
1226
+ files = import_fs7.default.readdirSync(dirPath).filter((f) => f.endsWith(".jsonl"));
1131
1227
  } catch {
1132
1228
  continue;
1133
1229
  }
1134
1230
  for (const file of files) {
1135
1231
  const sessionId = file.replace(".jsonl", "");
1136
- const parsed = await parseSessionFile(import_path7.default.join(dirPath, file));
1232
+ const parsed = await parseSessionFile(import_path8.default.join(dirPath, file));
1137
1233
  if (!parsed) continue;
1138
1234
  const projectPath = parsed.cwd || dirName.replace(/^-/, "/").replace(/-/g, "/");
1139
1235
  sessions2.push({
@@ -1153,21 +1249,21 @@ async function listClaudeSessions(filterProjectPath) {
1153
1249
  }
1154
1250
 
1155
1251
  // src/claude-conversation.ts
1156
- var import_fs7 = __toESM(require("fs"));
1157
- var import_path8 = __toESM(require("path"));
1158
- var import_os7 = __toESM(require("os"));
1252
+ var import_fs8 = __toESM(require("fs"));
1253
+ var import_path9 = __toESM(require("path"));
1254
+ var import_os8 = __toESM(require("os"));
1159
1255
  var import_readline2 = __toESM(require("readline"));
1160
- var CLAUDE_PROJECTS_DIR2 = import_path8.default.join(import_os7.default.homedir(), ".claude", "projects");
1256
+ var CLAUDE_PROJECTS_DIR2 = import_path9.default.join(import_os8.default.homedir(), ".claude", "projects");
1161
1257
  function findProjectDir(projectPath) {
1162
1258
  const encoded = encodeProjectPath(projectPath);
1163
- const dirPath = import_path8.default.join(CLAUDE_PROJECTS_DIR2, encoded);
1164
- if (import_fs7.default.existsSync(dirPath)) return dirPath;
1165
- if (!import_fs7.default.existsSync(CLAUDE_PROJECTS_DIR2)) return null;
1259
+ const dirPath = import_path9.default.join(CLAUDE_PROJECTS_DIR2, encoded);
1260
+ if (import_fs8.default.existsSync(dirPath)) return dirPath;
1261
+ if (!import_fs8.default.existsSync(CLAUDE_PROJECTS_DIR2)) return null;
1166
1262
  let allDirs;
1167
1263
  try {
1168
- allDirs = import_fs7.default.readdirSync(CLAUDE_PROJECTS_DIR2).filter((d) => {
1264
+ allDirs = import_fs8.default.readdirSync(CLAUDE_PROJECTS_DIR2).filter((d) => {
1169
1265
  try {
1170
- return import_fs7.default.statSync(import_path8.default.join(CLAUDE_PROJECTS_DIR2, d)).isDirectory();
1266
+ return import_fs8.default.statSync(import_path9.default.join(CLAUDE_PROJECTS_DIR2, d)).isDirectory();
1171
1267
  } catch {
1172
1268
  return false;
1173
1269
  }
@@ -1177,23 +1273,23 @@ function findProjectDir(projectPath) {
1177
1273
  }
1178
1274
  const matches = findProjectDirs(allDirs, projectPath);
1179
1275
  if (matches.length > 0) {
1180
- return import_path8.default.join(CLAUDE_PROJECTS_DIR2, matches[0]);
1276
+ return import_path9.default.join(CLAUDE_PROJECTS_DIR2, matches[0]);
1181
1277
  }
1182
1278
  return null;
1183
1279
  }
1184
1280
  function findSessionFileById(sessionId) {
1185
1281
  if (!/^[A-Za-z0-9._-]+$/.test(sessionId)) return null;
1186
- if (!import_fs7.default.existsSync(CLAUDE_PROJECTS_DIR2)) return null;
1282
+ if (!import_fs8.default.existsSync(CLAUDE_PROJECTS_DIR2)) return null;
1187
1283
  let dirs;
1188
1284
  try {
1189
- dirs = import_fs7.default.readdirSync(CLAUDE_PROJECTS_DIR2);
1285
+ dirs = import_fs8.default.readdirSync(CLAUDE_PROJECTS_DIR2);
1190
1286
  } catch {
1191
1287
  return null;
1192
1288
  }
1193
1289
  for (const dir of dirs) {
1194
- const candidate = import_path8.default.join(CLAUDE_PROJECTS_DIR2, dir, `${sessionId}.jsonl`);
1290
+ const candidate = import_path9.default.join(CLAUDE_PROJECTS_DIR2, dir, `${sessionId}.jsonl`);
1195
1291
  try {
1196
- if (import_fs7.default.statSync(candidate).isFile()) return candidate;
1292
+ if (import_fs8.default.statSync(candidate).isFile()) return candidate;
1197
1293
  } catch {
1198
1294
  }
1199
1295
  }
@@ -1204,20 +1300,20 @@ function findLatestSessionFile(projectPath) {
1204
1300
  if (!dirPath) return null;
1205
1301
  let entries;
1206
1302
  try {
1207
- entries = import_fs7.default.readdirSync(dirPath);
1303
+ entries = import_fs8.default.readdirSync(dirPath);
1208
1304
  } catch {
1209
1305
  return null;
1210
1306
  }
1211
1307
  const files = entries.filter((f) => f.endsWith(".jsonl") && !f.includes("/")).map((f) => {
1212
1308
  try {
1213
- return { name: f, mtime: import_fs7.default.statSync(import_path8.default.join(dirPath, f)).mtimeMs };
1309
+ return { name: f, mtime: import_fs8.default.statSync(import_path9.default.join(dirPath, f)).mtimeMs };
1214
1310
  } catch {
1215
1311
  return null;
1216
1312
  }
1217
1313
  }).filter((f) => f !== null).sort((a, b) => b.mtime - a.mtime);
1218
1314
  if (files.length === 0) return null;
1219
1315
  return {
1220
- filePath: import_path8.default.join(dirPath, files[0].name),
1316
+ filePath: import_path9.default.join(dirPath, files[0].name),
1221
1317
  sessionId: files[0].name.replace(".jsonl", "")
1222
1318
  };
1223
1319
  }
@@ -1227,8 +1323,8 @@ async function readConversation(projectPath, afterLine = 0, specificSessionId) {
1227
1323
  if (specificSessionId) {
1228
1324
  sessionId = specificSessionId;
1229
1325
  const dirPath = findProjectDir(projectPath);
1230
- const direct = dirPath ? import_path8.default.join(dirPath, `${specificSessionId}.jsonl`) : null;
1231
- if (direct && import_fs7.default.existsSync(direct)) {
1326
+ const direct = dirPath ? import_path9.default.join(dirPath, `${specificSessionId}.jsonl`) : null;
1327
+ if (direct && import_fs8.default.existsSync(direct)) {
1232
1328
  filePath = direct;
1233
1329
  } else {
1234
1330
  const byId = findSessionFileById(specificSessionId);
@@ -1242,7 +1338,7 @@ async function readConversation(projectPath, afterLine = 0, specificSessionId) {
1242
1338
  sessionId = found.sessionId;
1243
1339
  }
1244
1340
  try {
1245
- const stream = import_fs7.default.createReadStream(filePath, { encoding: "utf-8" });
1341
+ const stream = import_fs8.default.createReadStream(filePath, { encoding: "utf-8" });
1246
1342
  const rl = import_readline2.default.createInterface({ input: stream, crlfDelay: Infinity });
1247
1343
  const messages = [];
1248
1344
  let lineNum = 0;
@@ -1484,8 +1580,8 @@ socket.on(AGENT_EXEC, async (payload) => {
1484
1580
  const { requestId, command, cwd } = payload;
1485
1581
  if (!requestId) return;
1486
1582
  const { exec: exec2 } = await import("child_process");
1487
- const { promisify: promisify3 } = await import("util");
1488
- const execAsync2 = promisify3(exec2);
1583
+ const { promisify: promisify4 } = await import("util");
1584
+ const execAsync2 = promisify4(exec2);
1489
1585
  try {
1490
1586
  const { stdout, stderr } = await execAsync2(command, { cwd, timeout: 3e4 });
1491
1587
  socket.emit(AGENT_EXEC_RESULT, { requestId, stdout: stdout || "", stderr: stderr || "" });