cli-remote-agent 1.0.8 → 1.0.11
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 +86 -3
- package/dist/cli.js.map +1 -1
- package/dist/index.js +83 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -59,6 +59,7 @@ var TMUX_LIST = "tmux:list";
|
|
|
59
59
|
var TMUX_LIST_RESULT = "tmux:list:result";
|
|
60
60
|
var TMUX_KILL = "tmux:kill";
|
|
61
61
|
var TMUX_KILL_RESULT = "tmux:kill:result";
|
|
62
|
+
var TMUX_SCROLL = "tmux:scroll";
|
|
62
63
|
|
|
63
64
|
// ../shared/src/constants.ts
|
|
64
65
|
var HEARTBEAT_INTERVAL = 15e3;
|
|
@@ -372,6 +373,7 @@ function getLiveClaudeSessions() {
|
|
|
372
373
|
out.push({
|
|
373
374
|
pid: obj.pid,
|
|
374
375
|
cwd: typeof obj.cwd === "string" ? obj.cwd : "",
|
|
376
|
+
sessionId: typeof obj.sessionId === "string" ? obj.sessionId : void 0,
|
|
375
377
|
name: typeof obj.name === "string" ? obj.name : void 0,
|
|
376
378
|
status: typeof obj.status === "string" ? obj.status : void 0,
|
|
377
379
|
updatedAt: typeof obj.updatedAt === "number" ? obj.updatedAt : void 0
|
|
@@ -402,6 +404,15 @@ function isDescendantOf(pid, ancestor, parents) {
|
|
|
402
404
|
}
|
|
403
405
|
return false;
|
|
404
406
|
}
|
|
407
|
+
async function findClaudeSessionForPtyPid(ptyPid) {
|
|
408
|
+
const live = getLiveClaudeSessions().filter((s) => s.sessionId);
|
|
409
|
+
if (live.length === 0) return null;
|
|
410
|
+
const parents = await getPidParents();
|
|
411
|
+
for (let i = live.length - 1; i >= 0; i--) {
|
|
412
|
+
if (isDescendantOf(live[i].pid, ptyPid, parents)) return live[i].sessionId;
|
|
413
|
+
}
|
|
414
|
+
return null;
|
|
415
|
+
}
|
|
405
416
|
|
|
406
417
|
// src/tmux.ts
|
|
407
418
|
var execFileAsync2 = (0, import_util2.promisify)(import_child_process3.execFile);
|
|
@@ -459,6 +470,41 @@ async function killTmuxSession(name) {
|
|
|
459
470
|
return { ok: false, error: msg };
|
|
460
471
|
}
|
|
461
472
|
}
|
|
473
|
+
async function scrollTmux(name, direction) {
|
|
474
|
+
const bin = resolveTmuxPath();
|
|
475
|
+
if (!bin) return { inCopyMode: false };
|
|
476
|
+
const target = `=${name}`;
|
|
477
|
+
const run = (args) => execFileAsync2(bin, args, { timeout: 4e3 }).catch(() => {
|
|
478
|
+
});
|
|
479
|
+
const inMode = async () => {
|
|
480
|
+
try {
|
|
481
|
+
const { stdout } = await execFileAsync2(bin, ["display-message", "-t", target, "-p", "#{pane_in_mode}"], { timeout: 3e3 });
|
|
482
|
+
return stdout.trim() === "1";
|
|
483
|
+
} catch {
|
|
484
|
+
return false;
|
|
485
|
+
}
|
|
486
|
+
};
|
|
487
|
+
if (direction === "exit") {
|
|
488
|
+
if (await inMode()) await run(["send-keys", "-t", target, "-X", "cancel"]);
|
|
489
|
+
return { inCopyMode: false };
|
|
490
|
+
}
|
|
491
|
+
if (direction === "up") {
|
|
492
|
+
await run(["copy-mode", "-t", target]);
|
|
493
|
+
await run(["send-keys", "-t", target, "-X", "halfpage-up"]);
|
|
494
|
+
return { inCopyMode: true };
|
|
495
|
+
}
|
|
496
|
+
if (!await inMode()) return { inCopyMode: false };
|
|
497
|
+
await run(["send-keys", "-t", target, "-X", "halfpage-down"]);
|
|
498
|
+
try {
|
|
499
|
+
const { stdout } = await execFileAsync2(bin, ["display-message", "-t", target, "-p", "#{scroll_position}"], { timeout: 3e3 });
|
|
500
|
+
if ((parseInt(stdout.trim(), 10) || 0) === 0) {
|
|
501
|
+
await run(["send-keys", "-t", target, "-X", "cancel"]);
|
|
502
|
+
return { inCopyMode: false };
|
|
503
|
+
}
|
|
504
|
+
} catch {
|
|
505
|
+
}
|
|
506
|
+
return { inCopyMode: true };
|
|
507
|
+
}
|
|
462
508
|
async function enrichWithPanesAndClaude(sessions2) {
|
|
463
509
|
if (IS_WIN || sessions2.length === 0) return;
|
|
464
510
|
try {
|
|
@@ -639,6 +685,9 @@ var PtySession = class {
|
|
|
639
685
|
});
|
|
640
686
|
}
|
|
641
687
|
}
|
|
688
|
+
get pid() {
|
|
689
|
+
return this.pty.pid;
|
|
690
|
+
}
|
|
642
691
|
write(data) {
|
|
643
692
|
this.pty.write(data);
|
|
644
693
|
}
|
|
@@ -704,6 +753,9 @@ function createTerminalSession(sessionId, cols, rows, shellPreference, cwd, onDa
|
|
|
704
753
|
sessions.set(sessionId, session);
|
|
705
754
|
logger.info({ sessionId, cols, rows }, "PTY session created");
|
|
706
755
|
}
|
|
756
|
+
function getSessionPid(sessionId) {
|
|
757
|
+
return sessions.get(sessionId)?.pid;
|
|
758
|
+
}
|
|
707
759
|
function writeToSession(sessionId, data) {
|
|
708
760
|
sessions.get(sessionId)?.write(data);
|
|
709
761
|
}
|
|
@@ -1614,9 +1666,12 @@ startLocalControl(LOCAL_CONTROL_PORT, (raw) => {
|
|
|
1614
1666
|
socket.emit(CLAUDE_HOOK, payload);
|
|
1615
1667
|
}
|
|
1616
1668
|
});
|
|
1669
|
+
var sessionTmuxName = /* @__PURE__ */ new Map();
|
|
1670
|
+
var sessionInCopyMode = /* @__PURE__ */ new Map();
|
|
1617
1671
|
socket.on(TERMINAL_OPEN, (payload) => {
|
|
1618
1672
|
const { sessionId, cols, rows, tmux, launch } = payload;
|
|
1619
1673
|
if (!sessionId) return;
|
|
1674
|
+
if (tmux) sessionTmuxName.set(sessionId, tmux);
|
|
1620
1675
|
let launchSpec;
|
|
1621
1676
|
if (tmux) {
|
|
1622
1677
|
const spec = buildTmuxLaunch(tmux, launch);
|
|
@@ -1640,6 +1695,8 @@ socket.on(TERMINAL_OPEN, (payload) => {
|
|
|
1640
1695
|
},
|
|
1641
1696
|
(sid, exitCode) => {
|
|
1642
1697
|
socket.emit(TERMINAL_EXIT, { sessionId: sid, exitCode });
|
|
1698
|
+
sessionTmuxName.delete(sid);
|
|
1699
|
+
sessionInCopyMode.delete(sid);
|
|
1643
1700
|
},
|
|
1644
1701
|
launchSpec
|
|
1645
1702
|
);
|
|
@@ -1661,7 +1718,20 @@ socket.on(TMUX_KILL, async (payload) => {
|
|
|
1661
1718
|
logger.info({ name, ok: result.ok, error: result.error }, "tmux kill requested");
|
|
1662
1719
|
socket.emit(TMUX_KILL_RESULT, { requestId, name, ok: result.ok, error: result.error });
|
|
1663
1720
|
});
|
|
1721
|
+
socket.on(TMUX_SCROLL, async (payload) => {
|
|
1722
|
+
const { sessionId, direction } = payload;
|
|
1723
|
+
const name = sessionId && sessionTmuxName.get(sessionId);
|
|
1724
|
+
if (!name) return;
|
|
1725
|
+
const { inCopyMode } = await scrollTmux(name, direction);
|
|
1726
|
+
sessionInCopyMode.set(sessionId, inCopyMode);
|
|
1727
|
+
});
|
|
1664
1728
|
socket.on(TERMINAL_INPUT, (payload) => {
|
|
1729
|
+
const name = sessionTmuxName.get(payload.sessionId);
|
|
1730
|
+
if (name && sessionInCopyMode.get(payload.sessionId)) {
|
|
1731
|
+
sessionInCopyMode.set(payload.sessionId, false);
|
|
1732
|
+
scrollTmux(name, "exit").catch(() => {
|
|
1733
|
+
});
|
|
1734
|
+
}
|
|
1665
1735
|
writeToSession(payload.sessionId, payload.data);
|
|
1666
1736
|
});
|
|
1667
1737
|
socket.on(TERMINAL_RESIZE, (payload) => {
|
|
@@ -1669,6 +1739,8 @@ socket.on(TERMINAL_RESIZE, (payload) => {
|
|
|
1669
1739
|
});
|
|
1670
1740
|
socket.on(TERMINAL_CLOSE, (payload) => {
|
|
1671
1741
|
closeSession(payload.sessionId);
|
|
1742
|
+
sessionTmuxName.delete(payload.sessionId);
|
|
1743
|
+
sessionInCopyMode.delete(payload.sessionId);
|
|
1672
1744
|
});
|
|
1673
1745
|
socket.on(SESSION_SYNC, () => {
|
|
1674
1746
|
const aliveIds = getAliveSessionIds();
|
|
@@ -1745,7 +1817,17 @@ socket.on(AGENT_EXEC, async (payload) => {
|
|
|
1745
1817
|
});
|
|
1746
1818
|
socket.on(CLAUDE_CONV_READ, async (payload) => {
|
|
1747
1819
|
try {
|
|
1748
|
-
|
|
1820
|
+
let sessionId = payload.sessionId;
|
|
1821
|
+
if (!sessionId && payload.terminalSessionId) {
|
|
1822
|
+
const ptyPid = getSessionPid(payload.terminalSessionId);
|
|
1823
|
+
const resolved = ptyPid ? await findClaudeSessionForPtyPid(ptyPid) : null;
|
|
1824
|
+
if (!resolved) {
|
|
1825
|
+
socket.emit(CLAUDE_CONV_DATA, { sessionId: "", messages: [], totalLines: 0 });
|
|
1826
|
+
return;
|
|
1827
|
+
}
|
|
1828
|
+
sessionId = resolved;
|
|
1829
|
+
}
|
|
1830
|
+
const result = await readConversation(payload.projectPath, payload.afterLine || 0, sessionId);
|
|
1749
1831
|
if (result) {
|
|
1750
1832
|
socket.emit(CLAUDE_CONV_DATA, {
|
|
1751
1833
|
sessionId: result.sessionId,
|