ragent-cli 1.7.0 → 1.7.2

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.
Files changed (2) hide show
  1. package/dist/index.js +85 -33
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -31,7 +31,7 @@ var require_package = __commonJS({
31
31
  "package.json"(exports2, module2) {
32
32
  module2.exports = {
33
33
  name: "ragent-cli",
34
- version: "1.7.0",
34
+ version: "1.7.2",
35
35
  description: "CLI agent for rAgent Live \u2014 browser-first terminal control plane for AI coding agents",
36
36
  main: "dist/index.js",
37
37
  bin: {
@@ -575,14 +575,17 @@ async function collectSessionInventory(hostId, command) {
575
575
  for (const s of [...screen, ...zellij]) {
576
576
  if (s.pids) s.pids.forEach((p) => multiplexerPids.add(p));
577
577
  }
578
- for (const s of tmux) {
579
- if (s.pids) {
580
- for (const pid of s.pids) {
581
- multiplexerPids.add(pid);
582
- const childInfo = await getChildAgentInfo(pid);
583
- if (childInfo) {
584
- childInfo.childPids.forEach((p) => multiplexerPids.add(p));
585
- }
578
+ const tmuxChildTasks = tmux.flatMap(
579
+ (s) => (s.pids ?? []).map(async (pid) => ({ session: s, pid, childInfo: await getChildAgentInfo(pid) }))
580
+ );
581
+ const tmuxChildResults = await Promise.all(tmuxChildTasks);
582
+ for (const { session: s, pid, childInfo } of tmuxChildResults) {
583
+ multiplexerPids.add(pid);
584
+ if (childInfo) {
585
+ childInfo.childPids.forEach((p) => multiplexerPids.add(p));
586
+ if (!s.agentType && childInfo.agentType) {
587
+ s.agentType = childInfo.agentType;
588
+ s.command = childInfo.command;
586
589
  }
587
590
  }
588
591
  }
@@ -606,12 +609,13 @@ function detectAgentType(command) {
606
609
  const cmd = command.toLowerCase();
607
610
  const parts = cmd.split(/\s+/);
608
611
  const binary = parts[0]?.split("/").pop() ?? "";
609
- const scriptArg = binary === "node" && parts[1] ? parts[1].split("/").pop() ?? "" : "";
610
- if (binary === "claude" || binary === "claude-code" || scriptArg === "cli.js" && cmd.includes("claude-code")) {
612
+ const rawScriptArg = binary === "node" && parts[1] ? parts[1].split("/").pop() ?? "" : "";
613
+ const scriptArg = rawScriptArg.replace(/\.m?js$/, "");
614
+ if (binary === "claude" || binary === "claude-code" || scriptArg === "cli" && cmd.includes("claude-code")) {
611
615
  if (cmd.includes("--chrome-native-host")) return void 0;
612
616
  return "Claude Code";
613
617
  }
614
- if (binary === "codex" || scriptArg === "codex" || cmd.includes("codex-cli")) return "Codex CLI";
618
+ if (binary === "codex" || scriptArg === "codex" && cmd.includes("@openai/codex") || cmd.includes("codex-cli")) return "Codex CLI";
615
619
  if (binary === "aider") return "aider";
616
620
  if (binary === "cursor") {
617
621
  if (isElectronProcess(cmd)) return void 0;
@@ -621,9 +625,9 @@ function detectAgentType(command) {
621
625
  if (isElectronProcess(cmd)) return void 0;
622
626
  return "Windsurf";
623
627
  }
624
- if (binary === "gemini") return "Gemini CLI";
628
+ if (binary === "gemini" || scriptArg === "gemini" && cmd.includes("gemini-cli")) return "Gemini CLI";
625
629
  if (binary === "amazon-q" || binary === "amazon_q") return "Amazon Q";
626
- if (binary === "copilot") return "Copilot CLI";
630
+ if (binary === "copilot" || scriptArg === "copilot" && cmd.includes("@github/copilot")) return "Copilot CLI";
627
631
  return void 0;
628
632
  }
629
633
  function sessionInventoryFingerprint(sessions) {
@@ -1289,18 +1293,32 @@ var SessionStreamer = class {
1289
1293
  if (!paneTarget || !cleanEnv) return false;
1290
1294
  stream.initializing = true;
1291
1295
  try {
1296
+ let alternateScreen = false;
1292
1297
  try {
1293
- const scrollback = (0, import_node_child_process2.execFileSync)(
1298
+ const altFlag = (0, import_node_child_process2.execFileSync)(
1294
1299
  "tmux",
1295
- ["capture-pane", "-t", paneTarget, "-p", "-e", "-S", "-5000", "-E", "-1"],
1296
- { env: cleanEnv, timeout: 1e4, encoding: "utf-8" }
1297
- );
1298
- if (scrollback && scrollback.length > 0) {
1299
- this.sendFn(sessionId, scrollback.replace(/\n/g, "\r\n"));
1300
- }
1300
+ ["display-message", "-t", paneTarget, "-p", "#{alternate_on}"],
1301
+ { env: cleanEnv, timeout: 5e3, encoding: "utf-8" }
1302
+ ).trim();
1303
+ alternateScreen = altFlag === "1";
1301
1304
  } catch {
1302
1305
  }
1303
- this.sendFn(sessionId, "\x1B[0m\x1B[2J\x1B[H");
1306
+ if (alternateScreen) {
1307
+ this.sendFn(sessionId, "\x1B[?1049h\x1B[0m\x1B[2J\x1B[H");
1308
+ } else {
1309
+ try {
1310
+ const scrollback = (0, import_node_child_process2.execFileSync)(
1311
+ "tmux",
1312
+ ["capture-pane", "-t", paneTarget, "-p", "-e", "-S", "-5000", "-E", "-1"],
1313
+ { env: cleanEnv, timeout: 1e4, encoding: "utf-8" }
1314
+ );
1315
+ if (scrollback && scrollback.length > 0) {
1316
+ this.sendFn(sessionId, scrollback.replace(/\n/g, "\r\n"));
1317
+ }
1318
+ } catch {
1319
+ }
1320
+ this.sendFn(sessionId, "\x1B[?1049l\x1B[0m\x1B[2J\x1B[H");
1321
+ }
1304
1322
  try {
1305
1323
  const initial = (0, import_node_child_process2.execFileSync)(
1306
1324
  "tmux",
@@ -1414,18 +1432,33 @@ var SessionStreamer = class {
1414
1432
  this.onStreamStopped?.(sessionId);
1415
1433
  }
1416
1434
  });
1435
+ let alternateScreen = false;
1417
1436
  try {
1418
- const scrollback = (0, import_node_child_process2.execFileSync)(
1437
+ const altFlag = (0, import_node_child_process2.execFileSync)(
1419
1438
  "tmux",
1420
- ["capture-pane", "-t", paneTarget, "-p", "-e", "-S", "-5000", "-E", "-1"],
1421
- { env: cleanEnv, timeout: 1e4, encoding: "utf-8" }
1422
- );
1423
- if (scrollback && scrollback.length > 0) {
1424
- this.sendFn(sessionId, scrollback.replace(/\n/g, "\r\n"));
1425
- }
1439
+ ["display-message", "-t", paneTarget, "-p", "#{alternate_on}"],
1440
+ { env: cleanEnv, timeout: 5e3, encoding: "utf-8" }
1441
+ ).trim();
1442
+ alternateScreen = altFlag === "1";
1426
1443
  } catch {
1427
1444
  }
1428
- this.sendFn(sessionId, "\x1B[0m\x1B[2J\x1B[H");
1445
+ stream.alternateScreen = alternateScreen;
1446
+ if (alternateScreen) {
1447
+ this.sendFn(sessionId, "\x1B[?1049h\x1B[0m\x1B[2J\x1B[H");
1448
+ } else {
1449
+ try {
1450
+ const scrollback = (0, import_node_child_process2.execFileSync)(
1451
+ "tmux",
1452
+ ["capture-pane", "-t", paneTarget, "-p", "-e", "-S", "-5000", "-E", "-1"],
1453
+ { env: cleanEnv, timeout: 1e4, encoding: "utf-8" }
1454
+ );
1455
+ if (scrollback && scrollback.length > 0) {
1456
+ this.sendFn(sessionId, scrollback.replace(/\n/g, "\r\n"));
1457
+ }
1458
+ } catch {
1459
+ }
1460
+ this.sendFn(sessionId, "\x1B[?1049l\x1B[0m\x1B[2J\x1B[H");
1461
+ }
1429
1462
  try {
1430
1463
  const initial = (0, import_node_child_process2.execFileSync)(
1431
1464
  "tmux",
@@ -1573,8 +1606,18 @@ var SessionStreamer = class {
1573
1606
  if (!pid) return false;
1574
1607
  if (!(0, import_node_fs.existsSync)(`/proc/${pid}`)) {
1575
1608
  console.warn(`[rAgent] Process ${pid} does not exist (no /proc/${pid}).`);
1609
+ this.sendFn(sessionId, "\r\n[rAgent] Process is no longer running. It will be removed on next sync.\r\n");
1576
1610
  return false;
1577
1611
  }
1612
+ try {
1613
+ const stat = (0, import_node_fs.readFileSync)(`/proc/${pid}/stat`, "utf8");
1614
+ if (stat.includes(") Z")) {
1615
+ console.warn(`[rAgent] Process ${pid} is a zombie.`);
1616
+ this.sendFn(sessionId, "\r\n[rAgent] Process has exited (zombie). It will be removed on next sync.\r\n");
1617
+ return false;
1618
+ }
1619
+ } catch {
1620
+ }
1578
1621
  try {
1579
1622
  const straceProc = (0, import_node_child_process2.spawn)(
1580
1623
  "strace",
@@ -1632,7 +1675,11 @@ var SessionStreamer = class {
1632
1675
  const remaining = stream.utf8Decoder.end();
1633
1676
  if (remaining) this.sendFn(sessionId, remaining);
1634
1677
  if (code === 1) {
1635
- this.sendFn(sessionId, "\r\n[rAgent] Permission denied: cannot attach to process.\r\nTo enable process tracing, run:\r\n sudo sysctl kernel.yama.ptrace_scope=0\r\n");
1678
+ if (pid && !(0, import_node_fs.existsSync)(`/proc/${pid}`)) {
1679
+ this.sendFn(sessionId, "\r\n[rAgent] Process has exited. It will be removed on next sync.\r\n");
1680
+ } else {
1681
+ this.sendFn(sessionId, "\r\n[rAgent] Permission denied: cannot attach to process.\r\nTo enable process tracing, run:\r\n sudo sysctl kernel.yama.ptrace_scope=0\r\n");
1682
+ }
1636
1683
  }
1637
1684
  stream.stopped = true;
1638
1685
  this.active.delete(sessionId);
@@ -2723,8 +2770,13 @@ var ControlDispatcher = class {
2723
2770
  process.kill(pid, "SIGTERM");
2724
2771
  console.log(`[rAgent] Sent SIGTERM to process ${pid} (${sessionId}).`);
2725
2772
  } catch (error) {
2726
- const message = error instanceof Error ? error.message : String(error);
2727
- console.warn(`[rAgent] Failed to kill process ${pid}: ${message}`);
2773
+ const code = error.code;
2774
+ if (code === "ESRCH") {
2775
+ console.log(`[rAgent] Process ${pid} already exited, cleaning up.`);
2776
+ } else {
2777
+ const message = error instanceof Error ? error.message : String(error);
2778
+ console.warn(`[rAgent] Failed to kill process ${pid}: ${message}`);
2779
+ }
2728
2780
  }
2729
2781
  await this.syncInventory();
2730
2782
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ragent-cli",
3
- "version": "1.7.0",
3
+ "version": "1.7.2",
4
4
  "description": "CLI agent for rAgent Live — browser-first terminal control plane for AI coding agents",
5
5
  "main": "dist/index.js",
6
6
  "bin": {