@rahularya01/pi-cursor 1.4.15 → 1.4.16

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/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # Changelog
2
2
 
3
+ ## [1.4.16] - 2026-08-16
4
+
5
+ ### Performance
6
+
7
+ - **Eliminated O(n²) frame reassembly on the streaming hot path.** The bridge's stdout reader, the Connect frame parser, and `h2-bridge.mjs`'s stdin reader all re-concatenated the entire buffered backlog on every incoming chunk, which is quadratic in a frame's total size once it arrives split across many small reads (large tool results, images, checkpoints). Replaced with a chunk-array accumulator that only merges what's needed to make progress — up to ~690x faster reassembling a large frame from small chunks in benchmarks.
8
+ - **Cached checkpoint history fingerprinting.** `fingerprintCompletedTurns()` re-serialized and hashed the full completed-turn history from scratch on every call, even though it runs multiple times per turn over overlapping turn arrays. Added a per-turn cache keyed by turn-object identity.
9
+ - **Memoized MCP tool schema slimming.** `buildMcpToolDefinitions()` and the derived MCP tool-name list re-slimmed and re-encoded every tool's schema on every call, even when the underlying tool set was unchanged from the previous turn. Both are now cached by array identity.
10
+
3
11
  ## [1.4.15] - 2026-08-15
4
12
 
5
13
  ### Documentation
@@ -48,14 +48,21 @@ function connectEndStreamError(code, message) {
48
48
  }
49
49
 
50
50
  // --- Buffered stdin reader ---
51
+ //
52
+ // Chunks are queued in an array and only concatenated once enough bytes have arrived to satisfy
53
+ // a `readExact` call. Concatenating on every `data` event instead (`stdinBuf = Buffer.concat([
54
+ // stdinBuf, chunk])`) is O(n^2) in the message size when a large message arrives split across
55
+ // many small pipe reads, since every partial chunk re-copies everything buffered so far.
51
56
 
52
- let stdinBuf = Buffer.alloc(0);
57
+ let stdinChunks = [];
58
+ let stdinLength = 0;
53
59
  let stdinResolve = null;
54
60
  let stdinEnded = false;
55
61
 
56
62
  process.stdin.on("data", (chunk) => {
57
- stdinBuf = Buffer.concat([stdinBuf, chunk]);
58
- if (stdinBuf.length > MAX_BRIDGE_MESSAGE_BYTES + 4) {
63
+ stdinChunks.push(chunk);
64
+ stdinLength += chunk.length;
65
+ if (stdinLength > MAX_BRIDGE_MESSAGE_BYTES + 4) {
59
66
  process.stderr.write("[h2-bridge] stdin buffer limit exceeded\n");
60
67
  process.exit(1);
61
68
  }
@@ -82,12 +89,16 @@ function waitForData() {
82
89
  }
83
90
 
84
91
  async function readExact(n) {
85
- while (stdinBuf.length < n) {
92
+ while (stdinLength < n) {
86
93
  if (stdinEnded) return null;
87
94
  await waitForData();
88
95
  }
89
- const result = stdinBuf.subarray(0, n);
90
- stdinBuf = stdinBuf.subarray(n);
96
+ if (stdinChunks.length > 1) stdinChunks = [Buffer.concat(stdinChunks, stdinLength)];
97
+ const buf = stdinChunks[0] ?? Buffer.alloc(0);
98
+ const result = buf.subarray(0, n);
99
+ const rest = buf.subarray(n);
100
+ stdinChunks = rest.length > 0 ? [rest] : [];
101
+ stdinLength = rest.length;
91
102
  return Buffer.from(result);
92
103
  }
93
104