@rahularya01/pi-cursor 1.4.9 → 1.4.10

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.10] - 2026-08-15
4
+
5
+ ### Fixed
6
+
7
+ - Hardened permission handling, transport framing, OAuth cancellation, recovery journals, logging, and MCP tool validation.
8
+ - Startup model discovery now uses stale-while-revalidate behavior so Pi can activate from cached or bundled models without waiting for network discovery.
9
+ - Added bounded payloads, backpressure handling, cleanup on aborted/failing streams, and expanded regression coverage.
10
+
3
11
  ## [1.4.9] - 2026-08-12
4
12
 
5
13
  ### Fixed
@@ -22,15 +22,20 @@
22
22
  */
23
23
  import http2 from "node:http2";
24
24
  import crypto from "node:crypto";
25
+ import { once } from "node:events";
25
26
 
26
27
  const CURSOR_CLIENT_VERSION = process.env.PI_CURSOR_CLIENT_VERSION || "cli-2026.05.01-eea359f";
28
+ const MAX_BRIDGE_MESSAGE_BYTES = 64 * 1024 * 1024;
29
+ const MAX_ERROR_BODY_BYTES = 1024 * 1024;
27
30
 
28
31
  /** Write one length-prefixed message to stdout. */
29
32
  function writeMessage(data) {
33
+ if (data.length > MAX_BRIDGE_MESSAGE_BYTES) {
34
+ throw new Error(`bridge output exceeds ${MAX_BRIDGE_MESSAGE_BYTES} bytes`);
35
+ }
30
36
  const lenBuf = Buffer.alloc(4);
31
37
  lenBuf.writeUInt32BE(data.length, 0);
32
- process.stdout.write(lenBuf);
33
- process.stdout.write(data);
38
+ return process.stdout.write(Buffer.concat([lenBuf, data]));
34
39
  }
35
40
 
36
41
  function connectEndStreamError(code, message) {
@@ -50,6 +55,10 @@ let stdinEnded = false;
50
55
 
51
56
  process.stdin.on("data", (chunk) => {
52
57
  stdinBuf = Buffer.concat([stdinBuf, chunk]);
58
+ if (stdinBuf.length > MAX_BRIDGE_MESSAGE_BYTES + 4) {
59
+ process.stderr.write("[h2-bridge] stdin buffer limit exceeded\n");
60
+ process.exit(1);
61
+ }
53
62
  if (stdinResolve) {
54
63
  const r = stdinResolve;
55
64
  stdinResolve = null;
@@ -86,6 +95,9 @@ async function readMessage() {
86
95
  const lenBuf = await readExact(4);
87
96
  if (!lenBuf) return null;
88
97
  const len = lenBuf.readUInt32BE(0);
98
+ if (len > MAX_BRIDGE_MESSAGE_BYTES) {
99
+ throw new Error(`bridge input exceeds ${MAX_BRIDGE_MESSAGE_BYTES} bytes`);
100
+ }
89
101
  if (len === 0) return Buffer.alloc(0);
90
102
  return readExact(len);
91
103
  }
@@ -218,6 +230,7 @@ const h2Stream = client.request(headers);
218
230
  let responseStatus = 0;
219
231
  let responseStatusText = "";
220
232
  const errorChunks = [];
233
+ let errorBodyBytes = 0;
221
234
  const isErrorStatus = () => responseStatus !== 0 && (responseStatus < 200 || responseStatus >= 300);
222
235
 
223
236
  h2Stream.on("response", (responseHeaders) => {
@@ -231,9 +244,17 @@ h2Stream.on("response", (responseHeaders) => {
231
244
  h2Stream.on("data", (chunk) => {
232
245
  resetTimeout();
233
246
  if (isErrorStatus()) {
234
- errorChunks.push(Buffer.from(chunk));
247
+ const remaining = MAX_ERROR_BODY_BYTES - errorBodyBytes;
248
+ if (remaining > 0) {
249
+ const kept = Buffer.from(chunk).subarray(0, remaining);
250
+ errorChunks.push(kept);
251
+ errorBodyBytes += kept.byteLength;
252
+ }
235
253
  } else {
236
- writeMessage(chunk);
254
+ if (!writeMessage(chunk)) {
255
+ h2Stream.pause();
256
+ process.stdout.once("drain", () => h2Stream.resume());
257
+ }
237
258
  }
238
259
  });
239
260
 
@@ -284,7 +305,13 @@ if (unary) {
284
305
  }
285
306
  if (!h2Stream.closed && !h2Stream.destroyed) {
286
307
  resetTimeout();
287
- h2Stream.write(msg);
308
+ if (!h2Stream.write(msg)) {
309
+ try {
310
+ await once(h2Stream, "drain");
311
+ } catch {
312
+ break;
313
+ }
314
+ }
288
315
  }
289
316
  }
290
317