cli-remote-agent 1.0.2 → 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/cli.js CHANGED
@@ -414,6 +414,74 @@ var init_local_control = __esm({
414
414
  }
415
415
  });
416
416
 
417
+ // src/claude-live.ts
418
+ function isAlive(pid) {
419
+ try {
420
+ process.kill(pid, 0);
421
+ return true;
422
+ } catch {
423
+ return false;
424
+ }
425
+ }
426
+ function getLiveClaudeSessions() {
427
+ let files;
428
+ try {
429
+ files = import_fs4.default.readdirSync(LIVE_SESSIONS_DIR).filter((f) => f.endsWith(".json"));
430
+ } catch {
431
+ return [];
432
+ }
433
+ const out = [];
434
+ for (const f of files) {
435
+ try {
436
+ const obj = JSON.parse(import_fs4.default.readFileSync(import_path3.default.join(LIVE_SESSIONS_DIR, f), "utf-8"));
437
+ if (typeof obj?.pid !== "number" || !isAlive(obj.pid)) continue;
438
+ out.push({
439
+ pid: obj.pid,
440
+ cwd: typeof obj.cwd === "string" ? obj.cwd : "",
441
+ name: typeof obj.name === "string" ? obj.name : void 0,
442
+ status: typeof obj.status === "string" ? obj.status : void 0,
443
+ updatedAt: typeof obj.updatedAt === "number" ? obj.updatedAt : void 0
444
+ });
445
+ } catch {
446
+ }
447
+ }
448
+ out.sort((a, b) => (a.updatedAt || 0) - (b.updatedAt || 0));
449
+ return out;
450
+ }
451
+ async function getPidParents() {
452
+ const map = /* @__PURE__ */ new Map();
453
+ try {
454
+ const { stdout } = await execFileAsync("ps", ["-axo", "pid=,ppid="], { timeout: 5e3 });
455
+ for (const line of stdout.split("\n")) {
456
+ const m = line.trim().match(/^(\d+)\s+(\d+)$/);
457
+ if (m) map.set(parseInt(m[1], 10), parseInt(m[2], 10));
458
+ }
459
+ } catch {
460
+ }
461
+ return map;
462
+ }
463
+ function isDescendantOf(pid, ancestor, parents) {
464
+ let cur = pid;
465
+ for (let i = 0; i < 25 && cur !== void 0 && cur > 1; i++) {
466
+ if (cur === ancestor) return true;
467
+ cur = parents.get(cur);
468
+ }
469
+ return false;
470
+ }
471
+ var import_fs4, import_path3, import_os2, import_child_process, import_util, execFileAsync, LIVE_SESSIONS_DIR;
472
+ var init_claude_live = __esm({
473
+ "src/claude-live.ts"() {
474
+ "use strict";
475
+ import_fs4 = __toESM(require("fs"));
476
+ import_path3 = __toESM(require("path"));
477
+ import_os2 = __toESM(require("os"));
478
+ import_child_process = require("child_process");
479
+ import_util = require("util");
480
+ execFileAsync = (0, import_util.promisify)(import_child_process.execFile);
481
+ LIVE_SESSIONS_DIR = import_path3.default.join(import_os2.default.homedir(), ".claude", "sessions");
482
+ }
483
+ });
484
+
417
485
  // src/tmux.ts
418
486
  function tmuxCmd(args) {
419
487
  return IS_WIN ? { file: "wsl.exe", args: ["tmux", ...args] } : { file: "tmux", args };
@@ -422,8 +490,8 @@ async function listTmuxSessions() {
422
490
  const fmt = "#{session_name} #{session_windows} #{session_attached} #{session_activity}";
423
491
  const { file, args } = tmuxCmd(["list-sessions", "-F", fmt]);
424
492
  try {
425
- const { stdout } = await execFileAsync(file, args, { timeout: 6e3 });
426
- return stdout.split("\n").map((line) => line.replace(/\r$/, "").trim()).filter(Boolean).map((line) => {
493
+ const { stdout } = await execFileAsync2(file, args, { timeout: 6e3 });
494
+ const sessions2 = stdout.split("\n").map((line) => line.replace(/\r$/, "").trim()).filter(Boolean).map((line) => {
427
495
  const [name, windows, attached, activity] = line.split(" ");
428
496
  return {
429
497
  name,
@@ -432,10 +500,42 @@ async function listTmuxSessions() {
432
500
  activity: parseInt(activity, 10) || void 0
433
501
  };
434
502
  });
503
+ await enrichWithPanesAndClaude(sessions2);
504
+ return sessions2;
435
505
  } catch {
436
506
  return [];
437
507
  }
438
508
  }
509
+ async function enrichWithPanesAndClaude(sessions2) {
510
+ if (IS_WIN || sessions2.length === 0) return;
511
+ try {
512
+ const paneFmt = "#{session_name} #{pane_pid} #{pane_current_path} #{window_active}#{pane_active}";
513
+ const { file, args } = tmuxCmd(["list-panes", "-a", "-F", paneFmt]);
514
+ const { stdout } = await execFileAsync2(file, args, { timeout: 6e3 });
515
+ const panes = stdout.split("\n").map((line) => line.replace(/\r$/, "").trim()).filter(Boolean).map((line) => {
516
+ const [session, pid, path8, activeFlags] = line.split(" ");
517
+ return { session, pid: parseInt(pid, 10) || 0, path: path8 || "", active: activeFlags === "11" };
518
+ });
519
+ const byName = new Map(sessions2.map((s) => [s.name, s]));
520
+ for (const pane of panes) {
521
+ const s = byName.get(pane.session);
522
+ if (s && (!s.path || pane.active)) s.path = pane.path || s.path;
523
+ }
524
+ const live = getLiveClaudeSessions();
525
+ if (live.length === 0) return;
526
+ const parents = await getPidParents();
527
+ for (const cs of live) {
528
+ 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);
529
+ if (!target) continue;
530
+ const s = byName.get(target.session);
531
+ if (!s) continue;
532
+ s.claudeTitle = cs.name;
533
+ s.claudeStatus = cs.status;
534
+ if (cs.cwd) s.path = cs.cwd;
535
+ }
536
+ } catch {
537
+ }
538
+ }
439
539
  function shq(v) {
440
540
  return `'${v.replace(/'/g, `'\\''`)}'`;
441
541
  }
@@ -450,13 +550,14 @@ function buildTmuxLaunch(name, launch, shell) {
450
550
  if (trimmed) cmd2 += ` ${shq(trimmed)}`;
451
551
  return { file: shell, args: ["-l", "-c", cmd2] };
452
552
  }
453
- var import_child_process, import_util, execFileAsync, IS_WIN;
553
+ var import_child_process2, import_util2, execFileAsync2, IS_WIN;
454
554
  var init_tmux = __esm({
455
555
  "src/tmux.ts"() {
456
556
  "use strict";
457
- import_child_process = require("child_process");
458
- import_util = require("util");
459
- execFileAsync = (0, import_util.promisify)(import_child_process.execFile);
557
+ import_child_process2 = require("child_process");
558
+ import_util2 = require("util");
559
+ init_claude_live();
560
+ execFileAsync2 = (0, import_util2.promisify)(import_child_process2.execFile);
460
561
  IS_WIN = process.platform === "win32";
461
562
  }
462
563
  });
@@ -466,7 +567,7 @@ function detectShell(preference) {
466
567
  if (preference !== "auto") return preference;
467
568
  if (process.platform === "win32") {
468
569
  try {
469
- (0, import_child_process2.execSync)("where pwsh", { stdio: "ignore" });
570
+ (0, import_child_process3.execSync)("where pwsh", { stdio: "ignore" });
470
571
  return "pwsh.exe";
471
572
  } catch {
472
573
  return "powershell.exe";
@@ -474,25 +575,25 @@ function detectShell(preference) {
474
575
  }
475
576
  return process.env.SHELL || "/bin/bash";
476
577
  }
477
- var import_child_process2;
578
+ var import_child_process3;
478
579
  var init_shell = __esm({
479
580
  "src/shell.ts"() {
480
581
  "use strict";
481
- import_child_process2 = require("child_process");
582
+ import_child_process3 = require("child_process");
482
583
  }
483
584
  });
484
585
 
485
586
  // src/pty-session.ts
486
587
  function ensureInitFiles() {
487
- const versionFile = (0, import_path3.join)(INIT_DIR, ".version");
488
- if ((0, import_fs4.existsSync)(versionFile)) {
588
+ const versionFile = (0, import_path4.join)(INIT_DIR, ".version");
589
+ if ((0, import_fs5.existsSync)(versionFile)) {
489
590
  try {
490
- if ((0, import_fs4.readFileSync)(versionFile, "utf-8").trim() === INIT_VERSION) return;
591
+ if ((0, import_fs5.readFileSync)(versionFile, "utf-8").trim() === INIT_VERSION) return;
491
592
  } catch {
492
593
  }
493
594
  }
494
- (0, import_fs4.mkdirSync)(ZSH_DIR, { recursive: true });
495
- (0, import_fs4.writeFileSync)(BASH_INIT, [
595
+ (0, import_fs5.mkdirSync)(ZSH_DIR, { recursive: true });
596
+ (0, import_fs5.writeFileSync)(BASH_INIT, [
496
597
  "[ -f ~/.bash_profile ] && source ~/.bash_profile",
497
598
  "[ -f ~/.bashrc ] && source ~/.bashrc",
498
599
  "__crc_s=$SECONDS",
@@ -503,11 +604,11 @@ function ensureInitFiles() {
503
604
  `PROMPT_COMMAND='[ "$__crc_armed" = 1 ] && [ \${__crc_elapsed:-0} -ge ${THRESHOLD} ] && printf "\\a"; __crc_armed=1; eval "$__crc_orig_pc"'`,
504
605
  ""
505
606
  ].join("\n"), "utf-8");
506
- (0, import_fs4.writeFileSync)(ZSH_ENV, [
607
+ (0, import_fs5.writeFileSync)(ZSH_ENV, [
507
608
  '[ -f "${ZDOTDIR_ORIG:-$HOME}/.zshenv" ] && source "${ZDOTDIR_ORIG:-$HOME}/.zshenv"',
508
609
  ""
509
610
  ].join("\n"), "utf-8");
510
- (0, import_fs4.writeFileSync)(ZSH_RC, [
611
+ (0, import_fs5.writeFileSync)(ZSH_RC, [
511
612
  '[ -f "${ZDOTDIR_ORIG:-$HOME}/.zshrc" ] && source "${ZDOTDIR_ORIG:-$HOME}/.zshrc"',
512
613
  "__crc_s=$SECONDS",
513
614
  "__crc_armed=0",
@@ -520,36 +621,36 @@ function ensureInitFiles() {
520
621
  "fi",
521
622
  ""
522
623
  ].join("\n"), "utf-8");
523
- (0, import_fs4.writeFileSync)(versionFile, INIT_VERSION, "utf-8");
624
+ (0, import_fs5.writeFileSync)(versionFile, INIT_VERSION, "utf-8");
524
625
  }
525
626
  function resolveCwd(cwd) {
526
- 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];
627
+ 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];
527
628
  for (const c of candidates) {
528
629
  if (c) {
529
630
  try {
530
- if ((0, import_fs4.existsSync)(c)) return c;
631
+ if ((0, import_fs5.existsSync)(c)) return c;
531
632
  } catch {
532
633
  }
533
634
  }
534
635
  }
535
- return (0, import_os2.homedir)();
636
+ return (0, import_os3.homedir)();
536
637
  }
537
- var pty, import_fs4, import_path3, import_os2, THRESHOLD, INIT_DIR, BASH_INIT, ZSH_DIR, ZSH_RC, ZSH_ENV, INIT_VERSION, PtySession;
638
+ var pty, import_fs5, import_path4, import_os3, THRESHOLD, INIT_DIR, BASH_INIT, ZSH_DIR, ZSH_RC, ZSH_ENV, INIT_VERSION, PtySession;
538
639
  var init_pty_session = __esm({
539
640
  "src/pty-session.ts"() {
540
641
  "use strict";
541
642
  pty = __toESM(require("node-pty"));
542
- import_fs4 = require("fs");
543
- import_path3 = require("path");
544
- import_os2 = require("os");
643
+ import_fs5 = require("fs");
644
+ import_path4 = require("path");
645
+ import_os3 = require("os");
545
646
  init_src();
546
647
  init_shell();
547
648
  THRESHOLD = 3;
548
- INIT_DIR = (0, import_path3.join)((0, import_os2.tmpdir)(), "crc-shell-init");
549
- BASH_INIT = (0, import_path3.join)(INIT_DIR, "bashrc");
550
- ZSH_DIR = (0, import_path3.join)(INIT_DIR, "zsh");
551
- ZSH_RC = (0, import_path3.join)(ZSH_DIR, ".zshrc");
552
- ZSH_ENV = (0, import_path3.join)(ZSH_DIR, ".zshenv");
649
+ INIT_DIR = (0, import_path4.join)((0, import_os3.tmpdir)(), "crc-shell-init");
650
+ BASH_INIT = (0, import_path4.join)(INIT_DIR, "bashrc");
651
+ ZSH_DIR = (0, import_path4.join)(INIT_DIR, "zsh");
652
+ ZSH_RC = (0, import_path4.join)(ZSH_DIR, ".zshrc");
653
+ ZSH_ENV = (0, import_path4.join)(ZSH_DIR, ".zshenv");
553
654
  INIT_VERSION = "2";
554
655
  PtySession = class {
555
656
  id;
@@ -593,7 +694,7 @@ var init_pty_session = __esm({
593
694
  name: "xterm-256color",
594
695
  cols,
595
696
  rows,
596
- cwd: (0, import_os2.homedir)(),
697
+ cwd: (0, import_os3.homedir)(),
597
698
  env
598
699
  });
599
700
  }
@@ -740,7 +841,7 @@ var init_terminal_manager = __esm({
740
841
 
741
842
  // src/heartbeat.ts
742
843
  function getCpuUsage() {
743
- const cpus = import_os3.default.cpus();
844
+ const cpus = import_os4.default.cpus();
744
845
  let idle = 0;
745
846
  let total = 0;
746
847
  for (const cpu of cpus) {
@@ -760,7 +861,7 @@ function getCpuUsage() {
760
861
  function getRootPaths() {
761
862
  if (process.platform === "win32") {
762
863
  try {
763
- const output = (0, import_child_process3.execSync)("wmic logicaldisk get name", { encoding: "utf-8" });
864
+ const output = (0, import_child_process4.execSync)("wmic logicaldisk get name", { encoding: "utf-8" });
764
865
  return output.split("\n").map((l) => l.trim()).filter((l) => /^[A-Z]:$/.test(l)).map((l) => l + "\\");
765
866
  } catch {
766
867
  return ["C:\\"];
@@ -769,29 +870,29 @@ function getRootPaths() {
769
870
  return ["/"];
770
871
  }
771
872
  function buildHeartbeat(homeDir) {
772
- const totalMem = import_os3.default.totalmem();
773
- const freeMem = import_os3.default.freemem();
873
+ const totalMem = import_os4.default.totalmem();
874
+ const freeMem = import_os4.default.freemem();
774
875
  return {
775
- hostname: import_os3.default.hostname(),
876
+ hostname: import_os4.default.hostname(),
776
877
  platform: process.platform,
777
- arch: import_os3.default.arch(),
878
+ arch: import_os4.default.arch(),
778
879
  cpuUsage: getCpuUsage(),
779
880
  memoryUsage: Math.round((totalMem - freeMem) / totalMem * 100),
780
- uptime: Math.round(import_os3.default.uptime()),
881
+ uptime: Math.round(import_os4.default.uptime()),
781
882
  activeSessions: getActiveSessionCount(),
782
- pathSeparator: import_path4.default.sep,
783
- homeDirectory: homeDir || import_os3.default.homedir(),
883
+ pathSeparator: import_path5.default.sep,
884
+ homeDirectory: homeDir || import_os4.default.homedir(),
784
885
  rootPaths: getRootPaths(),
785
886
  capabilities: { terminal: true, fileTransfer: false }
786
887
  };
787
888
  }
788
- var import_os3, import_path4, import_child_process3, prevCpu;
889
+ var import_os4, import_path5, import_child_process4, prevCpu;
789
890
  var init_heartbeat = __esm({
790
891
  "src/heartbeat.ts"() {
791
892
  "use strict";
792
- import_os3 = __toESM(require("os"));
793
- import_path4 = __toESM(require("path"));
794
- import_child_process3 = require("child_process");
893
+ import_os4 = __toESM(require("os"));
894
+ import_path5 = __toESM(require("path"));
895
+ import_child_process4 = require("child_process");
795
896
  init_terminal_manager();
796
897
  prevCpu = null;
797
898
  }
@@ -799,28 +900,28 @@ var init_heartbeat = __esm({
799
900
 
800
901
  // src/file-explorer.ts
801
902
  function isInSecretDir(resolved) {
802
- const rel = import_path5.default.relative(SECRET_DIR, resolved);
803
- return rel === "" || !rel.startsWith(".." + import_path5.default.sep) && rel !== ".." && !import_path5.default.isAbsolute(rel);
903
+ const rel = import_path6.default.relative(SECRET_DIR, resolved);
904
+ return rel === "" || !rel.startsWith(".." + import_path6.default.sep) && rel !== ".." && !import_path6.default.isAbsolute(rel);
804
905
  }
805
906
  function listDirectory(dirPath) {
806
907
  try {
807
- const resolved = import_path5.default.resolve(dirPath);
908
+ const resolved = import_path6.default.resolve(dirPath);
808
909
  if (isInSecretDir(resolved)) {
809
910
  return { entries: [], error: "Access denied" };
810
911
  }
811
- if (!import_fs5.default.existsSync(resolved)) {
912
+ if (!import_fs6.default.existsSync(resolved)) {
812
913
  return { entries: [], error: "Path does not exist" };
813
914
  }
814
- const stat = import_fs5.default.statSync(resolved);
915
+ const stat = import_fs6.default.statSync(resolved);
815
916
  if (!stat.isDirectory()) {
816
917
  return { entries: [], error: "Not a directory" };
817
918
  }
818
- const dirents = import_fs5.default.readdirSync(resolved, { withFileTypes: true });
919
+ const dirents = import_fs6.default.readdirSync(resolved, { withFileTypes: true });
819
920
  const entries = [];
820
921
  for (const dirent of dirents) {
821
922
  try {
822
- const fullPath = import_path5.default.join(resolved, dirent.name);
823
- const s = import_fs5.default.statSync(fullPath);
923
+ const fullPath = import_path6.default.join(resolved, dirent.name);
924
+ const s = import_fs6.default.statSync(fullPath);
824
925
  entries.push({
825
926
  name: dirent.name,
826
927
  isDirectory: dirent.isDirectory(),
@@ -842,22 +943,22 @@ function listDirectory(dirPath) {
842
943
  }
843
944
  async function downloadFile(filePath, serverUrl, secret, agentId) {
844
945
  try {
845
- const resolved = import_path5.default.resolve(filePath);
946
+ const resolved = import_path6.default.resolve(filePath);
846
947
  if (isInSecretDir(resolved)) {
847
948
  return { error: "Access denied" };
848
949
  }
849
- if (!import_fs5.default.existsSync(resolved)) {
950
+ if (!import_fs6.default.existsSync(resolved)) {
850
951
  return { error: "File does not exist" };
851
952
  }
852
- const stat = import_fs5.default.statSync(resolved);
953
+ const stat = import_fs6.default.statSync(resolved);
853
954
  if (stat.isDirectory()) {
854
955
  return { error: "Cannot download a directory" };
855
956
  }
856
957
  if (stat.size > FILE_MAX_SIZE) {
857
958
  return { error: `File too large (max ${FILE_MAX_SIZE} bytes)` };
858
959
  }
859
- const fileName = import_path5.default.basename(resolved);
860
- const fileStream = import_fs5.default.createReadStream(resolved);
960
+ const fileName = import_path6.default.basename(resolved);
961
+ const fileStream = import_fs6.default.createReadStream(resolved);
861
962
  const baseUrl = serverUrl.replace("wss://", "https://").replace("ws://", "http://");
862
963
  const url = `${baseUrl}/api/files/receive`;
863
964
  const res = await fetch(url, {
@@ -886,16 +987,16 @@ async function downloadFile(filePath, serverUrl, secret, agentId) {
886
987
  return { error: err.message };
887
988
  }
888
989
  }
889
- var import_fs5, import_path5, import_os4, SECRET_DIR;
990
+ var import_fs6, import_path6, import_os5, SECRET_DIR;
890
991
  var init_file_explorer = __esm({
891
992
  "src/file-explorer.ts"() {
892
993
  "use strict";
893
- import_fs5 = __toESM(require("fs"));
894
- import_path5 = __toESM(require("path"));
895
- import_os4 = __toESM(require("os"));
994
+ import_fs6 = __toESM(require("fs"));
995
+ import_path6 = __toESM(require("path"));
996
+ import_os5 = __toESM(require("os"));
896
997
  init_logger();
897
998
  init_src();
898
- SECRET_DIR = import_path5.default.join(import_os4.default.homedir(), ".crc-agent");
999
+ SECRET_DIR = import_path6.default.join(import_os5.default.homedir(), ".crc-agent");
899
1000
  }
900
1001
  });
901
1002
 
@@ -918,8 +1019,8 @@ async function runCmd(cmd2, shell) {
918
1019
  }
919
1020
  function getConfigPath(profile) {
920
1021
  const file = profile.configFile || `${profile.id}.conf`;
921
- if (import_path6.default.isAbsolute(file)) return file;
922
- return import_path6.default.join(VPN_DIR, file);
1022
+ if (import_path7.default.isAbsolute(file)) return file;
1023
+ return import_path7.default.join(VPN_DIR, file);
923
1024
  }
924
1025
  async function getScutilStatus(serviceName) {
925
1026
  const { stdout } = await runCmd(`scutil --nc status '${shq2(serviceName)}'`);
@@ -1035,7 +1136,7 @@ async function connectWireGuard(profile) {
1035
1136
  const tunnelName = profile.tunnelName || profile.id;
1036
1137
  if (isWindows) {
1037
1138
  const confPath2 = getConfigPath(profile);
1038
- if (!import_fs6.default.existsSync(confPath2)) {
1139
+ if (!import_fs7.default.existsSync(confPath2)) {
1039
1140
  return `Config file not found: ${confPath2}`;
1040
1141
  }
1041
1142
  const script = `
@@ -1061,7 +1162,7 @@ async function connectWireGuard(profile) {
1061
1162
  async function connectOpenVpn(profile) {
1062
1163
  if (isWindows) {
1063
1164
  const confPath2 = getConfigPath(profile);
1064
- if (!import_fs6.default.existsSync(confPath2)) {
1165
+ if (!import_fs7.default.existsSync(confPath2)) {
1065
1166
  return `Config file not found: ${confPath2}`;
1066
1167
  }
1067
1168
  const connector = "C:\\Program Files\\OpenVPN Connect\\ovpnconnector.exe";
@@ -1088,7 +1189,7 @@ async function connectOpenVpn(profile) {
1088
1189
  return scutilStart(profile.serviceName);
1089
1190
  }
1090
1191
  const confPath = getConfigPath(profile);
1091
- if (!import_fs6.default.existsSync(confPath)) {
1192
+ if (!import_fs7.default.existsSync(confPath)) {
1092
1193
  return `Config file not found: ${confPath}`;
1093
1194
  }
1094
1195
  const { stderr } = await runCmd(`sudo openvpn --config '${shq2(confPath)}' --daemon`);
@@ -1097,7 +1198,7 @@ async function connectOpenVpn(profile) {
1097
1198
  async function connectAzure(profile) {
1098
1199
  if (isWindows) {
1099
1200
  const confPath = getConfigPath(profile);
1100
- if (!import_fs6.default.existsSync(confPath)) {
1201
+ if (!import_fs7.default.existsSync(confPath)) {
1101
1202
  return `Config file not found: ${confPath}`;
1102
1203
  }
1103
1204
  await runCmd(`& 'AzureVpn.exe' -i '${psq(confPath)}' 2>&1`);
@@ -1217,19 +1318,19 @@ async function disconnectVpn(configs, profileId) {
1217
1318
  }
1218
1319
  return profiles;
1219
1320
  }
1220
- var import_child_process4, import_util2, import_fs6, import_path6, import_os5, execAsync, isWindows, VPN_DIR;
1321
+ var import_child_process5, import_util3, import_fs7, import_path7, import_os6, execAsync, isWindows, VPN_DIR;
1221
1322
  var init_vpn_manager = __esm({
1222
1323
  "src/vpn-manager.ts"() {
1223
1324
  "use strict";
1224
- import_child_process4 = require("child_process");
1225
- import_util2 = require("util");
1226
- import_fs6 = __toESM(require("fs"));
1227
- import_path6 = __toESM(require("path"));
1228
- import_os5 = __toESM(require("os"));
1325
+ import_child_process5 = require("child_process");
1326
+ import_util3 = require("util");
1327
+ import_fs7 = __toESM(require("fs"));
1328
+ import_path7 = __toESM(require("path"));
1329
+ import_os6 = __toESM(require("os"));
1229
1330
  init_logger();
1230
- execAsync = (0, import_util2.promisify)(import_child_process4.exec);
1331
+ execAsync = (0, import_util3.promisify)(import_child_process5.exec);
1231
1332
  isWindows = process.platform === "win32";
1232
- VPN_DIR = import_path6.default.join(import_os5.default.homedir(), ".crc-agent", "vpn");
1333
+ VPN_DIR = import_path7.default.join(import_os6.default.homedir(), ".crc-agent", "vpn");
1233
1334
  }
1234
1335
  });
1235
1336
 
@@ -1264,7 +1365,7 @@ var init_claude_path = __esm({
1264
1365
  // src/claude-sessions.ts
1265
1366
  async function parseSessionFile(filePath) {
1266
1367
  try {
1267
- const stream = import_fs7.default.createReadStream(filePath, { encoding: "utf-8" });
1368
+ const stream = import_fs8.default.createReadStream(filePath, { encoding: "utf-8" });
1268
1369
  const rl = import_readline2.default.createInterface({ input: stream, crlfDelay: Infinity });
1269
1370
  let firstMessage = "";
1270
1371
  let lastTimestamp = "";
@@ -1312,17 +1413,17 @@ async function parseSessionFile(filePath) {
1312
1413
  }
1313
1414
  async function listClaudeSessions(filterProjectPath) {
1314
1415
  const sessions2 = [];
1315
- if (!import_fs7.default.existsSync(CLAUDE_PROJECTS_DIR)) return sessions2;
1416
+ if (!import_fs8.default.existsSync(CLAUDE_PROJECTS_DIR)) return sessions2;
1316
1417
  const isDirSafe = (d) => {
1317
1418
  try {
1318
- return import_fs7.default.statSync(import_path7.default.join(CLAUDE_PROJECTS_DIR, d)).isDirectory();
1419
+ return import_fs8.default.statSync(import_path8.default.join(CLAUDE_PROJECTS_DIR, d)).isDirectory();
1319
1420
  } catch {
1320
1421
  return false;
1321
1422
  }
1322
1423
  };
1323
1424
  let allEntries;
1324
1425
  try {
1325
- allEntries = import_fs7.default.readdirSync(CLAUDE_PROJECTS_DIR);
1426
+ allEntries = import_fs8.default.readdirSync(CLAUDE_PROJECTS_DIR);
1326
1427
  } catch {
1327
1428
  return sessions2;
1328
1429
  }
@@ -1335,16 +1436,16 @@ async function listClaudeSessions(filterProjectPath) {
1335
1436
  projectDirs = allEntries.filter((d) => isDirSafe(d) && !d.startsWith("-private-"));
1336
1437
  }
1337
1438
  for (const dirName of projectDirs) {
1338
- const dirPath = import_path7.default.join(CLAUDE_PROJECTS_DIR, dirName);
1439
+ const dirPath = import_path8.default.join(CLAUDE_PROJECTS_DIR, dirName);
1339
1440
  let files;
1340
1441
  try {
1341
- files = import_fs7.default.readdirSync(dirPath).filter((f) => f.endsWith(".jsonl"));
1442
+ files = import_fs8.default.readdirSync(dirPath).filter((f) => f.endsWith(".jsonl"));
1342
1443
  } catch {
1343
1444
  continue;
1344
1445
  }
1345
1446
  for (const file of files) {
1346
1447
  const sessionId = file.replace(".jsonl", "");
1347
- const parsed = await parseSessionFile(import_path7.default.join(dirPath, file));
1448
+ const parsed = await parseSessionFile(import_path8.default.join(dirPath, file));
1348
1449
  if (!parsed) continue;
1349
1450
  const projectPath = parsed.cwd || dirName.replace(/^-/, "/").replace(/-/g, "/");
1350
1451
  sessions2.push({
@@ -1362,31 +1463,31 @@ async function listClaudeSessions(filterProjectPath) {
1362
1463
  sessions2.sort((a, b) => b.lastTimestamp > a.lastTimestamp ? 1 : -1);
1363
1464
  return sessions2;
1364
1465
  }
1365
- var import_fs7, import_path7, import_os6, import_readline2, CLAUDE_PROJECTS_DIR;
1466
+ var import_fs8, import_path8, import_os7, import_readline2, CLAUDE_PROJECTS_DIR;
1366
1467
  var init_claude_sessions = __esm({
1367
1468
  "src/claude-sessions.ts"() {
1368
1469
  "use strict";
1369
- import_fs7 = __toESM(require("fs"));
1370
- import_path7 = __toESM(require("path"));
1371
- import_os6 = __toESM(require("os"));
1470
+ import_fs8 = __toESM(require("fs"));
1471
+ import_path8 = __toESM(require("path"));
1472
+ import_os7 = __toESM(require("os"));
1372
1473
  import_readline2 = __toESM(require("readline"));
1373
1474
  init_logger();
1374
1475
  init_claude_path();
1375
- CLAUDE_PROJECTS_DIR = import_path7.default.join(import_os6.default.homedir(), ".claude", "projects");
1476
+ CLAUDE_PROJECTS_DIR = import_path8.default.join(import_os7.default.homedir(), ".claude", "projects");
1376
1477
  }
1377
1478
  });
1378
1479
 
1379
1480
  // src/claude-conversation.ts
1380
1481
  function findProjectDir(projectPath) {
1381
1482
  const encoded = encodeProjectPath(projectPath);
1382
- const dirPath = import_path8.default.join(CLAUDE_PROJECTS_DIR2, encoded);
1383
- if (import_fs8.default.existsSync(dirPath)) return dirPath;
1384
- if (!import_fs8.default.existsSync(CLAUDE_PROJECTS_DIR2)) return null;
1483
+ const dirPath = import_path9.default.join(CLAUDE_PROJECTS_DIR2, encoded);
1484
+ if (import_fs9.default.existsSync(dirPath)) return dirPath;
1485
+ if (!import_fs9.default.existsSync(CLAUDE_PROJECTS_DIR2)) return null;
1385
1486
  let allDirs;
1386
1487
  try {
1387
- allDirs = import_fs8.default.readdirSync(CLAUDE_PROJECTS_DIR2).filter((d) => {
1488
+ allDirs = import_fs9.default.readdirSync(CLAUDE_PROJECTS_DIR2).filter((d) => {
1388
1489
  try {
1389
- return import_fs8.default.statSync(import_path8.default.join(CLAUDE_PROJECTS_DIR2, d)).isDirectory();
1490
+ return import_fs9.default.statSync(import_path9.default.join(CLAUDE_PROJECTS_DIR2, d)).isDirectory();
1390
1491
  } catch {
1391
1492
  return false;
1392
1493
  }
@@ -1396,23 +1497,23 @@ function findProjectDir(projectPath) {
1396
1497
  }
1397
1498
  const matches = findProjectDirs(allDirs, projectPath);
1398
1499
  if (matches.length > 0) {
1399
- return import_path8.default.join(CLAUDE_PROJECTS_DIR2, matches[0]);
1500
+ return import_path9.default.join(CLAUDE_PROJECTS_DIR2, matches[0]);
1400
1501
  }
1401
1502
  return null;
1402
1503
  }
1403
1504
  function findSessionFileById(sessionId) {
1404
1505
  if (!/^[A-Za-z0-9._-]+$/.test(sessionId)) return null;
1405
- if (!import_fs8.default.existsSync(CLAUDE_PROJECTS_DIR2)) return null;
1506
+ if (!import_fs9.default.existsSync(CLAUDE_PROJECTS_DIR2)) return null;
1406
1507
  let dirs;
1407
1508
  try {
1408
- dirs = import_fs8.default.readdirSync(CLAUDE_PROJECTS_DIR2);
1509
+ dirs = import_fs9.default.readdirSync(CLAUDE_PROJECTS_DIR2);
1409
1510
  } catch {
1410
1511
  return null;
1411
1512
  }
1412
1513
  for (const dir of dirs) {
1413
- const candidate = import_path8.default.join(CLAUDE_PROJECTS_DIR2, dir, `${sessionId}.jsonl`);
1514
+ const candidate = import_path9.default.join(CLAUDE_PROJECTS_DIR2, dir, `${sessionId}.jsonl`);
1414
1515
  try {
1415
- if (import_fs8.default.statSync(candidate).isFile()) return candidate;
1516
+ if (import_fs9.default.statSync(candidate).isFile()) return candidate;
1416
1517
  } catch {
1417
1518
  }
1418
1519
  }
@@ -1423,20 +1524,20 @@ function findLatestSessionFile(projectPath) {
1423
1524
  if (!dirPath) return null;
1424
1525
  let entries;
1425
1526
  try {
1426
- entries = import_fs8.default.readdirSync(dirPath);
1527
+ entries = import_fs9.default.readdirSync(dirPath);
1427
1528
  } catch {
1428
1529
  return null;
1429
1530
  }
1430
1531
  const files = entries.filter((f) => f.endsWith(".jsonl") && !f.includes("/")).map((f) => {
1431
1532
  try {
1432
- return { name: f, mtime: import_fs8.default.statSync(import_path8.default.join(dirPath, f)).mtimeMs };
1533
+ return { name: f, mtime: import_fs9.default.statSync(import_path9.default.join(dirPath, f)).mtimeMs };
1433
1534
  } catch {
1434
1535
  return null;
1435
1536
  }
1436
1537
  }).filter((f) => f !== null).sort((a, b) => b.mtime - a.mtime);
1437
1538
  if (files.length === 0) return null;
1438
1539
  return {
1439
- filePath: import_path8.default.join(dirPath, files[0].name),
1540
+ filePath: import_path9.default.join(dirPath, files[0].name),
1440
1541
  sessionId: files[0].name.replace(".jsonl", "")
1441
1542
  };
1442
1543
  }
@@ -1446,8 +1547,8 @@ async function readConversation(projectPath, afterLine = 0, specificSessionId) {
1446
1547
  if (specificSessionId) {
1447
1548
  sessionId = specificSessionId;
1448
1549
  const dirPath = findProjectDir(projectPath);
1449
- const direct = dirPath ? import_path8.default.join(dirPath, `${specificSessionId}.jsonl`) : null;
1450
- if (direct && import_fs8.default.existsSync(direct)) {
1550
+ const direct = dirPath ? import_path9.default.join(dirPath, `${specificSessionId}.jsonl`) : null;
1551
+ if (direct && import_fs9.default.existsSync(direct)) {
1451
1552
  filePath = direct;
1452
1553
  } else {
1453
1554
  const byId = findSessionFileById(specificSessionId);
@@ -1461,7 +1562,7 @@ async function readConversation(projectPath, afterLine = 0, specificSessionId) {
1461
1562
  sessionId = found.sessionId;
1462
1563
  }
1463
1564
  try {
1464
- const stream = import_fs8.default.createReadStream(filePath, { encoding: "utf-8" });
1565
+ const stream = import_fs9.default.createReadStream(filePath, { encoding: "utf-8" });
1465
1566
  const rl = import_readline3.default.createInterface({ input: stream, crlfDelay: Infinity });
1466
1567
  const messages = [];
1467
1568
  let lineNum = 0;
@@ -1542,17 +1643,17 @@ async function readConversation(projectPath, afterLine = 0, specificSessionId) {
1542
1643
  return null;
1543
1644
  }
1544
1645
  }
1545
- var import_fs8, import_path8, import_os7, import_readline3, CLAUDE_PROJECTS_DIR2;
1646
+ var import_fs9, import_path9, import_os8, import_readline3, CLAUDE_PROJECTS_DIR2;
1546
1647
  var init_claude_conversation = __esm({
1547
1648
  "src/claude-conversation.ts"() {
1548
1649
  "use strict";
1549
- import_fs8 = __toESM(require("fs"));
1550
- import_path8 = __toESM(require("path"));
1551
- import_os7 = __toESM(require("os"));
1650
+ import_fs9 = __toESM(require("fs"));
1651
+ import_path9 = __toESM(require("path"));
1652
+ import_os8 = __toESM(require("os"));
1552
1653
  import_readline3 = __toESM(require("readline"));
1553
1654
  init_logger();
1554
1655
  init_claude_path();
1555
- CLAUDE_PROJECTS_DIR2 = import_path8.default.join(import_os7.default.homedir(), ".claude", "projects");
1656
+ CLAUDE_PROJECTS_DIR2 = import_path9.default.join(import_os8.default.homedir(), ".claude", "projects");
1556
1657
  }
1557
1658
  });
1558
1659
 
@@ -1735,8 +1836,8 @@ var init_index = __esm({
1735
1836
  const { requestId, command, cwd } = payload;
1736
1837
  if (!requestId) return;
1737
1838
  const { exec: exec2 } = await import("child_process");
1738
- const { promisify: promisify3 } = await import("util");
1739
- const execAsync2 = promisify3(exec2);
1839
+ const { promisify: promisify4 } = await import("util");
1840
+ const execAsync2 = promisify4(exec2);
1740
1841
  try {
1741
1842
  const { stdout, stderr } = await execAsync2(command, { cwd, timeout: 3e4 });
1742
1843
  socket.emit(AGENT_EXEC_RESULT, { requestId, stdout: stdout || "", stderr: stderr || "" });