cli-remote-agent 1.0.5 → 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/cli.js +190 -109
- package/dist/cli.js.map +1 -1
- package/dist/index.js +183 -106
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -427,6 +427,51 @@ var init_local_control = __esm({
|
|
|
427
427
|
}
|
|
428
428
|
});
|
|
429
429
|
|
|
430
|
+
// src/pty-helper-fix.ts
|
|
431
|
+
function ensurePtyHelperExecutable() {
|
|
432
|
+
if (process.platform === "win32") return;
|
|
433
|
+
try {
|
|
434
|
+
const nodeRequire = (0, import_node_module.createRequire)(__filename);
|
|
435
|
+
const ptyMain = nodeRequire.resolve("node-pty");
|
|
436
|
+
const ptyDir = import_path3.default.dirname(import_path3.default.dirname(ptyMain));
|
|
437
|
+
const candidates = [import_path3.default.join(ptyDir, "build", "Release", "spawn-helper")];
|
|
438
|
+
const prebuilds = import_path3.default.join(ptyDir, "prebuilds");
|
|
439
|
+
try {
|
|
440
|
+
for (const d of import_fs4.default.readdirSync(prebuilds)) {
|
|
441
|
+
candidates.push(import_path3.default.join(prebuilds, d, "spawn-helper"));
|
|
442
|
+
}
|
|
443
|
+
} catch {
|
|
444
|
+
}
|
|
445
|
+
for (const file of candidates) {
|
|
446
|
+
try {
|
|
447
|
+
const mode = import_fs4.default.statSync(file).mode;
|
|
448
|
+
if (!(mode & 73)) {
|
|
449
|
+
import_fs4.default.chmodSync(file, mode | 493);
|
|
450
|
+
logger.info({ file }, "Restored execute bit on node-pty spawn-helper");
|
|
451
|
+
}
|
|
452
|
+
} catch {
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
if (process.platform === "darwin") {
|
|
456
|
+
(0, import_node_child_process.execFile)("xattr", ["-dr", "com.apple.quarantine", ptyDir], () => {
|
|
457
|
+
});
|
|
458
|
+
}
|
|
459
|
+
} catch (err) {
|
|
460
|
+
logger.warn({ error: err?.message }, "Could not verify node-pty spawn-helper permissions");
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
var import_node_module, import_node_child_process, import_fs4, import_path3;
|
|
464
|
+
var init_pty_helper_fix = __esm({
|
|
465
|
+
"src/pty-helper-fix.ts"() {
|
|
466
|
+
"use strict";
|
|
467
|
+
import_node_module = require("module");
|
|
468
|
+
import_node_child_process = require("child_process");
|
|
469
|
+
import_fs4 = __toESM(require("fs"));
|
|
470
|
+
import_path3 = __toESM(require("path"));
|
|
471
|
+
init_logger();
|
|
472
|
+
}
|
|
473
|
+
});
|
|
474
|
+
|
|
430
475
|
// src/claude-live.ts
|
|
431
476
|
function isAlive(pid) {
|
|
432
477
|
try {
|
|
@@ -439,14 +484,14 @@ function isAlive(pid) {
|
|
|
439
484
|
function getLiveClaudeSessions() {
|
|
440
485
|
let files;
|
|
441
486
|
try {
|
|
442
|
-
files =
|
|
487
|
+
files = import_fs5.default.readdirSync(LIVE_SESSIONS_DIR).filter((f) => f.endsWith(".json"));
|
|
443
488
|
} catch {
|
|
444
489
|
return [];
|
|
445
490
|
}
|
|
446
491
|
const out = [];
|
|
447
492
|
for (const f of files) {
|
|
448
493
|
try {
|
|
449
|
-
const obj = JSON.parse(
|
|
494
|
+
const obj = JSON.parse(import_fs5.default.readFileSync(import_path4.default.join(LIVE_SESSIONS_DIR, f), "utf-8"));
|
|
450
495
|
if (typeof obj?.pid !== "number" || !isAlive(obj.pid)) continue;
|
|
451
496
|
out.push({
|
|
452
497
|
pid: obj.pid,
|
|
@@ -481,23 +526,42 @@ function isDescendantOf(pid, ancestor, parents) {
|
|
|
481
526
|
}
|
|
482
527
|
return false;
|
|
483
528
|
}
|
|
484
|
-
var
|
|
529
|
+
var import_fs5, import_path4, import_os2, import_child_process, import_util, execFileAsync, LIVE_SESSIONS_DIR;
|
|
485
530
|
var init_claude_live = __esm({
|
|
486
531
|
"src/claude-live.ts"() {
|
|
487
532
|
"use strict";
|
|
488
|
-
|
|
489
|
-
|
|
533
|
+
import_fs5 = __toESM(require("fs"));
|
|
534
|
+
import_path4 = __toESM(require("path"));
|
|
490
535
|
import_os2 = __toESM(require("os"));
|
|
491
536
|
import_child_process = require("child_process");
|
|
492
537
|
import_util = require("util");
|
|
493
538
|
execFileAsync = (0, import_util.promisify)(import_child_process.execFile);
|
|
494
|
-
LIVE_SESSIONS_DIR =
|
|
539
|
+
LIVE_SESSIONS_DIR = import_path4.default.join(import_os2.default.homedir(), ".claude", "sessions");
|
|
495
540
|
}
|
|
496
541
|
});
|
|
497
542
|
|
|
498
543
|
// src/tmux.ts
|
|
544
|
+
function resolveTmuxPath() {
|
|
545
|
+
if (cachedTmuxPath !== void 0) return cachedTmuxPath;
|
|
546
|
+
const dirs = (process.env.PATH || "").split(import_path5.default.delimiter).filter(Boolean);
|
|
547
|
+
for (const extra of ["/opt/homebrew/bin", "/usr/local/bin", "/usr/bin", "/bin", "/opt/local/bin"]) {
|
|
548
|
+
if (!dirs.includes(extra)) dirs.push(extra);
|
|
549
|
+
}
|
|
550
|
+
for (const dir of dirs) {
|
|
551
|
+
const candidate = import_path5.default.join(dir, "tmux");
|
|
552
|
+
try {
|
|
553
|
+
import_fs6.default.accessSync(candidate, import_fs6.default.constants.X_OK);
|
|
554
|
+
cachedTmuxPath = candidate;
|
|
555
|
+
return candidate;
|
|
556
|
+
} catch {
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
cachedTmuxPath = null;
|
|
560
|
+
return null;
|
|
561
|
+
}
|
|
499
562
|
function tmuxCmd(args) {
|
|
500
|
-
|
|
563
|
+
if (IS_WIN) return { file: "wsl.exe", args: ["tmux", ...args] };
|
|
564
|
+
return { file: resolveTmuxPath() || "tmux", args };
|
|
501
565
|
}
|
|
502
566
|
async function listTmuxSessions() {
|
|
503
567
|
const fmt = "#{session_name} #{session_windows} #{session_attached} #{session_activity}";
|
|
@@ -536,8 +600,8 @@ async function enrichWithPanesAndClaude(sessions2) {
|
|
|
536
600
|
const { file, args } = tmuxCmd(["list-panes", "-a", "-F", paneFmt]);
|
|
537
601
|
const { stdout } = await execFileAsync2(file, args, { timeout: 6e3 });
|
|
538
602
|
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:
|
|
603
|
+
const [session, pid, path10, activeFlags] = line.split(" ");
|
|
604
|
+
return { session, pid: parseInt(pid, 10) || 0, path: path10 || "", active: activeFlags === "11" };
|
|
541
605
|
});
|
|
542
606
|
const byName = new Map(sessions2.map((s) => [s.name, s]));
|
|
543
607
|
for (const pane of panes) {
|
|
@@ -559,26 +623,31 @@ async function enrichWithPanesAndClaude(sessions2) {
|
|
|
559
623
|
} catch {
|
|
560
624
|
}
|
|
561
625
|
}
|
|
562
|
-
function
|
|
563
|
-
return `'${v.replace(/'/g, `'\\''`)}'`;
|
|
564
|
-
}
|
|
565
|
-
function buildTmuxLaunch(name, launch, shell) {
|
|
626
|
+
function buildTmuxLaunch(name, launch) {
|
|
566
627
|
const trimmed = launch && launch.trim() ? launch.trim() : void 0;
|
|
567
628
|
if (IS_WIN) {
|
|
568
|
-
const
|
|
569
|
-
if (trimmed)
|
|
570
|
-
return { file: "wsl.exe", args };
|
|
571
|
-
}
|
|
572
|
-
|
|
573
|
-
if (
|
|
574
|
-
|
|
629
|
+
const args2 = ["tmux", "new-session", "-A", "-s", name];
|
|
630
|
+
if (trimmed) args2.push(trimmed);
|
|
631
|
+
return { file: "wsl.exe", args: args2 };
|
|
632
|
+
}
|
|
633
|
+
const tmuxBin = resolveTmuxPath();
|
|
634
|
+
if (!tmuxBin) return null;
|
|
635
|
+
execFileAsync2(tmuxBin, ["set-option", "-g", "aggressive-resize", "on"], { timeout: 4e3 }).catch(
|
|
636
|
+
() => {
|
|
637
|
+
}
|
|
638
|
+
);
|
|
639
|
+
const args = ["new-session", "-A", "-s", name];
|
|
640
|
+
if (trimmed) args.push(trimmed);
|
|
641
|
+
return { file: tmuxBin, args };
|
|
575
642
|
}
|
|
576
|
-
var import_child_process2, import_util2, execFileAsync2, IS_WIN;
|
|
643
|
+
var import_child_process2, import_util2, import_fs6, import_path5, execFileAsync2, IS_WIN, cachedTmuxPath;
|
|
577
644
|
var init_tmux = __esm({
|
|
578
645
|
"src/tmux.ts"() {
|
|
579
646
|
"use strict";
|
|
580
647
|
import_child_process2 = require("child_process");
|
|
581
648
|
import_util2 = require("util");
|
|
649
|
+
import_fs6 = __toESM(require("fs"));
|
|
650
|
+
import_path5 = __toESM(require("path"));
|
|
582
651
|
init_claude_live();
|
|
583
652
|
execFileAsync2 = (0, import_util2.promisify)(import_child_process2.execFile);
|
|
584
653
|
IS_WIN = process.platform === "win32";
|
|
@@ -608,15 +677,15 @@ var init_shell = __esm({
|
|
|
608
677
|
|
|
609
678
|
// src/pty-session.ts
|
|
610
679
|
function ensureInitFiles() {
|
|
611
|
-
const versionFile = (0,
|
|
612
|
-
if ((0,
|
|
680
|
+
const versionFile = (0, import_path6.join)(INIT_DIR, ".version");
|
|
681
|
+
if ((0, import_fs7.existsSync)(versionFile)) {
|
|
613
682
|
try {
|
|
614
|
-
if ((0,
|
|
683
|
+
if ((0, import_fs7.readFileSync)(versionFile, "utf-8").trim() === INIT_VERSION) return;
|
|
615
684
|
} catch {
|
|
616
685
|
}
|
|
617
686
|
}
|
|
618
|
-
(0,
|
|
619
|
-
(0,
|
|
687
|
+
(0, import_fs7.mkdirSync)(ZSH_DIR, { recursive: true });
|
|
688
|
+
(0, import_fs7.writeFileSync)(BASH_INIT, [
|
|
620
689
|
"[ -f ~/.bash_profile ] && source ~/.bash_profile",
|
|
621
690
|
"[ -f ~/.bashrc ] && source ~/.bashrc",
|
|
622
691
|
"__crc_s=$SECONDS",
|
|
@@ -627,11 +696,11 @@ function ensureInitFiles() {
|
|
|
627
696
|
`PROMPT_COMMAND='[ "$__crc_armed" = 1 ] && [ \${__crc_elapsed:-0} -ge ${THRESHOLD} ] && printf "\\a"; __crc_armed=1; eval "$__crc_orig_pc"'`,
|
|
628
697
|
""
|
|
629
698
|
].join("\n"), "utf-8");
|
|
630
|
-
(0,
|
|
699
|
+
(0, import_fs7.writeFileSync)(ZSH_ENV, [
|
|
631
700
|
'[ -f "${ZDOTDIR_ORIG:-$HOME}/.zshenv" ] && source "${ZDOTDIR_ORIG:-$HOME}/.zshenv"',
|
|
632
701
|
""
|
|
633
702
|
].join("\n"), "utf-8");
|
|
634
|
-
(0,
|
|
703
|
+
(0, import_fs7.writeFileSync)(ZSH_RC, [
|
|
635
704
|
'[ -f "${ZDOTDIR_ORIG:-$HOME}/.zshrc" ] && source "${ZDOTDIR_ORIG:-$HOME}/.zshrc"',
|
|
636
705
|
"__crc_s=$SECONDS",
|
|
637
706
|
"__crc_armed=0",
|
|
@@ -644,36 +713,36 @@ function ensureInitFiles() {
|
|
|
644
713
|
"fi",
|
|
645
714
|
""
|
|
646
715
|
].join("\n"), "utf-8");
|
|
647
|
-
(0,
|
|
716
|
+
(0, import_fs7.writeFileSync)(versionFile, INIT_VERSION, "utf-8");
|
|
648
717
|
}
|
|
649
718
|
function resolveCwd(cwd) {
|
|
650
719
|
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
720
|
for (const c of candidates) {
|
|
652
721
|
if (c) {
|
|
653
722
|
try {
|
|
654
|
-
if ((0,
|
|
723
|
+
if ((0, import_fs7.existsSync)(c)) return c;
|
|
655
724
|
} catch {
|
|
656
725
|
}
|
|
657
726
|
}
|
|
658
727
|
}
|
|
659
728
|
return (0, import_os3.homedir)();
|
|
660
729
|
}
|
|
661
|
-
var pty,
|
|
730
|
+
var pty, import_fs7, import_path6, import_os3, THRESHOLD, INIT_DIR, BASH_INIT, ZSH_DIR, ZSH_RC, ZSH_ENV, INIT_VERSION, PtySession;
|
|
662
731
|
var init_pty_session = __esm({
|
|
663
732
|
"src/pty-session.ts"() {
|
|
664
733
|
"use strict";
|
|
665
734
|
pty = __toESM(require("node-pty"));
|
|
666
|
-
|
|
667
|
-
|
|
735
|
+
import_fs7 = require("fs");
|
|
736
|
+
import_path6 = require("path");
|
|
668
737
|
import_os3 = require("os");
|
|
669
738
|
init_src();
|
|
670
739
|
init_shell();
|
|
671
740
|
THRESHOLD = 3;
|
|
672
|
-
INIT_DIR = (0,
|
|
673
|
-
BASH_INIT = (0,
|
|
674
|
-
ZSH_DIR = (0,
|
|
675
|
-
ZSH_RC = (0,
|
|
676
|
-
ZSH_ENV = (0,
|
|
741
|
+
INIT_DIR = (0, import_path6.join)((0, import_os3.tmpdir)(), "crc-shell-init");
|
|
742
|
+
BASH_INIT = (0, import_path6.join)(INIT_DIR, "bashrc");
|
|
743
|
+
ZSH_DIR = (0, import_path6.join)(INIT_DIR, "zsh");
|
|
744
|
+
ZSH_RC = (0, import_path6.join)(ZSH_DIR, ".zshrc");
|
|
745
|
+
ZSH_ENV = (0, import_path6.join)(ZSH_DIR, ".zshenv");
|
|
677
746
|
INIT_VERSION = "2";
|
|
678
747
|
PtySession = class {
|
|
679
748
|
id;
|
|
@@ -903,18 +972,18 @@ function buildHeartbeat(homeDir) {
|
|
|
903
972
|
memoryUsage: Math.round((totalMem - freeMem) / totalMem * 100),
|
|
904
973
|
uptime: Math.round(import_os4.default.uptime()),
|
|
905
974
|
activeSessions: getActiveSessionCount(),
|
|
906
|
-
pathSeparator:
|
|
975
|
+
pathSeparator: import_path7.default.sep,
|
|
907
976
|
homeDirectory: homeDir || import_os4.default.homedir(),
|
|
908
977
|
rootPaths: getRootPaths(),
|
|
909
978
|
capabilities: { terminal: true, fileTransfer: false }
|
|
910
979
|
};
|
|
911
980
|
}
|
|
912
|
-
var import_os4,
|
|
981
|
+
var import_os4, import_path7, import_child_process4, prevCpu;
|
|
913
982
|
var init_heartbeat = __esm({
|
|
914
983
|
"src/heartbeat.ts"() {
|
|
915
984
|
"use strict";
|
|
916
985
|
import_os4 = __toESM(require("os"));
|
|
917
|
-
|
|
986
|
+
import_path7 = __toESM(require("path"));
|
|
918
987
|
import_child_process4 = require("child_process");
|
|
919
988
|
init_terminal_manager();
|
|
920
989
|
prevCpu = null;
|
|
@@ -923,28 +992,28 @@ var init_heartbeat = __esm({
|
|
|
923
992
|
|
|
924
993
|
// src/file-explorer.ts
|
|
925
994
|
function isInSecretDir(resolved) {
|
|
926
|
-
const rel =
|
|
927
|
-
return rel === "" || !rel.startsWith(".." +
|
|
995
|
+
const rel = import_path8.default.relative(SECRET_DIR, resolved);
|
|
996
|
+
return rel === "" || !rel.startsWith(".." + import_path8.default.sep) && rel !== ".." && !import_path8.default.isAbsolute(rel);
|
|
928
997
|
}
|
|
929
998
|
function listDirectory(dirPath) {
|
|
930
999
|
try {
|
|
931
|
-
const resolved =
|
|
1000
|
+
const resolved = import_path8.default.resolve(dirPath);
|
|
932
1001
|
if (isInSecretDir(resolved)) {
|
|
933
1002
|
return { entries: [], error: "Access denied" };
|
|
934
1003
|
}
|
|
935
|
-
if (!
|
|
1004
|
+
if (!import_fs8.default.existsSync(resolved)) {
|
|
936
1005
|
return { entries: [], error: "Path does not exist" };
|
|
937
1006
|
}
|
|
938
|
-
const stat =
|
|
1007
|
+
const stat = import_fs8.default.statSync(resolved);
|
|
939
1008
|
if (!stat.isDirectory()) {
|
|
940
1009
|
return { entries: [], error: "Not a directory" };
|
|
941
1010
|
}
|
|
942
|
-
const dirents =
|
|
1011
|
+
const dirents = import_fs8.default.readdirSync(resolved, { withFileTypes: true });
|
|
943
1012
|
const entries = [];
|
|
944
1013
|
for (const dirent of dirents) {
|
|
945
1014
|
try {
|
|
946
|
-
const fullPath =
|
|
947
|
-
const s =
|
|
1015
|
+
const fullPath = import_path8.default.join(resolved, dirent.name);
|
|
1016
|
+
const s = import_fs8.default.statSync(fullPath);
|
|
948
1017
|
entries.push({
|
|
949
1018
|
name: dirent.name,
|
|
950
1019
|
isDirectory: dirent.isDirectory(),
|
|
@@ -966,22 +1035,22 @@ function listDirectory(dirPath) {
|
|
|
966
1035
|
}
|
|
967
1036
|
async function downloadFile(filePath, serverUrl, secret, agentId) {
|
|
968
1037
|
try {
|
|
969
|
-
const resolved =
|
|
1038
|
+
const resolved = import_path8.default.resolve(filePath);
|
|
970
1039
|
if (isInSecretDir(resolved)) {
|
|
971
1040
|
return { error: "Access denied" };
|
|
972
1041
|
}
|
|
973
|
-
if (!
|
|
1042
|
+
if (!import_fs8.default.existsSync(resolved)) {
|
|
974
1043
|
return { error: "File does not exist" };
|
|
975
1044
|
}
|
|
976
|
-
const stat =
|
|
1045
|
+
const stat = import_fs8.default.statSync(resolved);
|
|
977
1046
|
if (stat.isDirectory()) {
|
|
978
1047
|
return { error: "Cannot download a directory" };
|
|
979
1048
|
}
|
|
980
1049
|
if (stat.size > FILE_MAX_SIZE) {
|
|
981
1050
|
return { error: `File too large (max ${FILE_MAX_SIZE} bytes)` };
|
|
982
1051
|
}
|
|
983
|
-
const fileName =
|
|
984
|
-
const fileStream =
|
|
1052
|
+
const fileName = import_path8.default.basename(resolved);
|
|
1053
|
+
const fileStream = import_fs8.default.createReadStream(resolved);
|
|
985
1054
|
const baseUrl = serverUrl.replace("wss://", "https://").replace("ws://", "http://");
|
|
986
1055
|
const url = `${baseUrl}/api/files/receive`;
|
|
987
1056
|
const res = await fetch(url, {
|
|
@@ -1010,21 +1079,21 @@ async function downloadFile(filePath, serverUrl, secret, agentId) {
|
|
|
1010
1079
|
return { error: err.message };
|
|
1011
1080
|
}
|
|
1012
1081
|
}
|
|
1013
|
-
var
|
|
1082
|
+
var import_fs8, import_path8, import_os5, SECRET_DIR;
|
|
1014
1083
|
var init_file_explorer = __esm({
|
|
1015
1084
|
"src/file-explorer.ts"() {
|
|
1016
1085
|
"use strict";
|
|
1017
|
-
|
|
1018
|
-
|
|
1086
|
+
import_fs8 = __toESM(require("fs"));
|
|
1087
|
+
import_path8 = __toESM(require("path"));
|
|
1019
1088
|
import_os5 = __toESM(require("os"));
|
|
1020
1089
|
init_logger();
|
|
1021
1090
|
init_src();
|
|
1022
|
-
SECRET_DIR =
|
|
1091
|
+
SECRET_DIR = import_path8.default.join(import_os5.default.homedir(), ".crc-agent");
|
|
1023
1092
|
}
|
|
1024
1093
|
});
|
|
1025
1094
|
|
|
1026
1095
|
// src/vpn-manager.ts
|
|
1027
|
-
function
|
|
1096
|
+
function shq(value) {
|
|
1028
1097
|
return value.replace(/'/g, "'\\''");
|
|
1029
1098
|
}
|
|
1030
1099
|
function psq(value) {
|
|
@@ -1042,11 +1111,11 @@ async function runCmd(cmd2, shell) {
|
|
|
1042
1111
|
}
|
|
1043
1112
|
function getConfigPath(profile) {
|
|
1044
1113
|
const file = profile.configFile || `${profile.id}.conf`;
|
|
1045
|
-
if (
|
|
1046
|
-
return
|
|
1114
|
+
if (import_path9.default.isAbsolute(file)) return file;
|
|
1115
|
+
return import_path9.default.join(VPN_DIR, file);
|
|
1047
1116
|
}
|
|
1048
1117
|
async function getScutilStatus(serviceName) {
|
|
1049
|
-
const { stdout } = await runCmd(`scutil --nc status '${
|
|
1118
|
+
const { stdout } = await runCmd(`scutil --nc status '${shq(serviceName)}'`);
|
|
1050
1119
|
const firstLine = stdout.trim().split("\n")[0];
|
|
1051
1120
|
if (firstLine === "Connected") return "connected";
|
|
1052
1121
|
if (firstLine === "Connecting") return "connecting";
|
|
@@ -1054,11 +1123,11 @@ async function getScutilStatus(serviceName) {
|
|
|
1054
1123
|
return "disconnected";
|
|
1055
1124
|
}
|
|
1056
1125
|
async function scutilStart(serviceName) {
|
|
1057
|
-
const { stderr } = await runCmd(`scutil --nc start '${
|
|
1126
|
+
const { stderr } = await runCmd(`scutil --nc start '${shq(serviceName)}'`);
|
|
1058
1127
|
return stderr || null;
|
|
1059
1128
|
}
|
|
1060
1129
|
async function scutilStop(serviceName) {
|
|
1061
|
-
const { stderr } = await runCmd(`scutil --nc stop '${
|
|
1130
|
+
const { stderr } = await runCmd(`scutil --nc stop '${shq(serviceName)}'`);
|
|
1062
1131
|
return stderr || null;
|
|
1063
1132
|
}
|
|
1064
1133
|
async function runOsascript(script) {
|
|
@@ -1107,7 +1176,7 @@ async function getWireGuardStatus(profile) {
|
|
|
1107
1176
|
return getScutilStatus(profile.serviceName);
|
|
1108
1177
|
}
|
|
1109
1178
|
const tunnelName = profile.tunnelName || profile.id;
|
|
1110
|
-
const { stdout } = await runCmd(`wg show '${
|
|
1179
|
+
const { stdout } = await runCmd(`wg show '${shq(tunnelName)}' 2>/dev/null`);
|
|
1111
1180
|
return stdout.trim() ? "connected" : "disconnected";
|
|
1112
1181
|
}
|
|
1113
1182
|
async function getOpenVpnStatus(profile) {
|
|
@@ -1159,7 +1228,7 @@ async function connectWireGuard(profile) {
|
|
|
1159
1228
|
const tunnelName = profile.tunnelName || profile.id;
|
|
1160
1229
|
if (isWindows) {
|
|
1161
1230
|
const confPath2 = getConfigPath(profile);
|
|
1162
|
-
if (!
|
|
1231
|
+
if (!import_fs9.default.existsSync(confPath2)) {
|
|
1163
1232
|
return `Config file not found: ${confPath2}`;
|
|
1164
1233
|
}
|
|
1165
1234
|
const script = `
|
|
@@ -1179,13 +1248,13 @@ async function connectWireGuard(profile) {
|
|
|
1179
1248
|
return scutilStart(profile.serviceName);
|
|
1180
1249
|
}
|
|
1181
1250
|
const confPath = getConfigPath(profile);
|
|
1182
|
-
const { stderr } = await runCmd(`sudo wg-quick up '${
|
|
1251
|
+
const { stderr } = await runCmd(`sudo wg-quick up '${shq(confPath)}'`);
|
|
1183
1252
|
return stderr || null;
|
|
1184
1253
|
}
|
|
1185
1254
|
async function connectOpenVpn(profile) {
|
|
1186
1255
|
if (isWindows) {
|
|
1187
1256
|
const confPath2 = getConfigPath(profile);
|
|
1188
|
-
if (!
|
|
1257
|
+
if (!import_fs9.default.existsSync(confPath2)) {
|
|
1189
1258
|
return `Config file not found: ${confPath2}`;
|
|
1190
1259
|
}
|
|
1191
1260
|
const connector = "C:\\Program Files\\OpenVPN Connect\\ovpnconnector.exe";
|
|
@@ -1212,16 +1281,16 @@ async function connectOpenVpn(profile) {
|
|
|
1212
1281
|
return scutilStart(profile.serviceName);
|
|
1213
1282
|
}
|
|
1214
1283
|
const confPath = getConfigPath(profile);
|
|
1215
|
-
if (!
|
|
1284
|
+
if (!import_fs9.default.existsSync(confPath)) {
|
|
1216
1285
|
return `Config file not found: ${confPath}`;
|
|
1217
1286
|
}
|
|
1218
|
-
const { stderr } = await runCmd(`sudo openvpn --config '${
|
|
1287
|
+
const { stderr } = await runCmd(`sudo openvpn --config '${shq(confPath)}' --daemon`);
|
|
1219
1288
|
return stderr || null;
|
|
1220
1289
|
}
|
|
1221
1290
|
async function connectAzure(profile) {
|
|
1222
1291
|
if (isWindows) {
|
|
1223
1292
|
const confPath = getConfigPath(profile);
|
|
1224
|
-
if (!
|
|
1293
|
+
if (!import_fs9.default.existsSync(confPath)) {
|
|
1225
1294
|
return `Config file not found: ${confPath}`;
|
|
1226
1295
|
}
|
|
1227
1296
|
await runCmd(`& 'AzureVpn.exe' -i '${psq(confPath)}' 2>&1`);
|
|
@@ -1265,7 +1334,7 @@ async function disconnectWireGuard(profile) {
|
|
|
1265
1334
|
return scutilStop(profile.serviceName);
|
|
1266
1335
|
}
|
|
1267
1336
|
const confPath = getConfigPath(profile);
|
|
1268
|
-
const { stderr } = await runCmd(`sudo wg-quick down '${
|
|
1337
|
+
const { stderr } = await runCmd(`sudo wg-quick down '${shq(confPath)}'`);
|
|
1269
1338
|
return stderr || null;
|
|
1270
1339
|
}
|
|
1271
1340
|
async function disconnectOpenVpn(profile) {
|
|
@@ -1341,19 +1410,19 @@ async function disconnectVpn(configs, profileId) {
|
|
|
1341
1410
|
}
|
|
1342
1411
|
return profiles;
|
|
1343
1412
|
}
|
|
1344
|
-
var import_child_process5, import_util3,
|
|
1413
|
+
var import_child_process5, import_util3, import_fs9, import_path9, import_os6, execAsync, isWindows, VPN_DIR;
|
|
1345
1414
|
var init_vpn_manager = __esm({
|
|
1346
1415
|
"src/vpn-manager.ts"() {
|
|
1347
1416
|
"use strict";
|
|
1348
1417
|
import_child_process5 = require("child_process");
|
|
1349
1418
|
import_util3 = require("util");
|
|
1350
|
-
|
|
1351
|
-
|
|
1419
|
+
import_fs9 = __toESM(require("fs"));
|
|
1420
|
+
import_path9 = __toESM(require("path"));
|
|
1352
1421
|
import_os6 = __toESM(require("os"));
|
|
1353
1422
|
init_logger();
|
|
1354
1423
|
execAsync = (0, import_util3.promisify)(import_child_process5.exec);
|
|
1355
1424
|
isWindows = process.platform === "win32";
|
|
1356
|
-
VPN_DIR =
|
|
1425
|
+
VPN_DIR = import_path9.default.join(import_os6.default.homedir(), ".crc-agent", "vpn");
|
|
1357
1426
|
}
|
|
1358
1427
|
});
|
|
1359
1428
|
|
|
@@ -1388,7 +1457,7 @@ var init_claude_path = __esm({
|
|
|
1388
1457
|
// src/claude-sessions.ts
|
|
1389
1458
|
async function parseSessionFile(filePath) {
|
|
1390
1459
|
try {
|
|
1391
|
-
const stream =
|
|
1460
|
+
const stream = import_fs10.default.createReadStream(filePath, { encoding: "utf-8" });
|
|
1392
1461
|
const rl = import_readline2.default.createInterface({ input: stream, crlfDelay: Infinity });
|
|
1393
1462
|
let firstMessage = "";
|
|
1394
1463
|
let lastTimestamp = "";
|
|
@@ -1436,17 +1505,17 @@ async function parseSessionFile(filePath) {
|
|
|
1436
1505
|
}
|
|
1437
1506
|
async function listClaudeSessions(filterProjectPath) {
|
|
1438
1507
|
const sessions2 = [];
|
|
1439
|
-
if (!
|
|
1508
|
+
if (!import_fs10.default.existsSync(CLAUDE_PROJECTS_DIR)) return sessions2;
|
|
1440
1509
|
const isDirSafe = (d) => {
|
|
1441
1510
|
try {
|
|
1442
|
-
return
|
|
1511
|
+
return import_fs10.default.statSync(import_path10.default.join(CLAUDE_PROJECTS_DIR, d)).isDirectory();
|
|
1443
1512
|
} catch {
|
|
1444
1513
|
return false;
|
|
1445
1514
|
}
|
|
1446
1515
|
};
|
|
1447
1516
|
let allEntries;
|
|
1448
1517
|
try {
|
|
1449
|
-
allEntries =
|
|
1518
|
+
allEntries = import_fs10.default.readdirSync(CLAUDE_PROJECTS_DIR);
|
|
1450
1519
|
} catch {
|
|
1451
1520
|
return sessions2;
|
|
1452
1521
|
}
|
|
@@ -1459,16 +1528,16 @@ async function listClaudeSessions(filterProjectPath) {
|
|
|
1459
1528
|
projectDirs = allEntries.filter((d) => isDirSafe(d) && !d.startsWith("-private-"));
|
|
1460
1529
|
}
|
|
1461
1530
|
for (const dirName of projectDirs) {
|
|
1462
|
-
const dirPath =
|
|
1531
|
+
const dirPath = import_path10.default.join(CLAUDE_PROJECTS_DIR, dirName);
|
|
1463
1532
|
let files;
|
|
1464
1533
|
try {
|
|
1465
|
-
files =
|
|
1534
|
+
files = import_fs10.default.readdirSync(dirPath).filter((f) => f.endsWith(".jsonl"));
|
|
1466
1535
|
} catch {
|
|
1467
1536
|
continue;
|
|
1468
1537
|
}
|
|
1469
1538
|
for (const file of files) {
|
|
1470
1539
|
const sessionId = file.replace(".jsonl", "");
|
|
1471
|
-
const parsed = await parseSessionFile(
|
|
1540
|
+
const parsed = await parseSessionFile(import_path10.default.join(dirPath, file));
|
|
1472
1541
|
if (!parsed) continue;
|
|
1473
1542
|
const projectPath = parsed.cwd || dirName.replace(/^-/, "/").replace(/-/g, "/");
|
|
1474
1543
|
sessions2.push({
|
|
@@ -1486,31 +1555,31 @@ async function listClaudeSessions(filterProjectPath) {
|
|
|
1486
1555
|
sessions2.sort((a, b) => b.lastTimestamp > a.lastTimestamp ? 1 : -1);
|
|
1487
1556
|
return sessions2;
|
|
1488
1557
|
}
|
|
1489
|
-
var
|
|
1558
|
+
var import_fs10, import_path10, import_os7, import_readline2, CLAUDE_PROJECTS_DIR;
|
|
1490
1559
|
var init_claude_sessions = __esm({
|
|
1491
1560
|
"src/claude-sessions.ts"() {
|
|
1492
1561
|
"use strict";
|
|
1493
|
-
|
|
1494
|
-
|
|
1562
|
+
import_fs10 = __toESM(require("fs"));
|
|
1563
|
+
import_path10 = __toESM(require("path"));
|
|
1495
1564
|
import_os7 = __toESM(require("os"));
|
|
1496
1565
|
import_readline2 = __toESM(require("readline"));
|
|
1497
1566
|
init_logger();
|
|
1498
1567
|
init_claude_path();
|
|
1499
|
-
CLAUDE_PROJECTS_DIR =
|
|
1568
|
+
CLAUDE_PROJECTS_DIR = import_path10.default.join(import_os7.default.homedir(), ".claude", "projects");
|
|
1500
1569
|
}
|
|
1501
1570
|
});
|
|
1502
1571
|
|
|
1503
1572
|
// src/claude-conversation.ts
|
|
1504
1573
|
function findProjectDir(projectPath) {
|
|
1505
1574
|
const encoded = encodeProjectPath(projectPath);
|
|
1506
|
-
const dirPath =
|
|
1507
|
-
if (
|
|
1508
|
-
if (!
|
|
1575
|
+
const dirPath = import_path11.default.join(CLAUDE_PROJECTS_DIR2, encoded);
|
|
1576
|
+
if (import_fs11.default.existsSync(dirPath)) return dirPath;
|
|
1577
|
+
if (!import_fs11.default.existsSync(CLAUDE_PROJECTS_DIR2)) return null;
|
|
1509
1578
|
let allDirs;
|
|
1510
1579
|
try {
|
|
1511
|
-
allDirs =
|
|
1580
|
+
allDirs = import_fs11.default.readdirSync(CLAUDE_PROJECTS_DIR2).filter((d) => {
|
|
1512
1581
|
try {
|
|
1513
|
-
return
|
|
1582
|
+
return import_fs11.default.statSync(import_path11.default.join(CLAUDE_PROJECTS_DIR2, d)).isDirectory();
|
|
1514
1583
|
} catch {
|
|
1515
1584
|
return false;
|
|
1516
1585
|
}
|
|
@@ -1520,23 +1589,23 @@ function findProjectDir(projectPath) {
|
|
|
1520
1589
|
}
|
|
1521
1590
|
const matches = findProjectDirs(allDirs, projectPath);
|
|
1522
1591
|
if (matches.length > 0) {
|
|
1523
|
-
return
|
|
1592
|
+
return import_path11.default.join(CLAUDE_PROJECTS_DIR2, matches[0]);
|
|
1524
1593
|
}
|
|
1525
1594
|
return null;
|
|
1526
1595
|
}
|
|
1527
1596
|
function findSessionFileById(sessionId) {
|
|
1528
1597
|
if (!/^[A-Za-z0-9._-]+$/.test(sessionId)) return null;
|
|
1529
|
-
if (!
|
|
1598
|
+
if (!import_fs11.default.existsSync(CLAUDE_PROJECTS_DIR2)) return null;
|
|
1530
1599
|
let dirs;
|
|
1531
1600
|
try {
|
|
1532
|
-
dirs =
|
|
1601
|
+
dirs = import_fs11.default.readdirSync(CLAUDE_PROJECTS_DIR2);
|
|
1533
1602
|
} catch {
|
|
1534
1603
|
return null;
|
|
1535
1604
|
}
|
|
1536
1605
|
for (const dir of dirs) {
|
|
1537
|
-
const candidate =
|
|
1606
|
+
const candidate = import_path11.default.join(CLAUDE_PROJECTS_DIR2, dir, `${sessionId}.jsonl`);
|
|
1538
1607
|
try {
|
|
1539
|
-
if (
|
|
1608
|
+
if (import_fs11.default.statSync(candidate).isFile()) return candidate;
|
|
1540
1609
|
} catch {
|
|
1541
1610
|
}
|
|
1542
1611
|
}
|
|
@@ -1547,20 +1616,20 @@ function findLatestSessionFile(projectPath) {
|
|
|
1547
1616
|
if (!dirPath) return null;
|
|
1548
1617
|
let entries;
|
|
1549
1618
|
try {
|
|
1550
|
-
entries =
|
|
1619
|
+
entries = import_fs11.default.readdirSync(dirPath);
|
|
1551
1620
|
} catch {
|
|
1552
1621
|
return null;
|
|
1553
1622
|
}
|
|
1554
1623
|
const files = entries.filter((f) => f.endsWith(".jsonl") && !f.includes("/")).map((f) => {
|
|
1555
1624
|
try {
|
|
1556
|
-
return { name: f, mtime:
|
|
1625
|
+
return { name: f, mtime: import_fs11.default.statSync(import_path11.default.join(dirPath, f)).mtimeMs };
|
|
1557
1626
|
} catch {
|
|
1558
1627
|
return null;
|
|
1559
1628
|
}
|
|
1560
1629
|
}).filter((f) => f !== null).sort((a, b) => b.mtime - a.mtime);
|
|
1561
1630
|
if (files.length === 0) return null;
|
|
1562
1631
|
return {
|
|
1563
|
-
filePath:
|
|
1632
|
+
filePath: import_path11.default.join(dirPath, files[0].name),
|
|
1564
1633
|
sessionId: files[0].name.replace(".jsonl", "")
|
|
1565
1634
|
};
|
|
1566
1635
|
}
|
|
@@ -1570,8 +1639,8 @@ async function readConversation(projectPath, afterLine = 0, specificSessionId) {
|
|
|
1570
1639
|
if (specificSessionId) {
|
|
1571
1640
|
sessionId = specificSessionId;
|
|
1572
1641
|
const dirPath = findProjectDir(projectPath);
|
|
1573
|
-
const direct = dirPath ?
|
|
1574
|
-
if (direct &&
|
|
1642
|
+
const direct = dirPath ? import_path11.default.join(dirPath, `${specificSessionId}.jsonl`) : null;
|
|
1643
|
+
if (direct && import_fs11.default.existsSync(direct)) {
|
|
1575
1644
|
filePath = direct;
|
|
1576
1645
|
} else {
|
|
1577
1646
|
const byId = findSessionFileById(specificSessionId);
|
|
@@ -1585,7 +1654,7 @@ async function readConversation(projectPath, afterLine = 0, specificSessionId) {
|
|
|
1585
1654
|
sessionId = found.sessionId;
|
|
1586
1655
|
}
|
|
1587
1656
|
try {
|
|
1588
|
-
const stream =
|
|
1657
|
+
const stream = import_fs11.default.createReadStream(filePath, { encoding: "utf-8" });
|
|
1589
1658
|
const rl = import_readline3.default.createInterface({ input: stream, crlfDelay: Infinity });
|
|
1590
1659
|
const messages = [];
|
|
1591
1660
|
let lineNum = 0;
|
|
@@ -1666,17 +1735,17 @@ async function readConversation(projectPath, afterLine = 0, specificSessionId) {
|
|
|
1666
1735
|
return null;
|
|
1667
1736
|
}
|
|
1668
1737
|
}
|
|
1669
|
-
var
|
|
1738
|
+
var import_fs11, import_path11, import_os8, import_readline3, CLAUDE_PROJECTS_DIR2;
|
|
1670
1739
|
var init_claude_conversation = __esm({
|
|
1671
1740
|
"src/claude-conversation.ts"() {
|
|
1672
1741
|
"use strict";
|
|
1673
|
-
|
|
1674
|
-
|
|
1742
|
+
import_fs11 = __toESM(require("fs"));
|
|
1743
|
+
import_path11 = __toESM(require("path"));
|
|
1675
1744
|
import_os8 = __toESM(require("os"));
|
|
1676
1745
|
import_readline3 = __toESM(require("readline"));
|
|
1677
1746
|
init_logger();
|
|
1678
1747
|
init_claude_path();
|
|
1679
|
-
CLAUDE_PROJECTS_DIR2 =
|
|
1748
|
+
CLAUDE_PROJECTS_DIR2 = import_path11.default.join(import_os8.default.homedir(), ".claude", "projects");
|
|
1680
1749
|
}
|
|
1681
1750
|
});
|
|
1682
1751
|
|
|
@@ -1692,8 +1761,8 @@ var init_index = __esm({
|
|
|
1692
1761
|
init_logger();
|
|
1693
1762
|
init_claude_plugin_installer();
|
|
1694
1763
|
init_local_control();
|
|
1764
|
+
init_pty_helper_fix();
|
|
1695
1765
|
init_tmux();
|
|
1696
|
-
init_shell();
|
|
1697
1766
|
init_heartbeat();
|
|
1698
1767
|
init_file_explorer();
|
|
1699
1768
|
init_vpn_manager();
|
|
@@ -1706,6 +1775,7 @@ var init_index = __esm({
|
|
|
1706
1775
|
}
|
|
1707
1776
|
config = loadConfig();
|
|
1708
1777
|
logger.info({ agentId: config.agentId, serverUrl: config.serverUrl }, "Starting agent");
|
|
1778
|
+
ensurePtyHelperExecutable();
|
|
1709
1779
|
process.on("unhandledRejection", (reason) => {
|
|
1710
1780
|
logger.error({ reason }, "Unhandled promise rejection (agent kept alive)");
|
|
1711
1781
|
});
|
|
@@ -1765,7 +1835,18 @@ var init_index = __esm({
|
|
|
1765
1835
|
socket.on(TERMINAL_OPEN, (payload) => {
|
|
1766
1836
|
const { sessionId, cols, rows, tmux, launch } = payload;
|
|
1767
1837
|
if (!sessionId) return;
|
|
1768
|
-
|
|
1838
|
+
let launchSpec;
|
|
1839
|
+
if (tmux) {
|
|
1840
|
+
const spec = buildTmuxLaunch(tmux, launch);
|
|
1841
|
+
if (!spec) {
|
|
1842
|
+
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";
|
|
1843
|
+
socket.emit(TERMINAL_OUTPUT, { sessionId, data: msg });
|
|
1844
|
+
socket.emit(TERMINAL_EXIT, { sessionId, exitCode: 1 });
|
|
1845
|
+
logger.warn({ sessionId, tmux }, "tmux launch requested but tmux not found");
|
|
1846
|
+
return;
|
|
1847
|
+
}
|
|
1848
|
+
launchSpec = spec;
|
|
1849
|
+
}
|
|
1769
1850
|
createTerminalSession(
|
|
1770
1851
|
sessionId,
|
|
1771
1852
|
cols,
|