cli-remote-agent 1.0.5 → 1.0.6
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 +137 -103
- package/dist/cli.js.map +1 -1
- package/dist/index.js +139 -101
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -496,8 +496,27 @@ var init_claude_live = __esm({
|
|
|
496
496
|
});
|
|
497
497
|
|
|
498
498
|
// src/tmux.ts
|
|
499
|
+
function resolveTmuxPath() {
|
|
500
|
+
if (cachedTmuxPath !== void 0) return cachedTmuxPath;
|
|
501
|
+
const dirs = (process.env.PATH || "").split(import_path4.default.delimiter).filter(Boolean);
|
|
502
|
+
for (const extra of ["/opt/homebrew/bin", "/usr/local/bin", "/usr/bin", "/bin", "/opt/local/bin"]) {
|
|
503
|
+
if (!dirs.includes(extra)) dirs.push(extra);
|
|
504
|
+
}
|
|
505
|
+
for (const dir of dirs) {
|
|
506
|
+
const candidate = import_path4.default.join(dir, "tmux");
|
|
507
|
+
try {
|
|
508
|
+
import_fs5.default.accessSync(candidate, import_fs5.default.constants.X_OK);
|
|
509
|
+
cachedTmuxPath = candidate;
|
|
510
|
+
return candidate;
|
|
511
|
+
} catch {
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
cachedTmuxPath = null;
|
|
515
|
+
return null;
|
|
516
|
+
}
|
|
499
517
|
function tmuxCmd(args) {
|
|
500
|
-
|
|
518
|
+
if (IS_WIN) return { file: "wsl.exe", args: ["tmux", ...args] };
|
|
519
|
+
return { file: resolveTmuxPath() || "tmux", args };
|
|
501
520
|
}
|
|
502
521
|
async function listTmuxSessions() {
|
|
503
522
|
const fmt = "#{session_name} #{session_windows} #{session_attached} #{session_activity}";
|
|
@@ -536,8 +555,8 @@ async function enrichWithPanesAndClaude(sessions2) {
|
|
|
536
555
|
const { file, args } = tmuxCmd(["list-panes", "-a", "-F", paneFmt]);
|
|
537
556
|
const { stdout } = await execFileAsync2(file, args, { timeout: 6e3 });
|
|
538
557
|
const panes = stdout.split("\n").map((line) => line.replace(/\r$/, "").trim()).filter(Boolean).map((line) => {
|
|
539
|
-
const [session, pid,
|
|
540
|
-
return { session, pid: parseInt(pid, 10) || 0, path:
|
|
558
|
+
const [session, pid, path9, activeFlags] = line.split(" ");
|
|
559
|
+
return { session, pid: parseInt(pid, 10) || 0, path: path9 || "", active: activeFlags === "11" };
|
|
541
560
|
});
|
|
542
561
|
const byName = new Map(sessions2.map((s) => [s.name, s]));
|
|
543
562
|
for (const pane of panes) {
|
|
@@ -559,26 +578,31 @@ async function enrichWithPanesAndClaude(sessions2) {
|
|
|
559
578
|
} catch {
|
|
560
579
|
}
|
|
561
580
|
}
|
|
562
|
-
function
|
|
563
|
-
return `'${v.replace(/'/g, `'\\''`)}'`;
|
|
564
|
-
}
|
|
565
|
-
function buildTmuxLaunch(name, launch, shell) {
|
|
581
|
+
function buildTmuxLaunch(name, launch) {
|
|
566
582
|
const trimmed = launch && launch.trim() ? launch.trim() : void 0;
|
|
567
583
|
if (IS_WIN) {
|
|
568
|
-
const
|
|
569
|
-
if (trimmed)
|
|
570
|
-
return { file: "wsl.exe", args };
|
|
571
|
-
}
|
|
572
|
-
|
|
573
|
-
if (
|
|
574
|
-
|
|
584
|
+
const args2 = ["tmux", "new-session", "-A", "-s", name];
|
|
585
|
+
if (trimmed) args2.push(trimmed);
|
|
586
|
+
return { file: "wsl.exe", args: args2 };
|
|
587
|
+
}
|
|
588
|
+
const tmuxBin = resolveTmuxPath();
|
|
589
|
+
if (!tmuxBin) return null;
|
|
590
|
+
execFileAsync2(tmuxBin, ["set-option", "-g", "aggressive-resize", "on"], { timeout: 4e3 }).catch(
|
|
591
|
+
() => {
|
|
592
|
+
}
|
|
593
|
+
);
|
|
594
|
+
const args = ["new-session", "-A", "-s", name];
|
|
595
|
+
if (trimmed) args.push(trimmed);
|
|
596
|
+
return { file: tmuxBin, args };
|
|
575
597
|
}
|
|
576
|
-
var import_child_process2, import_util2, execFileAsync2, IS_WIN;
|
|
598
|
+
var import_child_process2, import_util2, import_fs5, import_path4, execFileAsync2, IS_WIN, cachedTmuxPath;
|
|
577
599
|
var init_tmux = __esm({
|
|
578
600
|
"src/tmux.ts"() {
|
|
579
601
|
"use strict";
|
|
580
602
|
import_child_process2 = require("child_process");
|
|
581
603
|
import_util2 = require("util");
|
|
604
|
+
import_fs5 = __toESM(require("fs"));
|
|
605
|
+
import_path4 = __toESM(require("path"));
|
|
582
606
|
init_claude_live();
|
|
583
607
|
execFileAsync2 = (0, import_util2.promisify)(import_child_process2.execFile);
|
|
584
608
|
IS_WIN = process.platform === "win32";
|
|
@@ -608,15 +632,15 @@ var init_shell = __esm({
|
|
|
608
632
|
|
|
609
633
|
// src/pty-session.ts
|
|
610
634
|
function ensureInitFiles() {
|
|
611
|
-
const versionFile = (0,
|
|
612
|
-
if ((0,
|
|
635
|
+
const versionFile = (0, import_path5.join)(INIT_DIR, ".version");
|
|
636
|
+
if ((0, import_fs6.existsSync)(versionFile)) {
|
|
613
637
|
try {
|
|
614
|
-
if ((0,
|
|
638
|
+
if ((0, import_fs6.readFileSync)(versionFile, "utf-8").trim() === INIT_VERSION) return;
|
|
615
639
|
} catch {
|
|
616
640
|
}
|
|
617
641
|
}
|
|
618
|
-
(0,
|
|
619
|
-
(0,
|
|
642
|
+
(0, import_fs6.mkdirSync)(ZSH_DIR, { recursive: true });
|
|
643
|
+
(0, import_fs6.writeFileSync)(BASH_INIT, [
|
|
620
644
|
"[ -f ~/.bash_profile ] && source ~/.bash_profile",
|
|
621
645
|
"[ -f ~/.bashrc ] && source ~/.bashrc",
|
|
622
646
|
"__crc_s=$SECONDS",
|
|
@@ -627,11 +651,11 @@ function ensureInitFiles() {
|
|
|
627
651
|
`PROMPT_COMMAND='[ "$__crc_armed" = 1 ] && [ \${__crc_elapsed:-0} -ge ${THRESHOLD} ] && printf "\\a"; __crc_armed=1; eval "$__crc_orig_pc"'`,
|
|
628
652
|
""
|
|
629
653
|
].join("\n"), "utf-8");
|
|
630
|
-
(0,
|
|
654
|
+
(0, import_fs6.writeFileSync)(ZSH_ENV, [
|
|
631
655
|
'[ -f "${ZDOTDIR_ORIG:-$HOME}/.zshenv" ] && source "${ZDOTDIR_ORIG:-$HOME}/.zshenv"',
|
|
632
656
|
""
|
|
633
657
|
].join("\n"), "utf-8");
|
|
634
|
-
(0,
|
|
658
|
+
(0, import_fs6.writeFileSync)(ZSH_RC, [
|
|
635
659
|
'[ -f "${ZDOTDIR_ORIG:-$HOME}/.zshrc" ] && source "${ZDOTDIR_ORIG:-$HOME}/.zshrc"',
|
|
636
660
|
"__crc_s=$SECONDS",
|
|
637
661
|
"__crc_armed=0",
|
|
@@ -644,36 +668,36 @@ function ensureInitFiles() {
|
|
|
644
668
|
"fi",
|
|
645
669
|
""
|
|
646
670
|
].join("\n"), "utf-8");
|
|
647
|
-
(0,
|
|
671
|
+
(0, import_fs6.writeFileSync)(versionFile, INIT_VERSION, "utf-8");
|
|
648
672
|
}
|
|
649
673
|
function resolveCwd(cwd) {
|
|
650
674
|
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];
|
|
651
675
|
for (const c of candidates) {
|
|
652
676
|
if (c) {
|
|
653
677
|
try {
|
|
654
|
-
if ((0,
|
|
678
|
+
if ((0, import_fs6.existsSync)(c)) return c;
|
|
655
679
|
} catch {
|
|
656
680
|
}
|
|
657
681
|
}
|
|
658
682
|
}
|
|
659
683
|
return (0, import_os3.homedir)();
|
|
660
684
|
}
|
|
661
|
-
var pty,
|
|
685
|
+
var pty, import_fs6, import_path5, import_os3, THRESHOLD, INIT_DIR, BASH_INIT, ZSH_DIR, ZSH_RC, ZSH_ENV, INIT_VERSION, PtySession;
|
|
662
686
|
var init_pty_session = __esm({
|
|
663
687
|
"src/pty-session.ts"() {
|
|
664
688
|
"use strict";
|
|
665
689
|
pty = __toESM(require("node-pty"));
|
|
666
|
-
|
|
667
|
-
|
|
690
|
+
import_fs6 = require("fs");
|
|
691
|
+
import_path5 = require("path");
|
|
668
692
|
import_os3 = require("os");
|
|
669
693
|
init_src();
|
|
670
694
|
init_shell();
|
|
671
695
|
THRESHOLD = 3;
|
|
672
|
-
INIT_DIR = (0,
|
|
673
|
-
BASH_INIT = (0,
|
|
674
|
-
ZSH_DIR = (0,
|
|
675
|
-
ZSH_RC = (0,
|
|
676
|
-
ZSH_ENV = (0,
|
|
696
|
+
INIT_DIR = (0, import_path5.join)((0, import_os3.tmpdir)(), "crc-shell-init");
|
|
697
|
+
BASH_INIT = (0, import_path5.join)(INIT_DIR, "bashrc");
|
|
698
|
+
ZSH_DIR = (0, import_path5.join)(INIT_DIR, "zsh");
|
|
699
|
+
ZSH_RC = (0, import_path5.join)(ZSH_DIR, ".zshrc");
|
|
700
|
+
ZSH_ENV = (0, import_path5.join)(ZSH_DIR, ".zshenv");
|
|
677
701
|
INIT_VERSION = "2";
|
|
678
702
|
PtySession = class {
|
|
679
703
|
id;
|
|
@@ -903,18 +927,18 @@ function buildHeartbeat(homeDir) {
|
|
|
903
927
|
memoryUsage: Math.round((totalMem - freeMem) / totalMem * 100),
|
|
904
928
|
uptime: Math.round(import_os4.default.uptime()),
|
|
905
929
|
activeSessions: getActiveSessionCount(),
|
|
906
|
-
pathSeparator:
|
|
930
|
+
pathSeparator: import_path6.default.sep,
|
|
907
931
|
homeDirectory: homeDir || import_os4.default.homedir(),
|
|
908
932
|
rootPaths: getRootPaths(),
|
|
909
933
|
capabilities: { terminal: true, fileTransfer: false }
|
|
910
934
|
};
|
|
911
935
|
}
|
|
912
|
-
var import_os4,
|
|
936
|
+
var import_os4, import_path6, import_child_process4, prevCpu;
|
|
913
937
|
var init_heartbeat = __esm({
|
|
914
938
|
"src/heartbeat.ts"() {
|
|
915
939
|
"use strict";
|
|
916
940
|
import_os4 = __toESM(require("os"));
|
|
917
|
-
|
|
941
|
+
import_path6 = __toESM(require("path"));
|
|
918
942
|
import_child_process4 = require("child_process");
|
|
919
943
|
init_terminal_manager();
|
|
920
944
|
prevCpu = null;
|
|
@@ -923,28 +947,28 @@ var init_heartbeat = __esm({
|
|
|
923
947
|
|
|
924
948
|
// src/file-explorer.ts
|
|
925
949
|
function isInSecretDir(resolved) {
|
|
926
|
-
const rel =
|
|
927
|
-
return rel === "" || !rel.startsWith(".." +
|
|
950
|
+
const rel = import_path7.default.relative(SECRET_DIR, resolved);
|
|
951
|
+
return rel === "" || !rel.startsWith(".." + import_path7.default.sep) && rel !== ".." && !import_path7.default.isAbsolute(rel);
|
|
928
952
|
}
|
|
929
953
|
function listDirectory(dirPath) {
|
|
930
954
|
try {
|
|
931
|
-
const resolved =
|
|
955
|
+
const resolved = import_path7.default.resolve(dirPath);
|
|
932
956
|
if (isInSecretDir(resolved)) {
|
|
933
957
|
return { entries: [], error: "Access denied" };
|
|
934
958
|
}
|
|
935
|
-
if (!
|
|
959
|
+
if (!import_fs7.default.existsSync(resolved)) {
|
|
936
960
|
return { entries: [], error: "Path does not exist" };
|
|
937
961
|
}
|
|
938
|
-
const stat =
|
|
962
|
+
const stat = import_fs7.default.statSync(resolved);
|
|
939
963
|
if (!stat.isDirectory()) {
|
|
940
964
|
return { entries: [], error: "Not a directory" };
|
|
941
965
|
}
|
|
942
|
-
const dirents =
|
|
966
|
+
const dirents = import_fs7.default.readdirSync(resolved, { withFileTypes: true });
|
|
943
967
|
const entries = [];
|
|
944
968
|
for (const dirent of dirents) {
|
|
945
969
|
try {
|
|
946
|
-
const fullPath =
|
|
947
|
-
const s =
|
|
970
|
+
const fullPath = import_path7.default.join(resolved, dirent.name);
|
|
971
|
+
const s = import_fs7.default.statSync(fullPath);
|
|
948
972
|
entries.push({
|
|
949
973
|
name: dirent.name,
|
|
950
974
|
isDirectory: dirent.isDirectory(),
|
|
@@ -966,22 +990,22 @@ function listDirectory(dirPath) {
|
|
|
966
990
|
}
|
|
967
991
|
async function downloadFile(filePath, serverUrl, secret, agentId) {
|
|
968
992
|
try {
|
|
969
|
-
const resolved =
|
|
993
|
+
const resolved = import_path7.default.resolve(filePath);
|
|
970
994
|
if (isInSecretDir(resolved)) {
|
|
971
995
|
return { error: "Access denied" };
|
|
972
996
|
}
|
|
973
|
-
if (!
|
|
997
|
+
if (!import_fs7.default.existsSync(resolved)) {
|
|
974
998
|
return { error: "File does not exist" };
|
|
975
999
|
}
|
|
976
|
-
const stat =
|
|
1000
|
+
const stat = import_fs7.default.statSync(resolved);
|
|
977
1001
|
if (stat.isDirectory()) {
|
|
978
1002
|
return { error: "Cannot download a directory" };
|
|
979
1003
|
}
|
|
980
1004
|
if (stat.size > FILE_MAX_SIZE) {
|
|
981
1005
|
return { error: `File too large (max ${FILE_MAX_SIZE} bytes)` };
|
|
982
1006
|
}
|
|
983
|
-
const fileName =
|
|
984
|
-
const fileStream =
|
|
1007
|
+
const fileName = import_path7.default.basename(resolved);
|
|
1008
|
+
const fileStream = import_fs7.default.createReadStream(resolved);
|
|
985
1009
|
const baseUrl = serverUrl.replace("wss://", "https://").replace("ws://", "http://");
|
|
986
1010
|
const url = `${baseUrl}/api/files/receive`;
|
|
987
1011
|
const res = await fetch(url, {
|
|
@@ -1010,21 +1034,21 @@ async function downloadFile(filePath, serverUrl, secret, agentId) {
|
|
|
1010
1034
|
return { error: err.message };
|
|
1011
1035
|
}
|
|
1012
1036
|
}
|
|
1013
|
-
var
|
|
1037
|
+
var import_fs7, import_path7, import_os5, SECRET_DIR;
|
|
1014
1038
|
var init_file_explorer = __esm({
|
|
1015
1039
|
"src/file-explorer.ts"() {
|
|
1016
1040
|
"use strict";
|
|
1017
|
-
|
|
1018
|
-
|
|
1041
|
+
import_fs7 = __toESM(require("fs"));
|
|
1042
|
+
import_path7 = __toESM(require("path"));
|
|
1019
1043
|
import_os5 = __toESM(require("os"));
|
|
1020
1044
|
init_logger();
|
|
1021
1045
|
init_src();
|
|
1022
|
-
SECRET_DIR =
|
|
1046
|
+
SECRET_DIR = import_path7.default.join(import_os5.default.homedir(), ".crc-agent");
|
|
1023
1047
|
}
|
|
1024
1048
|
});
|
|
1025
1049
|
|
|
1026
1050
|
// src/vpn-manager.ts
|
|
1027
|
-
function
|
|
1051
|
+
function shq(value) {
|
|
1028
1052
|
return value.replace(/'/g, "'\\''");
|
|
1029
1053
|
}
|
|
1030
1054
|
function psq(value) {
|
|
@@ -1042,11 +1066,11 @@ async function runCmd(cmd2, shell) {
|
|
|
1042
1066
|
}
|
|
1043
1067
|
function getConfigPath(profile) {
|
|
1044
1068
|
const file = profile.configFile || `${profile.id}.conf`;
|
|
1045
|
-
if (
|
|
1046
|
-
return
|
|
1069
|
+
if (import_path8.default.isAbsolute(file)) return file;
|
|
1070
|
+
return import_path8.default.join(VPN_DIR, file);
|
|
1047
1071
|
}
|
|
1048
1072
|
async function getScutilStatus(serviceName) {
|
|
1049
|
-
const { stdout } = await runCmd(`scutil --nc status '${
|
|
1073
|
+
const { stdout } = await runCmd(`scutil --nc status '${shq(serviceName)}'`);
|
|
1050
1074
|
const firstLine = stdout.trim().split("\n")[0];
|
|
1051
1075
|
if (firstLine === "Connected") return "connected";
|
|
1052
1076
|
if (firstLine === "Connecting") return "connecting";
|
|
@@ -1054,11 +1078,11 @@ async function getScutilStatus(serviceName) {
|
|
|
1054
1078
|
return "disconnected";
|
|
1055
1079
|
}
|
|
1056
1080
|
async function scutilStart(serviceName) {
|
|
1057
|
-
const { stderr } = await runCmd(`scutil --nc start '${
|
|
1081
|
+
const { stderr } = await runCmd(`scutil --nc start '${shq(serviceName)}'`);
|
|
1058
1082
|
return stderr || null;
|
|
1059
1083
|
}
|
|
1060
1084
|
async function scutilStop(serviceName) {
|
|
1061
|
-
const { stderr } = await runCmd(`scutil --nc stop '${
|
|
1085
|
+
const { stderr } = await runCmd(`scutil --nc stop '${shq(serviceName)}'`);
|
|
1062
1086
|
return stderr || null;
|
|
1063
1087
|
}
|
|
1064
1088
|
async function runOsascript(script) {
|
|
@@ -1107,7 +1131,7 @@ async function getWireGuardStatus(profile) {
|
|
|
1107
1131
|
return getScutilStatus(profile.serviceName);
|
|
1108
1132
|
}
|
|
1109
1133
|
const tunnelName = profile.tunnelName || profile.id;
|
|
1110
|
-
const { stdout } = await runCmd(`wg show '${
|
|
1134
|
+
const { stdout } = await runCmd(`wg show '${shq(tunnelName)}' 2>/dev/null`);
|
|
1111
1135
|
return stdout.trim() ? "connected" : "disconnected";
|
|
1112
1136
|
}
|
|
1113
1137
|
async function getOpenVpnStatus(profile) {
|
|
@@ -1159,7 +1183,7 @@ async function connectWireGuard(profile) {
|
|
|
1159
1183
|
const tunnelName = profile.tunnelName || profile.id;
|
|
1160
1184
|
if (isWindows) {
|
|
1161
1185
|
const confPath2 = getConfigPath(profile);
|
|
1162
|
-
if (!
|
|
1186
|
+
if (!import_fs8.default.existsSync(confPath2)) {
|
|
1163
1187
|
return `Config file not found: ${confPath2}`;
|
|
1164
1188
|
}
|
|
1165
1189
|
const script = `
|
|
@@ -1179,13 +1203,13 @@ async function connectWireGuard(profile) {
|
|
|
1179
1203
|
return scutilStart(profile.serviceName);
|
|
1180
1204
|
}
|
|
1181
1205
|
const confPath = getConfigPath(profile);
|
|
1182
|
-
const { stderr } = await runCmd(`sudo wg-quick up '${
|
|
1206
|
+
const { stderr } = await runCmd(`sudo wg-quick up '${shq(confPath)}'`);
|
|
1183
1207
|
return stderr || null;
|
|
1184
1208
|
}
|
|
1185
1209
|
async function connectOpenVpn(profile) {
|
|
1186
1210
|
if (isWindows) {
|
|
1187
1211
|
const confPath2 = getConfigPath(profile);
|
|
1188
|
-
if (!
|
|
1212
|
+
if (!import_fs8.default.existsSync(confPath2)) {
|
|
1189
1213
|
return `Config file not found: ${confPath2}`;
|
|
1190
1214
|
}
|
|
1191
1215
|
const connector = "C:\\Program Files\\OpenVPN Connect\\ovpnconnector.exe";
|
|
@@ -1212,16 +1236,16 @@ async function connectOpenVpn(profile) {
|
|
|
1212
1236
|
return scutilStart(profile.serviceName);
|
|
1213
1237
|
}
|
|
1214
1238
|
const confPath = getConfigPath(profile);
|
|
1215
|
-
if (!
|
|
1239
|
+
if (!import_fs8.default.existsSync(confPath)) {
|
|
1216
1240
|
return `Config file not found: ${confPath}`;
|
|
1217
1241
|
}
|
|
1218
|
-
const { stderr } = await runCmd(`sudo openvpn --config '${
|
|
1242
|
+
const { stderr } = await runCmd(`sudo openvpn --config '${shq(confPath)}' --daemon`);
|
|
1219
1243
|
return stderr || null;
|
|
1220
1244
|
}
|
|
1221
1245
|
async function connectAzure(profile) {
|
|
1222
1246
|
if (isWindows) {
|
|
1223
1247
|
const confPath = getConfigPath(profile);
|
|
1224
|
-
if (!
|
|
1248
|
+
if (!import_fs8.default.existsSync(confPath)) {
|
|
1225
1249
|
return `Config file not found: ${confPath}`;
|
|
1226
1250
|
}
|
|
1227
1251
|
await runCmd(`& 'AzureVpn.exe' -i '${psq(confPath)}' 2>&1`);
|
|
@@ -1265,7 +1289,7 @@ async function disconnectWireGuard(profile) {
|
|
|
1265
1289
|
return scutilStop(profile.serviceName);
|
|
1266
1290
|
}
|
|
1267
1291
|
const confPath = getConfigPath(profile);
|
|
1268
|
-
const { stderr } = await runCmd(`sudo wg-quick down '${
|
|
1292
|
+
const { stderr } = await runCmd(`sudo wg-quick down '${shq(confPath)}'`);
|
|
1269
1293
|
return stderr || null;
|
|
1270
1294
|
}
|
|
1271
1295
|
async function disconnectOpenVpn(profile) {
|
|
@@ -1341,19 +1365,19 @@ async function disconnectVpn(configs, profileId) {
|
|
|
1341
1365
|
}
|
|
1342
1366
|
return profiles;
|
|
1343
1367
|
}
|
|
1344
|
-
var import_child_process5, import_util3,
|
|
1368
|
+
var import_child_process5, import_util3, import_fs8, import_path8, import_os6, execAsync, isWindows, VPN_DIR;
|
|
1345
1369
|
var init_vpn_manager = __esm({
|
|
1346
1370
|
"src/vpn-manager.ts"() {
|
|
1347
1371
|
"use strict";
|
|
1348
1372
|
import_child_process5 = require("child_process");
|
|
1349
1373
|
import_util3 = require("util");
|
|
1350
|
-
|
|
1351
|
-
|
|
1374
|
+
import_fs8 = __toESM(require("fs"));
|
|
1375
|
+
import_path8 = __toESM(require("path"));
|
|
1352
1376
|
import_os6 = __toESM(require("os"));
|
|
1353
1377
|
init_logger();
|
|
1354
1378
|
execAsync = (0, import_util3.promisify)(import_child_process5.exec);
|
|
1355
1379
|
isWindows = process.platform === "win32";
|
|
1356
|
-
VPN_DIR =
|
|
1380
|
+
VPN_DIR = import_path8.default.join(import_os6.default.homedir(), ".crc-agent", "vpn");
|
|
1357
1381
|
}
|
|
1358
1382
|
});
|
|
1359
1383
|
|
|
@@ -1388,7 +1412,7 @@ var init_claude_path = __esm({
|
|
|
1388
1412
|
// src/claude-sessions.ts
|
|
1389
1413
|
async function parseSessionFile(filePath) {
|
|
1390
1414
|
try {
|
|
1391
|
-
const stream =
|
|
1415
|
+
const stream = import_fs9.default.createReadStream(filePath, { encoding: "utf-8" });
|
|
1392
1416
|
const rl = import_readline2.default.createInterface({ input: stream, crlfDelay: Infinity });
|
|
1393
1417
|
let firstMessage = "";
|
|
1394
1418
|
let lastTimestamp = "";
|
|
@@ -1436,17 +1460,17 @@ async function parseSessionFile(filePath) {
|
|
|
1436
1460
|
}
|
|
1437
1461
|
async function listClaudeSessions(filterProjectPath) {
|
|
1438
1462
|
const sessions2 = [];
|
|
1439
|
-
if (!
|
|
1463
|
+
if (!import_fs9.default.existsSync(CLAUDE_PROJECTS_DIR)) return sessions2;
|
|
1440
1464
|
const isDirSafe = (d) => {
|
|
1441
1465
|
try {
|
|
1442
|
-
return
|
|
1466
|
+
return import_fs9.default.statSync(import_path9.default.join(CLAUDE_PROJECTS_DIR, d)).isDirectory();
|
|
1443
1467
|
} catch {
|
|
1444
1468
|
return false;
|
|
1445
1469
|
}
|
|
1446
1470
|
};
|
|
1447
1471
|
let allEntries;
|
|
1448
1472
|
try {
|
|
1449
|
-
allEntries =
|
|
1473
|
+
allEntries = import_fs9.default.readdirSync(CLAUDE_PROJECTS_DIR);
|
|
1450
1474
|
} catch {
|
|
1451
1475
|
return sessions2;
|
|
1452
1476
|
}
|
|
@@ -1459,16 +1483,16 @@ async function listClaudeSessions(filterProjectPath) {
|
|
|
1459
1483
|
projectDirs = allEntries.filter((d) => isDirSafe(d) && !d.startsWith("-private-"));
|
|
1460
1484
|
}
|
|
1461
1485
|
for (const dirName of projectDirs) {
|
|
1462
|
-
const dirPath =
|
|
1486
|
+
const dirPath = import_path9.default.join(CLAUDE_PROJECTS_DIR, dirName);
|
|
1463
1487
|
let files;
|
|
1464
1488
|
try {
|
|
1465
|
-
files =
|
|
1489
|
+
files = import_fs9.default.readdirSync(dirPath).filter((f) => f.endsWith(".jsonl"));
|
|
1466
1490
|
} catch {
|
|
1467
1491
|
continue;
|
|
1468
1492
|
}
|
|
1469
1493
|
for (const file of files) {
|
|
1470
1494
|
const sessionId = file.replace(".jsonl", "");
|
|
1471
|
-
const parsed = await parseSessionFile(
|
|
1495
|
+
const parsed = await parseSessionFile(import_path9.default.join(dirPath, file));
|
|
1472
1496
|
if (!parsed) continue;
|
|
1473
1497
|
const projectPath = parsed.cwd || dirName.replace(/^-/, "/").replace(/-/g, "/");
|
|
1474
1498
|
sessions2.push({
|
|
@@ -1486,31 +1510,31 @@ async function listClaudeSessions(filterProjectPath) {
|
|
|
1486
1510
|
sessions2.sort((a, b) => b.lastTimestamp > a.lastTimestamp ? 1 : -1);
|
|
1487
1511
|
return sessions2;
|
|
1488
1512
|
}
|
|
1489
|
-
var
|
|
1513
|
+
var import_fs9, import_path9, import_os7, import_readline2, CLAUDE_PROJECTS_DIR;
|
|
1490
1514
|
var init_claude_sessions = __esm({
|
|
1491
1515
|
"src/claude-sessions.ts"() {
|
|
1492
1516
|
"use strict";
|
|
1493
|
-
|
|
1494
|
-
|
|
1517
|
+
import_fs9 = __toESM(require("fs"));
|
|
1518
|
+
import_path9 = __toESM(require("path"));
|
|
1495
1519
|
import_os7 = __toESM(require("os"));
|
|
1496
1520
|
import_readline2 = __toESM(require("readline"));
|
|
1497
1521
|
init_logger();
|
|
1498
1522
|
init_claude_path();
|
|
1499
|
-
CLAUDE_PROJECTS_DIR =
|
|
1523
|
+
CLAUDE_PROJECTS_DIR = import_path9.default.join(import_os7.default.homedir(), ".claude", "projects");
|
|
1500
1524
|
}
|
|
1501
1525
|
});
|
|
1502
1526
|
|
|
1503
1527
|
// src/claude-conversation.ts
|
|
1504
1528
|
function findProjectDir(projectPath) {
|
|
1505
1529
|
const encoded = encodeProjectPath(projectPath);
|
|
1506
|
-
const dirPath =
|
|
1507
|
-
if (
|
|
1508
|
-
if (!
|
|
1530
|
+
const dirPath = import_path10.default.join(CLAUDE_PROJECTS_DIR2, encoded);
|
|
1531
|
+
if (import_fs10.default.existsSync(dirPath)) return dirPath;
|
|
1532
|
+
if (!import_fs10.default.existsSync(CLAUDE_PROJECTS_DIR2)) return null;
|
|
1509
1533
|
let allDirs;
|
|
1510
1534
|
try {
|
|
1511
|
-
allDirs =
|
|
1535
|
+
allDirs = import_fs10.default.readdirSync(CLAUDE_PROJECTS_DIR2).filter((d) => {
|
|
1512
1536
|
try {
|
|
1513
|
-
return
|
|
1537
|
+
return import_fs10.default.statSync(import_path10.default.join(CLAUDE_PROJECTS_DIR2, d)).isDirectory();
|
|
1514
1538
|
} catch {
|
|
1515
1539
|
return false;
|
|
1516
1540
|
}
|
|
@@ -1520,23 +1544,23 @@ function findProjectDir(projectPath) {
|
|
|
1520
1544
|
}
|
|
1521
1545
|
const matches = findProjectDirs(allDirs, projectPath);
|
|
1522
1546
|
if (matches.length > 0) {
|
|
1523
|
-
return
|
|
1547
|
+
return import_path10.default.join(CLAUDE_PROJECTS_DIR2, matches[0]);
|
|
1524
1548
|
}
|
|
1525
1549
|
return null;
|
|
1526
1550
|
}
|
|
1527
1551
|
function findSessionFileById(sessionId) {
|
|
1528
1552
|
if (!/^[A-Za-z0-9._-]+$/.test(sessionId)) return null;
|
|
1529
|
-
if (!
|
|
1553
|
+
if (!import_fs10.default.existsSync(CLAUDE_PROJECTS_DIR2)) return null;
|
|
1530
1554
|
let dirs;
|
|
1531
1555
|
try {
|
|
1532
|
-
dirs =
|
|
1556
|
+
dirs = import_fs10.default.readdirSync(CLAUDE_PROJECTS_DIR2);
|
|
1533
1557
|
} catch {
|
|
1534
1558
|
return null;
|
|
1535
1559
|
}
|
|
1536
1560
|
for (const dir of dirs) {
|
|
1537
|
-
const candidate =
|
|
1561
|
+
const candidate = import_path10.default.join(CLAUDE_PROJECTS_DIR2, dir, `${sessionId}.jsonl`);
|
|
1538
1562
|
try {
|
|
1539
|
-
if (
|
|
1563
|
+
if (import_fs10.default.statSync(candidate).isFile()) return candidate;
|
|
1540
1564
|
} catch {
|
|
1541
1565
|
}
|
|
1542
1566
|
}
|
|
@@ -1547,20 +1571,20 @@ function findLatestSessionFile(projectPath) {
|
|
|
1547
1571
|
if (!dirPath) return null;
|
|
1548
1572
|
let entries;
|
|
1549
1573
|
try {
|
|
1550
|
-
entries =
|
|
1574
|
+
entries = import_fs10.default.readdirSync(dirPath);
|
|
1551
1575
|
} catch {
|
|
1552
1576
|
return null;
|
|
1553
1577
|
}
|
|
1554
1578
|
const files = entries.filter((f) => f.endsWith(".jsonl") && !f.includes("/")).map((f) => {
|
|
1555
1579
|
try {
|
|
1556
|
-
return { name: f, mtime:
|
|
1580
|
+
return { name: f, mtime: import_fs10.default.statSync(import_path10.default.join(dirPath, f)).mtimeMs };
|
|
1557
1581
|
} catch {
|
|
1558
1582
|
return null;
|
|
1559
1583
|
}
|
|
1560
1584
|
}).filter((f) => f !== null).sort((a, b) => b.mtime - a.mtime);
|
|
1561
1585
|
if (files.length === 0) return null;
|
|
1562
1586
|
return {
|
|
1563
|
-
filePath:
|
|
1587
|
+
filePath: import_path10.default.join(dirPath, files[0].name),
|
|
1564
1588
|
sessionId: files[0].name.replace(".jsonl", "")
|
|
1565
1589
|
};
|
|
1566
1590
|
}
|
|
@@ -1570,8 +1594,8 @@ async function readConversation(projectPath, afterLine = 0, specificSessionId) {
|
|
|
1570
1594
|
if (specificSessionId) {
|
|
1571
1595
|
sessionId = specificSessionId;
|
|
1572
1596
|
const dirPath = findProjectDir(projectPath);
|
|
1573
|
-
const direct = dirPath ?
|
|
1574
|
-
if (direct &&
|
|
1597
|
+
const direct = dirPath ? import_path10.default.join(dirPath, `${specificSessionId}.jsonl`) : null;
|
|
1598
|
+
if (direct && import_fs10.default.existsSync(direct)) {
|
|
1575
1599
|
filePath = direct;
|
|
1576
1600
|
} else {
|
|
1577
1601
|
const byId = findSessionFileById(specificSessionId);
|
|
@@ -1585,7 +1609,7 @@ async function readConversation(projectPath, afterLine = 0, specificSessionId) {
|
|
|
1585
1609
|
sessionId = found.sessionId;
|
|
1586
1610
|
}
|
|
1587
1611
|
try {
|
|
1588
|
-
const stream =
|
|
1612
|
+
const stream = import_fs10.default.createReadStream(filePath, { encoding: "utf-8" });
|
|
1589
1613
|
const rl = import_readline3.default.createInterface({ input: stream, crlfDelay: Infinity });
|
|
1590
1614
|
const messages = [];
|
|
1591
1615
|
let lineNum = 0;
|
|
@@ -1666,17 +1690,17 @@ async function readConversation(projectPath, afterLine = 0, specificSessionId) {
|
|
|
1666
1690
|
return null;
|
|
1667
1691
|
}
|
|
1668
1692
|
}
|
|
1669
|
-
var
|
|
1693
|
+
var import_fs10, import_path10, import_os8, import_readline3, CLAUDE_PROJECTS_DIR2;
|
|
1670
1694
|
var init_claude_conversation = __esm({
|
|
1671
1695
|
"src/claude-conversation.ts"() {
|
|
1672
1696
|
"use strict";
|
|
1673
|
-
|
|
1674
|
-
|
|
1697
|
+
import_fs10 = __toESM(require("fs"));
|
|
1698
|
+
import_path10 = __toESM(require("path"));
|
|
1675
1699
|
import_os8 = __toESM(require("os"));
|
|
1676
1700
|
import_readline3 = __toESM(require("readline"));
|
|
1677
1701
|
init_logger();
|
|
1678
1702
|
init_claude_path();
|
|
1679
|
-
CLAUDE_PROJECTS_DIR2 =
|
|
1703
|
+
CLAUDE_PROJECTS_DIR2 = import_path10.default.join(import_os8.default.homedir(), ".claude", "projects");
|
|
1680
1704
|
}
|
|
1681
1705
|
});
|
|
1682
1706
|
|
|
@@ -1693,7 +1717,6 @@ var init_index = __esm({
|
|
|
1693
1717
|
init_claude_plugin_installer();
|
|
1694
1718
|
init_local_control();
|
|
1695
1719
|
init_tmux();
|
|
1696
|
-
init_shell();
|
|
1697
1720
|
init_heartbeat();
|
|
1698
1721
|
init_file_explorer();
|
|
1699
1722
|
init_vpn_manager();
|
|
@@ -1765,7 +1788,18 @@ var init_index = __esm({
|
|
|
1765
1788
|
socket.on(TERMINAL_OPEN, (payload) => {
|
|
1766
1789
|
const { sessionId, cols, rows, tmux, launch } = payload;
|
|
1767
1790
|
if (!sessionId) return;
|
|
1768
|
-
|
|
1791
|
+
let launchSpec;
|
|
1792
|
+
if (tmux) {
|
|
1793
|
+
const spec = buildTmuxLaunch(tmux, launch);
|
|
1794
|
+
if (!spec) {
|
|
1795
|
+
const msg = "\r\n\x1B[31mtmux is not installed on this machine.\x1B[0m\r\nInstall it to use tmux mirroring:\r\n macOS: brew install tmux\r\n Linux: sudo apt install tmux (or your package manager)\r\n\r\n";
|
|
1796
|
+
socket.emit(TERMINAL_OUTPUT, { sessionId, data: msg });
|
|
1797
|
+
socket.emit(TERMINAL_EXIT, { sessionId, exitCode: 1 });
|
|
1798
|
+
logger.warn({ sessionId, tmux }, "tmux launch requested but tmux not found");
|
|
1799
|
+
return;
|
|
1800
|
+
}
|
|
1801
|
+
launchSpec = spec;
|
|
1802
|
+
}
|
|
1769
1803
|
createTerminalSession(
|
|
1770
1804
|
sessionId,
|
|
1771
1805
|
cols,
|