ragent-cli 1.11.18 → 1.11.20

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/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.11.18",
34
+ version: "1.11.20",
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: {
@@ -90,7 +90,7 @@ var require_package = __commonJS({
90
90
  commander: "^14.0.3",
91
91
  figlet: "^1.9.3",
92
92
  "node-pty": "^1.1.0",
93
- ws: "^8.19.0"
93
+ ws: "^8.21.0"
94
94
  },
95
95
  devDependencies: {
96
96
  "@changesets/changelog-github": "^0.5.2",
@@ -11075,7 +11075,9 @@ var SessionStreamer = class {
11075
11075
  * never fires, and `resyncStream` deliberately does NOT restart pipe-pane —
11076
11076
  * so without this the pane is frozen until the stream is torn down by hand.
11077
11077
  *
11078
- * Batched into one `tmux list-panes -a` call so liveness costs one fork.
11078
+ * Costs one batched `tmux list-panes -a` fork for pids, plus one `capture-pane`
11079
+ * fork ONLY per currently-silent stream (flowing streams are provably alive and
11080
+ * skip the hash) — so ~one fork/tick on a healthy host.
11079
11081
  */
11080
11082
  checkPipeLiveness() {
11081
11083
  const tmuxStreams = [...this.active.values()].filter(
@@ -11101,22 +11103,29 @@ var SessionStreamer = class {
11101
11103
  continue;
11102
11104
  }
11103
11105
  const bytesNow = stream.bytesReceived ?? 0;
11104
- const paneMoved = info.fingerprint !== stream.lastLivenessFingerprint;
11105
11106
  const fifoSilent = bytesNow === (stream.lastLivenessBytes ?? 0);
11106
- if (paneMoved && fifoSilent) {
11107
- stream.deadPipeStrikes = (stream.deadPipeStrikes ?? 0) + 1;
11108
- if (stream.deadPipeStrikes >= DEAD_PIPE_STRIKES && !backedOff) {
11109
- dead.push({
11110
- sessionId: stream.sessionId,
11111
- reason: "pipe-pane silent while pane active",
11112
- detail: { strikes: stream.deadPipeStrikes }
11113
- });
11114
- }
11115
- } else {
11107
+ if (!fifoSilent) {
11116
11108
  stream.deadPipeStrikes = 0;
11109
+ } else {
11110
+ const contentHash = this.paneContentHash(stream.paneTarget, stream.cleanEnv);
11111
+ if (contentHash !== null) {
11112
+ const paneMoved = stream.lastContentHash !== void 0 && contentHash !== stream.lastContentHash;
11113
+ if (paneMoved) {
11114
+ stream.deadPipeStrikes = (stream.deadPipeStrikes ?? 0) + 1;
11115
+ if (stream.deadPipeStrikes >= DEAD_PIPE_STRIKES && !backedOff) {
11116
+ dead.push({
11117
+ sessionId: stream.sessionId,
11118
+ reason: "pipe-pane silent while pane active",
11119
+ detail: { strikes: stream.deadPipeStrikes }
11120
+ });
11121
+ }
11122
+ } else {
11123
+ stream.deadPipeStrikes = 0;
11124
+ }
11125
+ stream.lastContentHash = contentHash;
11126
+ }
11117
11127
  }
11118
11128
  stream.lastLivenessBytes = bytesNow;
11119
- stream.lastLivenessFingerprint = info.fingerprint;
11120
11129
  }
11121
11130
  if (dead.length === 0) return;
11122
11131
  const [first, ...rest] = dead;
@@ -11460,7 +11469,7 @@ var SessionStreamer = class {
11460
11469
  try {
11461
11470
  this.sendResetFn?.(sessionId, withScrollback ? "full" : "repaint", targetViewerId);
11462
11471
  const alternateScreen = this.detectAlternateScreen(paneTarget, cleanEnv);
11463
- if (withScrollback) {
11472
+ if (withScrollback && !alternateScreen) {
11464
11473
  send("\x1B[3J");
11465
11474
  try {
11466
11475
  const scrollback = (0, import_node_child_process2.execFileSync)(
@@ -11505,6 +11514,31 @@ var SessionStreamer = class {
11505
11514
  return false;
11506
11515
  }
11507
11516
  }
11517
+ /** Cheap stable string hash (djb2) for content change-detection. */
11518
+ hashString(s) {
11519
+ let h = 5381;
11520
+ for (let i = 0; i < s.length; i++) h = Math.imul(h, 33) + s.charCodeAt(i) | 0;
11521
+ return (h >>> 0).toString(36) + ":" + s.length;
11522
+ }
11523
+ /**
11524
+ * Hash of a pane's visible content (`capture-pane -p`). This is the watchdog's
11525
+ * activity signal: unlike cursor/history it changes on ANY visible redraw,
11526
+ * including in-place TUI updates (spinners, token counters, status bars) that
11527
+ * a Claude/Gemini pane emits without moving the cursor. Null on tmux failure
11528
+ * (the watchdog then skips the activity check for that tick).
11529
+ */
11530
+ paneContentHash(paneTarget, cleanEnv) {
11531
+ try {
11532
+ const out = (0, import_node_child_process2.execFileSync)(
11533
+ "tmux",
11534
+ ["capture-pane", "-t", paneTarget, "-p"],
11535
+ { env: cleanEnv ?? this.tmuxEnv(), timeout: 5e3, encoding: "utf-8" }
11536
+ );
11537
+ return this.hashString(out);
11538
+ } catch {
11539
+ return null;
11540
+ }
11541
+ }
11508
11542
  /** Build a tmux-safe env (TMUX/TMUX_PANE stripped) for liveness queries. */
11509
11543
  tmuxEnv() {
11510
11544
  const env = { ...process.env };
@@ -11562,9 +11596,9 @@ var SessionStreamer = class {
11562
11596
  * would shift the viewport by 1 row. Returns the number of lines sent
11563
11597
  * (0 when the capture failed or was empty) for relative cursor sync.
11564
11598
  */
11565
- sendVisiblePane(send, paneTarget, cleanEnv, alternateScreen) {
11599
+ sendVisiblePane(send, paneTarget, cleanEnv, _alternateScreen) {
11566
11600
  try {
11567
- const captureArgs = alternateScreen ? ["capture-pane", "-a", "-t", paneTarget, "-p", "-e"] : ["capture-pane", "-t", paneTarget, "-p", "-e"];
11601
+ const captureArgs = ["capture-pane", "-t", paneTarget, "-p", "-e"];
11568
11602
  const initial = (0, import_node_child_process2.execFileSync)(
11569
11603
  "tmux",
11570
11604
  captureArgs,
@@ -11658,10 +11692,8 @@ var SessionStreamer = class {
11658
11692
  return false;
11659
11693
  }
11660
11694
  const paneInfo = this.readPaneInfo(paneTarget, cleanEnv);
11661
- if (paneInfo) {
11662
- stream.panePid = paneInfo.panePid;
11663
- stream.lastLivenessFingerprint = paneInfo.fingerprint;
11664
- }
11695
+ if (paneInfo) stream.panePid = paneInfo.panePid;
11696
+ stream.lastContentHash = this.paneContentHash(paneTarget, cleanEnv) ?? void 0;
11665
11697
  stream.bytesReceived = 0;
11666
11698
  stream.lastLivenessBytes = 0;
11667
11699
  stream.deadPipeStrikes = 0;
@@ -11698,7 +11730,7 @@ var SessionStreamer = class {
11698
11730
  this.sendResetFn?.(sessionId, "full");
11699
11731
  const alternateScreen = this.detectAlternateScreen(paneTarget, cleanEnv);
11700
11732
  stream.alternateScreen = alternateScreen;
11701
- if (!opts?.skipScrollback) {
11733
+ if (!opts?.skipScrollback && !alternateScreen) {
11702
11734
  this.sendFn(sessionId, "\x1B[3J");
11703
11735
  try {
11704
11736
  const scrollback = (0, import_node_child_process2.execFileSync)(
package/dist/sbom.json CHANGED
@@ -1299,8 +1299,8 @@
1299
1299
  {
1300
1300
  "type": "library",
1301
1301
  "name": "ragent-cli",
1302
- "version": "1.11.18",
1303
- "bom-ref": "ragent-live|ragent-cli@1.11.18",
1302
+ "version": "1.11.20",
1303
+ "bom-ref": "ragent-live|ragent-cli@1.11.20",
1304
1304
  "author": "Intellimetrics",
1305
1305
  "description": "CLI agent for rAgent Live — browser-first terminal control plane for AI coding agents",
1306
1306
  "licenses": [
@@ -1311,7 +1311,7 @@
1311
1311
  }
1312
1312
  }
1313
1313
  ],
1314
- "purl": "pkg:npm/ragent-cli@1.11.18",
1314
+ "purl": "pkg:npm/ragent-cli@1.11.20",
1315
1315
  "externalReferences": [
1316
1316
  {
1317
1317
  "url": "https://github.com/chadlindell/ragent-live/issues",
@@ -1384,8 +1384,8 @@
1384
1384
  {
1385
1385
  "type": "library",
1386
1386
  "name": "ws",
1387
- "version": "8.20.0",
1388
- "bom-ref": "ragent-live|ws@8.20.0",
1387
+ "version": "8.21.0",
1388
+ "bom-ref": "ragent-live|ws@8.21.0",
1389
1389
  "author": "Einar Otto Stangvik",
1390
1390
  "description": "Simple to use, blazing fast and thoroughly tested websocket client and server for Node.js",
1391
1391
  "licenses": [
@@ -1396,10 +1396,10 @@
1396
1396
  }
1397
1397
  }
1398
1398
  ],
1399
- "purl": "pkg:npm/ws@8.20.0",
1399
+ "purl": "pkg:npm/ws@8.21.0",
1400
1400
  "externalReferences": [
1401
1401
  {
1402
- "url": "https://registry.npmjs.org/ws/-/ws-8.20.0.tgz",
1402
+ "url": "https://registry.npmjs.org/ws/-/ws-8.21.0.tgz",
1403
1403
  "type": "distribution",
1404
1404
  "comment": "as detected from npm-ls property \"resolved\""
1405
1405
  },
@@ -1436,7 +1436,7 @@
1436
1436
  "ragent-live|@emnapi/wasi-threads@1.2.1",
1437
1437
  "ragent-live|@pkgjs/parseargs@0.11.0",
1438
1438
  "ragent-live|@tybys/wasm-util@0.10.1",
1439
- "ragent-live|ragent-cli@1.11.18"
1439
+ "ragent-live|ragent-cli@1.11.20"
1440
1440
  ]
1441
1441
  },
1442
1442
  {
@@ -1469,7 +1469,7 @@
1469
1469
  "ragent-live|buffer@6.0.3",
1470
1470
  "ragent-live|events@3.3.0",
1471
1471
  "ragent-live|tslib@2.8.1",
1472
- "ragent-live|ws@8.20.0"
1472
+ "ragent-live|ws@8.21.0"
1473
1473
  ]
1474
1474
  },
1475
1475
  {
@@ -1584,21 +1584,21 @@
1584
1584
  ]
1585
1585
  },
1586
1586
  {
1587
- "ref": "ragent-live|ragent-cli@1.11.18",
1587
+ "ref": "ragent-live|ragent-cli@1.11.20",
1588
1588
  "dependsOn": [
1589
1589
  "ragent-live|@azure/web-pubsub-client@1.0.4",
1590
1590
  "ragent-live|@openai/codex-sdk@0.130.0",
1591
1591
  "ragent-live|commander@14.0.3",
1592
1592
  "ragent-live|figlet@1.11.0",
1593
1593
  "ragent-live|node-pty@1.1.0",
1594
- "ragent-live|ws@8.20.0"
1594
+ "ragent-live|ws@8.21.0"
1595
1595
  ]
1596
1596
  },
1597
1597
  {
1598
1598
  "ref": "ragent-live|tslib@2.8.1"
1599
1599
  },
1600
1600
  {
1601
- "ref": "ragent-live|ws@8.20.0"
1601
+ "ref": "ragent-live|ws@8.21.0"
1602
1602
  }
1603
1603
  ]
1604
1604
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ragent-cli",
3
- "version": "1.11.18",
3
+ "version": "1.11.20",
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": {
@@ -59,7 +59,7 @@
59
59
  "commander": "^14.0.3",
60
60
  "figlet": "^1.9.3",
61
61
  "node-pty": "^1.1.0",
62
- "ws": "^8.19.0"
62
+ "ws": "^8.21.0"
63
63
  },
64
64
  "devDependencies": {
65
65
  "@changesets/changelog-github": "^0.5.2",