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