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 +211 -110
- package/dist/cli.js.map +1 -1
- package/dist/index.js +195 -99
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
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
|
|
426
|
-
|
|
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
|
|
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
|
-
|
|
458
|
-
|
|
459
|
-
|
|
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,
|
|
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
|
|
578
|
+
var import_child_process3;
|
|
478
579
|
var init_shell = __esm({
|
|
479
580
|
"src/shell.ts"() {
|
|
480
581
|
"use strict";
|
|
481
|
-
|
|
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,
|
|
488
|
-
if ((0,
|
|
588
|
+
const versionFile = (0, import_path4.join)(INIT_DIR, ".version");
|
|
589
|
+
if ((0, import_fs5.existsSync)(versionFile)) {
|
|
489
590
|
try {
|
|
490
|
-
if ((0,
|
|
591
|
+
if ((0, import_fs5.readFileSync)(versionFile, "utf-8").trim() === INIT_VERSION) return;
|
|
491
592
|
} catch {
|
|
492
593
|
}
|
|
493
594
|
}
|
|
494
|
-
(0,
|
|
495
|
-
(0,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
631
|
+
if ((0, import_fs5.existsSync)(c)) return c;
|
|
531
632
|
} catch {
|
|
532
633
|
}
|
|
533
634
|
}
|
|
534
635
|
}
|
|
535
|
-
return (0,
|
|
636
|
+
return (0, import_os3.homedir)();
|
|
536
637
|
}
|
|
537
|
-
var pty,
|
|
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
|
-
|
|
543
|
-
|
|
544
|
-
|
|
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,
|
|
549
|
-
BASH_INIT = (0,
|
|
550
|
-
ZSH_DIR = (0,
|
|
551
|
-
ZSH_RC = (0,
|
|
552
|
-
ZSH_ENV = (0,
|
|
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,
|
|
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 =
|
|
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,
|
|
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 =
|
|
773
|
-
const freeMem =
|
|
873
|
+
const totalMem = import_os4.default.totalmem();
|
|
874
|
+
const freeMem = import_os4.default.freemem();
|
|
774
875
|
return {
|
|
775
|
-
hostname:
|
|
876
|
+
hostname: import_os4.default.hostname(),
|
|
776
877
|
platform: process.platform,
|
|
777
|
-
arch:
|
|
878
|
+
arch: import_os4.default.arch(),
|
|
778
879
|
cpuUsage: getCpuUsage(),
|
|
779
880
|
memoryUsage: Math.round((totalMem - freeMem) / totalMem * 100),
|
|
780
|
-
uptime: Math.round(
|
|
881
|
+
uptime: Math.round(import_os4.default.uptime()),
|
|
781
882
|
activeSessions: getActiveSessionCount(),
|
|
782
|
-
pathSeparator:
|
|
783
|
-
homeDirectory: 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
|
|
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
|
-
|
|
793
|
-
|
|
794
|
-
|
|
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 =
|
|
803
|
-
return rel === "" || !rel.startsWith(".." +
|
|
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 =
|
|
908
|
+
const resolved = import_path6.default.resolve(dirPath);
|
|
808
909
|
if (isInSecretDir(resolved)) {
|
|
809
910
|
return { entries: [], error: "Access denied" };
|
|
810
911
|
}
|
|
811
|
-
if (!
|
|
912
|
+
if (!import_fs6.default.existsSync(resolved)) {
|
|
812
913
|
return { entries: [], error: "Path does not exist" };
|
|
813
914
|
}
|
|
814
|
-
const stat =
|
|
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 =
|
|
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 =
|
|
823
|
-
const s =
|
|
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 =
|
|
946
|
+
const resolved = import_path6.default.resolve(filePath);
|
|
846
947
|
if (isInSecretDir(resolved)) {
|
|
847
948
|
return { error: "Access denied" };
|
|
848
949
|
}
|
|
849
|
-
if (!
|
|
950
|
+
if (!import_fs6.default.existsSync(resolved)) {
|
|
850
951
|
return { error: "File does not exist" };
|
|
851
952
|
}
|
|
852
|
-
const stat =
|
|
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 =
|
|
860
|
-
const fileStream =
|
|
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
|
|
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
|
-
|
|
894
|
-
|
|
895
|
-
|
|
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 =
|
|
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 (
|
|
922
|
-
return
|
|
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 (!
|
|
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 (!
|
|
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 (!
|
|
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 (!
|
|
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
|
|
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
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
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,
|
|
1331
|
+
execAsync = (0, import_util3.promisify)(import_child_process5.exec);
|
|
1231
1332
|
isWindows = process.platform === "win32";
|
|
1232
|
-
VPN_DIR =
|
|
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 =
|
|
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 (!
|
|
1416
|
+
if (!import_fs8.default.existsSync(CLAUDE_PROJECTS_DIR)) return sessions2;
|
|
1316
1417
|
const isDirSafe = (d) => {
|
|
1317
1418
|
try {
|
|
1318
|
-
return
|
|
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 =
|
|
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 =
|
|
1439
|
+
const dirPath = import_path8.default.join(CLAUDE_PROJECTS_DIR, dirName);
|
|
1339
1440
|
let files;
|
|
1340
1441
|
try {
|
|
1341
|
-
files =
|
|
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(
|
|
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
|
|
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
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
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 =
|
|
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 =
|
|
1383
|
-
if (
|
|
1384
|
-
if (!
|
|
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 =
|
|
1488
|
+
allDirs = import_fs9.default.readdirSync(CLAUDE_PROJECTS_DIR2).filter((d) => {
|
|
1388
1489
|
try {
|
|
1389
|
-
return
|
|
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
|
|
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 (!
|
|
1506
|
+
if (!import_fs9.default.existsSync(CLAUDE_PROJECTS_DIR2)) return null;
|
|
1406
1507
|
let dirs;
|
|
1407
1508
|
try {
|
|
1408
|
-
dirs =
|
|
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 =
|
|
1514
|
+
const candidate = import_path9.default.join(CLAUDE_PROJECTS_DIR2, dir, `${sessionId}.jsonl`);
|
|
1414
1515
|
try {
|
|
1415
|
-
if (
|
|
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 =
|
|
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:
|
|
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:
|
|
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 ?
|
|
1450
|
-
if (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 =
|
|
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
|
|
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
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
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 =
|
|
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:
|
|
1739
|
-
const execAsync2 =
|
|
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 || "" });
|